Javascript 如何设计链式模型。find()函数?
我正在尝试在Node.js中编写ORM。我想声明一个名为Model的类,该类将用于声明数据对象,如:Javascript 如何设计链式模型。find()函数?,javascript,sql,node.js,orm,Javascript,Sql,Node.js,Orm,我正在尝试在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) 或者只是一个简单的查找:
Users = new Model(someModelRules);
newUser = new Users(userInfomation);
数据模型User
有一个名为find()
的函数。现在,我想把find()
链接起来,比如:
Users.find(" name = 'John' ")
.orderedBy("age").desc()
.limit(0,10)
或者只是一个简单的查找
:
Users.find(" name = 'John' ")
要编写这个find
函数,我认为必须首先构建SQL,并在find
链的末尾执行SQL查询
我不知道怎么做,我能想到的就是添加一个函数,比如:doQuery()
,这样当调用doQuery()
函数时,我就知道是时候执行SQL查询了,比如:
Users.find(" name = 'John' ")
.orderedBy("age").desc()
.limit(0,10)
.doQuery();
我知道这是一个简单的解决方案,但我不想要额外的doQuery()
函数:(
那么,我应该如何设计它呢?如果你能给我看一些带有注释的示例代码,那就太好了
谢谢!(对不起,我的英语很差)
另外,我知道有一个查找函数,我只是想要,但我想知道如何编码它,我几乎无法理解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
我相信一定有更好的方法来实现这一点,但这是我目前能得到的最好的方法。
有什么意见吗?在链的末尾,您必须始终有一个execute/doQuery函数。
这是因为doQuery之前的所有其他函数都有助于构建需要在末尾执行的查询。在链的末尾始终必须有一个execute/doQuery函数。
这是因为doQuery之前的所有其他函数都有助于构建最终需要执行的查询。如果您将
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.
}
user.find({
what : " name = 'John' ",
orderedBy : "age DESC",
limit : "0,10"
});
一种完全不同的方法是使用一种方法来构建SQL,并在options对象中传递ORDER BY和LIMIT参数。然后调用如下所示:
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.
}
user.find({
what : " name = 'John' ",
orderedBy : "age DESC",
limit : "0,10"
});
这比您正在尝试的更适合SQL查询。您所拥有的类似于noSQL的东西,如MongoDB,其中获取记录和排序是独立的操作(我认为)。如果您将
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.
}
user.find({
what : " name = 'John' ",
orderedBy : "age DESC",
limit : "0,10"
});
一种完全不同的方法是使用一种方法来构建SQL,并在options对象中传递ORDER BY和LIMIT参数。然后调用如下所示:
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.
}
user.find({
what : " name = 'John' ",
orderedBy : "age DESC",
limit : "0,10"
});
这比您正在尝试的更适合SQL查询。您所拥有的类似于noSQL的东西,如MongoDB,其中获取记录和排序是单独的操作(我认为)。这将对性能产生巨大影响,因为它可能会多次进行查询。我宁愿使用
doQuery()
way……我相信一定有办法做到这一点。谢谢。这将对性能产生巨大影响,因为它可能会进行多次查询。我宁愿采用doQuery()
的方式……我相信一定有办法做到这一点。谢谢。好吧……但似乎每次调用函数(或几乎每次调用)时都会进行sql查询。如果我错了,请纠正我。谢谢,这很有趣,我会试着这样想。querytimeset
标志就是为了避免这种情况。只有在上一个函数还没有这样做的情况下,您才会安排新的查询。我明白了,scheduleQuery()
将异步运行,因此代码不会等待它,而只返回此?但我认为scheduleQuery()
仍在运行,链中的每个函数都将调用scheduleQuery()
来运行,因此如果我编写类似于:User.find(“name='John')).orderedBy('age')的代码
,事件循环中将运行2个scheduleQuery()
。我说得对吗?(对不起,我是Node.js新手)@JeremyHou实际上,scheduleQuery
是同步的。只有实际执行查询的部分(在setTimeout
内)是异步的。请参见正在运行的示例:。这种方法有一个主要缺点:不能按顺序进行两个不同的find()
调用,除非您以某种方式实现一种方法来强制执行挂起的查询以启动一个新的查询。我明白了!我想我可以声明另一个类(我们称之为myQuery
)它将具有orderedBy()
,limit()
,scheduleQuery()
函数,每次调用find()
函数时,都会创建一个新的myQuery对象,find()
函数可以调用newMyQuery.scheduleQuery();return newMyQuery;
。因此我可以创建多个find()
。感谢您指出实现此目的的方法!好吧……但似乎每次调用函数(或几乎每次调用)时都会进行sql查询。如果我错了,请纠正我。谢谢,这很有趣,我会试着这样想。querytimeset
标志就是为了避免这种情况。只有在上一个函数还没有这样做的情况下,您才会安排新的查询。我明白了,scheduleQuery()
将异步运行,因此代码不会等待它,而只返回此?但我认为scheduleQuery()
仍在运行,链中的每个函数都将调用scheduleQuery()
来运行,因此如果我编写类似于:User.find(“name='John')).orderedBy('age')的代码
,事件循环中将运行2个scheduleQuery()
。我说得对吗?(对不起,我是Node.js新手)@JeremyHou实际上,scheduleQuery
是同步的。只有实际执行查询的部分(在setTimeout
内)是异步的。