Skip to content

Commit bd56d6c

Browse files
committed
add .all() function to retrieve all rows in the result
1 parent 416ffb2 commit bd56d6c

4 files changed

Lines changed: 144 additions & 10 deletions

File tree

lib/sqlite3.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,10 @@
1616
var sqlite3 = module.exports = exports = require('./sqlite3_bindings');
1717
var sys = require("sys");
1818

19-
// function noop(err) {
20-
// if (err) throw err;
21-
// };
2219

2320
var Database = sqlite3.Database;
2421
var Statement = sqlite3.Statement;
2522

26-
2723
// Database#prepare(sql, [bind1, bind2, ...], [callback])
2824
Database.prototype.prepare = function(sql) {
2925
var callback, params = Array.prototype.slice.call(arguments, 1);
@@ -39,4 +35,3 @@ Database.prototype.prepare = function(sql) {
3935
return new Statement(this, sql, params.pop());
4036
}
4137
};
42-

src/statement.cc

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void Statement::Init(v8::Handle<Object> target) {
3939
NODE_SET_PROTOTYPE_METHOD(constructor_template, "bind", Bind);
4040
NODE_SET_PROTOTYPE_METHOD(constructor_template, "get", Get);
4141
NODE_SET_PROTOTYPE_METHOD(constructor_template, "run", Run);
42+
NODE_SET_PROTOTYPE_METHOD(constructor_template, "all", All);
4243
NODE_SET_PROTOTYPE_METHOD(constructor_template, "reset", Reset);
4344
NODE_SET_PROTOTYPE_METHOD(constructor_template, "finalize", Finalize);
4445

@@ -446,6 +447,89 @@ int Statement::EIO_AfterRun(eio_req *req) {
446447
return 0;
447448
}
448449

450+
Handle<Value> Statement::All(const Arguments& args) {
451+
HandleScope scope;
452+
Statement* stmt = ObjectWrap::Unwrap<Statement>(args.This());
453+
454+
Baton* baton = stmt->Bind<RowsBaton>(args);
455+
stmt->Schedule(EIO_BeginAll, baton);
456+
457+
return args.This();
458+
}
459+
460+
void Statement::EIO_BeginAll(Baton* baton) {
461+
assert(!baton->stmt->locked);
462+
assert(!baton->stmt->finalized);
463+
assert(baton->stmt->prepared);
464+
baton->stmt->locked = true;
465+
eio_custom(EIO_All, EIO_PRI_DEFAULT, EIO_AfterAll, baton);
466+
}
467+
468+
int Statement::EIO_All(eio_req *req) {
469+
STATEMENT_INIT(RowsBaton);
470+
471+
sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->handle);
472+
sqlite3_mutex_enter(mtx);
473+
474+
// Make sure that we also reset when there are no parameters.
475+
if (!baton->parameters.size()) {
476+
sqlite3_reset(stmt->handle);
477+
}
478+
479+
if (stmt->Bind(baton->parameters)) {
480+
while ((stmt->status = sqlite3_step(stmt->handle)) == SQLITE_ROW) {
481+
Data::Row* row = new Data::Row();
482+
GetRow(row, stmt->handle);
483+
baton->rows.push_back(row);
484+
}
485+
486+
if (stmt->status != SQLITE_DONE) {
487+
stmt->message = std::string(sqlite3_errmsg(stmt->db->handle));
488+
}
489+
}
490+
491+
sqlite3_mutex_leave(mtx);
492+
493+
return 0;
494+
}
495+
496+
int Statement::EIO_AfterAll(eio_req *req) {
497+
HandleScope scope;
498+
STATEMENT_INIT(RowsBaton);
499+
500+
if (stmt->status != SQLITE_DONE) {
501+
Error(baton);
502+
}
503+
else {
504+
// Fire callbacks.
505+
if (!baton->callback.IsEmpty() && baton->callback->IsFunction()) {
506+
if (baton->rows.size()) {
507+
// Create the result array from the data we acquired.
508+
Local<Array> result(Array::New(baton->rows.size()));
509+
Data::Rows::const_iterator it = baton->rows.begin();
510+
Data::Rows::const_iterator end = baton->rows.end();
511+
for (int i = 0; it < end; it++, i++) {
512+
result->Set(i, RowToJS(*it));
513+
}
514+
515+
Local<Value> argv[] = { Local<Value>::New(Null()), result };
516+
TRY_CATCH_CALL(stmt->handle_, baton->callback, 2, argv);
517+
}
518+
else {
519+
// There were no result rows.
520+
Local<Value> argv[] = {
521+
Local<Value>::New(Null()),
522+
Local<Value>::New(Array::New(0))
523+
};
524+
TRY_CATCH_CALL(stmt->handle_, baton->callback, 2, argv);
525+
}
526+
}
527+
}
528+
529+
STATEMENT_END();
530+
return 0;
531+
}
532+
449533
Handle<Value> Statement::Reset(const Arguments& args) {
450534
HandleScope scope;
451535
Statement* stmt = ObjectWrap::Unwrap<Statement>(args.This());
@@ -492,8 +576,9 @@ int Statement::EIO_AfterReset(eio_req *req) {
492576
Local<Array> Statement::RowToJS(Data::Row* row) {
493577
Local<Array> result(Array::New(row->size()));
494578

495-
Data::Row::iterator it = row->begin();
496-
for (int i = 0; it < row->end(); it++, i++) {
579+
Data::Row::const_iterator it = row->begin();
580+
Data::Row::const_iterator end = row->end();
581+
for (int i = 0; it < end; it++, i++) {
497582
Data::Field* field = *it;
498583
switch (field->type) {
499584
case SQLITE_INTEGER: {

src/statement.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ class Statement : public EventEmitter {
105105
Data::Row row;
106106
};
107107

108+
static struct RowsBaton : Baton {
109+
RowsBaton(Statement* stmt_, Handle<Function> cb_) :
110+
Baton(stmt_, cb_) {}
111+
Data::Rows rows;
112+
};
113+
108114
static struct PrepareBaton : Database::Baton {
109115
Statement* stmt;
110116
std::string sql;

test/prepare.test.js

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ exports['test retrieving reset() function'] = function(beforeExit) {
128128
});
129129
};
130130

131-
exports['test multiple get() function binding'] = function(beforeExit) {
131+
exports['test multiple get() parameter binding'] = function(beforeExit) {
132132
var db = new sqlite3.Database('test/support/prepare.db', sqlite3.OPEN_READONLY);
133133

134134
var retrieved = 0;
@@ -161,7 +161,7 @@ exports['test multiple get() function binding'] = function(beforeExit) {
161161
};
162162

163163

164-
exports['test prepare() function binding'] = function(beforeExit) {
164+
exports['test prepare() parameter binding'] = function(beforeExit) {
165165
var db = new sqlite3.Database('test/support/prepare.db', sqlite3.OPEN_READONLY);
166166

167167
var retrieved = 0;
@@ -182,7 +182,7 @@ exports['test prepare() function binding'] = function(beforeExit) {
182182
};
183183

184184

185-
exports['test get() function binding'] = function(beforeExit) {
185+
exports['test get() parameter binding'] = function(beforeExit) {
186186
var db = new sqlite3.Database('test/support/prepare.db', sqlite3.OPEN_READONLY);
187187

188188
var retrieved = 0;
@@ -201,3 +201,51 @@ exports['test get() function binding'] = function(beforeExit) {
201201
assert.equal(1, retrieved, "Didn't retrieve all rows");
202202
});
203203
};
204+
205+
exports['test all()'] = function(beforeExit) {
206+
var db = new sqlite3.Database('test/support/prepare.db', sqlite3.OPEN_READONLY);
207+
208+
var retrieved = 0;
209+
var count = 1000;
210+
211+
db.prepare("SELECT txt, num, flt, blb FROM foo WHERE num < ? ORDER BY num", count)
212+
.all(function(err, rows) {
213+
if (err) throw err;
214+
for (var i = 0; i < rows.length; i++) {
215+
assert.equal(rows[i][0], 'String ' + i);
216+
assert.equal(rows[i][1], i);
217+
assert.equal(rows[i][2], i * Math.PI);
218+
assert.equal(rows[i][3], null);
219+
retrieved++;
220+
}
221+
});
222+
223+
beforeExit(function() {
224+
assert.equal(count, retrieved, "Didn't retrieve all rows");
225+
});
226+
};
227+
228+
229+
230+
exports['test all() parameter binding'] = function(beforeExit) {
231+
var db = new sqlite3.Database('test/support/prepare.db', sqlite3.OPEN_READONLY);
232+
233+
var retrieved = 0;
234+
var count = 1000;
235+
236+
db.prepare("SELECT txt, num, flt, blb FROM foo WHERE num < ? ORDER BY num")
237+
.all(count, function(err, rows) {
238+
if (err) throw err;
239+
for (var i = 0; i < rows.length; i++) {
240+
assert.equal(rows[i][0], 'String ' + i);
241+
assert.equal(rows[i][1], i);
242+
assert.equal(rows[i][2], i * Math.PI);
243+
assert.equal(rows[i][3], null);
244+
retrieved++;
245+
}
246+
});
247+
248+
beforeExit(function() {
249+
assert.equal(count, retrieved, "Didn't retrieve all rows");
250+
});
251+
};

0 commit comments

Comments
 (0)