1

我正在尝试在 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' ")

要编写这个函数,我相信我必须先构建 SQL,然后在这条链find的末尾进行 SQL 查询。find

我不知道怎么做,我能想到的就是添加一个函数,比如:doQuery(),这样我就知道是时候在doQuery()调用函数时进行 SQL 查询了,比如:

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

我知道这是一个简单的解决方案,但我不想要额外的doQuery()功能。:(

那么,我该如何设计呢?如果您能向我展示一些带有注释的示例代码,您会非常高兴。

谢谢!(对不起我的英语不好)

附言。我知道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

我相信一定有更好的方法来实现这一点,但这是我目前能得到的最好的。任何意见?

4

2 回答 2

1

如果您将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,并在选项对象中传递 ORDER BY 和 LIMIT 参数。然后您的电话将如下所示:

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

这比您尝试做的更适合 SQL 查询。你所拥有的看起来像 MongoDB 这样的 noSQL 东西,其中获取记录和排序是单独的操作(我认为)。

于 2013-07-24T15:25:10.003 回答
0

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

于 2013-07-24T15:12:23.027 回答