如何devise一个链式Model.find()函数?

我正在尝试在Node.js中编写ORM 我想声明一个名为Model的类,它将被用来声明一个数据对象,如:

Users = new Model(someModelRules); newUser = new Users(userInfomation); 

数据模型User有一个名为find()的函数。 现在,我想使find()链接,如:

 Users.find(" name = 'John' ") .orderedBy("age").desc() .limit(0,10) 

或者只是简单地find

 Users.find(" name = 'John' ") 

为了编写这个find函数,我相信我必须先构buildSQL,然后在find链的末尾执行SQL查询。

我不知道该怎么做,所有我能想到的就是添加一个函数,如: doQuery() ,所以当doQuery()函数时,我将知道是时候执行SQL查询了,如:

 Users.find(" name = 'John' ") .orderedBy("age").desc() .limit(0,10) .doQuery(); 

我知道这是一个简单的解决scheme,但我不想额外的doQuery()函数。 🙁

那么,我该如何devise呢? 如果你能给我看一些带有注释的例子代码,那真是太好了。

谢谢! (抱歉我的英文不好)

PS。 我知道ORM2有一个查找function,我只是想,但我想知道如何编码,我几乎无法理解ORM2中的代码,因为没有评论。 (我不会用orm2)

=================================解决scheme================ ==============

受@bfavaretto启发:

 function User() { this.find = function(id, condition) { return new findChain(id, condition); } } function findChain(id, condition) { this._id = id this._condition = condition this.queryTimerSet = false; this.scheduleQuery = function () { var self = this; if(!self.queryTimerSet) { console.log('[TEST CASE: ' + self._id + '] Insert query into eventLoop'); setTimeout(function(){ console.log('[TEST CASE: ' + self._id + '] Start query: '+self._condition); }, 0); self.queryTimerSet = true; } else { console.log('[TEST CASE: ' + self._id + '] No need to insert another query'); } } this.orderedBy = function(column) { console.log('[TEST CASE: ' + this._id + '] orderedBy was called'); this._condition = this._condition + ' ORDER BY ' + column this.scheduleQuery(); return this; } this.desc = function() { // simply add DESC to the end of sql this._condition = this._condition + ' DESC' } this.scheduleQuery(); } var user = new User(); user.find(1,'SELECT * FROM test').orderedBy('NAME1').desc(); user.find(2,'SELECT * FROM test').orderedBy('NAME2'); user.find(3,'SELECT * FROM test'); 

运行这个代码,你会得到结果:

 [TEST CASE: 1] Insert query into eventLoop [TEST CASE: 1] orderedBy was called [TEST CASE: 1] No need to insert another query [TEST CASE: 2] Insert query into eventLoop [TEST CASE: 2] orderedBy was called [TEST CASE: 2] No need to insert another query [TEST CASE: 3] Insert query into eventLoop [TEST CASE: 1] Start query: SELECT * FROM test ORDER BY NAME1 DESC [TEST CASE: 2] Start query: SELECT * FROM test ORDER BY NAME2 [TEST CASE: 3] Start query: SELECT * FROM test 

我相信有一个更好的办法可以做到这一点,但这是我现在可以得到的最好的方式。 任何意见?

如果您计划doQuery逻辑asynchronous运行(但尽快),可以实现这一点。 我正在考虑这样的事情:

 function User() { // Flag to control whether a timer was already setup var queryTimerSet = false; // This will schedule the query execution to the next tick of the // event loop, if it wasn't already scheduled. // This function is available to your model methods via closure. function scheduleQuery() { if(!queryTimerSet) { setTimeout(function(){ // execute sql // from the query callback, set queryTimerSet back to false }, 0); queryTimerSet = true; } } this.find = function() { // ... logic that builds the sql scheduleQuery(); return this; } this.orderedBy = function() { // ... logic that appends to the sql scheduleQuery(); return this; } // etc. } 

一种完全不同的方法是使用单一方法构buildSQL,并将ORDER BY和LIMITparameter passing给选项对象。 那么你的电话会是这样的:

 user.find({ what : " name = 'John' ", orderedBy : "age DESC", limit : "0,10" }); 

这比你想要做的更适合SQL查询。 你看起来像noSQL的东西,如MongoDB,其中提取logging和sorting是单独的操作(我认为)。

您将始终必须有一个执行/ doQuery函数在链的末尾。 这是因为doQuery之前的所有其他函数都有助于构build需要在最后执行的查询。