[英]How to design a chained Model.find() function?
我正在尝试在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
功能的代码,我相信我必须先构建SQL,然后在此find
链的末尾进行SQL查询。
我不知道该怎么做,我所能想到的就是添加一个函数: doQuery()
,所以我知道该在doQuery()
函数时执行SQL查询了,例如:
Users.find(" name = 'John' ")
.orderedBy("age").desc()
.limit(0,10)
.doQuery();
我知道这是一个简单的解决方案,但是我不需要额外的doQuery()
函数。 :(
那么,我应该如何设计呢? 如果您可以向我展示一些带有注释的示例代码,那对您真是太好了。
谢谢! (对不起,我英语不好)
PS。 我知道ORM2有一个我只想要的查找功能,但是我想知道如何编写它,由于没有注释,所以我几乎无法理解ORM2中的代码。 (我不会使用orm2。)
===============================解决方案================ ==============
受到@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
逻辑安排为异步运行(但尽快),则有可能实现这一目标。 我在想这样的事情:
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.
}
一种完全不同的方法是使用一种方法来构建SQL,并在options对象中传递ORDER BY和LIMIT参数。 然后您的呼叫将如下所示:
user.find({
what : " name = 'John' ",
orderedBy : "age DESC",
limit : "0,10"
});
比您要执行的操作更适合SQL查询。 您所拥有的看起来像noSQL之类的东西,例如MongoDB,其中获取记录和排序是单独的操作(我认为)。
您将始终必须在链的末尾具有execute / doQuery函数。 这是因为doQuery之前的所有其他功能都有助于构建需要在最后执行的查询。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.