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' ")

この関数をコーディングfindするには、最初に SQL を作成し、このfindチェーンの最後で SQL クエリを実行する必要があると思います。

これを行う方法がわかりません。考えられるのは、次のような関数を追加することだけです。したがって、次のように、関数が呼び出されdoQuery()たときにSQLクエリを実行する時が来たことがわかります。doQuery()

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

これを達成するためのより良い方法があるに違いないと私は信じていますが、これが今のところ私が得ることができる最高のものです. コメントはありますか?

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.
}

まったく異なるアプローチの 1 つは、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

チェーンの最後には常に execute/doQuery 関数が必要です。これは、doQuery の前にある他のすべての関数が、最後に実行する必要があるクエリを作成するのに役立つためです。

于 2013-07-24T15:12:23.027 に答える