Commit a4c1a756 by Orlando Vazquez

Cache lastInsertRowID and affectedRows.

Add some options to preparing a statement. If the lastInsertedID and/or
affectedRows options are specified, those values will be looked up after every
step.
parent 858b70c3
...@@ -257,31 +257,31 @@ int Database::EIO_AfterPrepareAndStep(eio_req *req) { ...@@ -257,31 +257,31 @@ int Database::EIO_AfterPrepareAndStep(eio_req *req) {
// if the prepare failed // if the prepare failed
if (req->result != SQLITE_OK) { if (req->result != SQLITE_OK) {
argv[0] = Exception::Error( argv[0] = Exception::Error(
String::New(sqlite3_errmsg(prep_req->dbo->db_))); String::New(sqlite3_errmsg(prep_req->dbo->db_)));
argc = 1; argc = 1;
} }
else { else {
if (req->int1 == SQLITE_DONE) { if (req->int1 == SQLITE_DONE) {
if (prep_req->mode != EXEC_EMPTY) { if (prep_req->mode != EXEC_EMPTY) {
argv[0] = Local<Value>::New(Undefined()); // no error argv[0] = Local<Value>::New(Undefined()); // no error
Local<Object> info = Object::New(); Local<Object> info = Object::New();
if (prep_req->mode & EXEC_LAST_INSERT_ID) { if (prep_req->mode & EXEC_LAST_INSERT_ID) {
info->Set(String::NewSymbol("last_inserted_id"), info->Set(String::NewSymbol("last_inserted_id"),
Integer::NewFromUnsigned (prep_req->lastInsertId)); Integer::NewFromUnsigned (prep_req->lastInsertId));
} }
if (prep_req->mode & EXEC_AFFECTED_ROWS) { if (prep_req->mode & EXEC_AFFECTED_ROWS) {
info->Set(String::NewSymbol("affected_rows"), info->Set(String::NewSymbol("affected_rows"),
Integer::New (prep_req->affectedRows)); Integer::New (prep_req->affectedRows));
} }
argv[1] = info; argv[1] = info;
argc = 2; argc = 2;
} else { } else {
argc = 0; argc = 0;
} }
} }
...@@ -289,7 +289,7 @@ int Database::EIO_AfterPrepareAndStep(eio_req *req) { ...@@ -289,7 +289,7 @@ int Database::EIO_AfterPrepareAndStep(eio_req *req) {
argv[0] = External::New(prep_req->stmt); argv[0] = External::New(prep_req->stmt);
argv[1] = Integer::New(req->int1); argv[1] = Integer::New(req->int1);
Persistent<Object> statement( Persistent<Object> statement(
Statement::constructor_template->GetFunction()->NewInstance(2, argv)); Statement::constructor_template->GetFunction()->NewInstance(2, argv));
if (prep_req->tail) { if (prep_req->tail) {
statement->Set(String::New("tail"), String::New(prep_req->tail)); statement->Set(String::New("tail"), String::New(prep_req->tail));
...@@ -359,6 +359,7 @@ int Database::EIO_PrepareAndStep(eio_req *req) { ...@@ -359,6 +359,7 @@ int Database::EIO_PrepareAndStep(eio_req *req) {
Handle<Value> Database::PrepareAndStep(const Arguments& args) { Handle<Value> Database::PrepareAndStep(const Arguments& args) {
HandleScope scope; HandleScope scope;
REQ_STR_ARG(0, sql); REQ_STR_ARG(0, sql);
REQ_FUN_ARG(1, cb); REQ_FUN_ARG(1, cb);
OPT_INT_ARG(2, mode, EXEC_EMPTY); OPT_INT_ARG(2, mode, EXEC_EMPTY);
...@@ -392,7 +393,7 @@ int Database::EIO_AfterPrepare(eio_req *req) { ...@@ -392,7 +393,7 @@ int Database::EIO_AfterPrepare(eio_req *req) {
struct prepare_request *prep_req = (struct prepare_request *)(req->data); struct prepare_request *prep_req = (struct prepare_request *)(req->data);
HandleScope scope; HandleScope scope;
Local<Value> argv[2]; Local<Value> argv[3];
int argc = 0; int argc = 0;
// if the prepare failed // if the prepare failed
...@@ -404,16 +405,17 @@ int Database::EIO_AfterPrepare(eio_req *req) { ...@@ -404,16 +405,17 @@ int Database::EIO_AfterPrepare(eio_req *req) {
else { else {
argv[0] = External::New(prep_req->stmt); argv[0] = External::New(prep_req->stmt);
argv[1] = Integer::New(-1); argv[1] = Integer::New(-1);
argv[2] = Integer::New(prep_req->mode);
Persistent<Object> statement( Persistent<Object> statement(
Statement::constructor_template->GetFunction()->NewInstance(2, argv)); Statement::constructor_template->GetFunction()->NewInstance(3, argv));
if (prep_req->tail) { if (prep_req->tail) {
statement->Set(String::New("tail"), String::New(prep_req->tail)); statement->Set(String::New("tail"), String::New(prep_req->tail));
} }
argc = 2;
argv[0] = Local<Value>::New(Undefined()); argv[0] = Local<Value>::New(Undefined());
argv[1] = Local<Value>::New(statement); argv[1] = Local<Value>::New(statement);
argc = 2;
} }
TryCatch try_catch; TryCatch try_catch;
...@@ -454,11 +456,49 @@ int Database::EIO_Prepare(eio_req *req) { ...@@ -454,11 +456,49 @@ int Database::EIO_Prepare(eio_req *req) {
return 0; return 0;
} }
// Statement#prepare(sql, [ options ,] callback);
Handle<Value> Database::Prepare(const Arguments& args) { Handle<Value> Database::Prepare(const Arguments& args) {
HandleScope scope; HandleScope scope;
Local<Object> options;
Local<Function> cb;
int mode;
REQ_STR_ARG(0, sql); REQ_STR_ARG(0, sql);
REQ_FUN_ARG(1, cb);
OPT_INT_ARG(2, mode, EXEC_EMPTY); // middle argument could be options or
switch (args.Length()) {
case 2:
if (!args[1]->IsFunction()) {
return ThrowException(Exception::TypeError(
String::New("Argument 1 must be a function")));
}
cb = Local<Function>::Cast(args[1]);
options = Object::New();
break;
case 3:
if (!args[1]->IsObject()) {
return ThrowException(Exception::TypeError(
String::New("Argument 1 must be an object")));
}
options = Local<Function>::Cast(args[1]);
if (!args[2]->IsFunction()) {
return ThrowException(Exception::TypeError(
String::New("Argument 2 must be a function")));
}
cb = Local<Function>::Cast(args[2]);
break;
}
mode = EXEC_EMPTY;
if (options->Get(String::New("lastInsertRowID"))->IsTrue()) {
mode |= EXEC_LAST_INSERT_ID;
}
if (options->Get(String::New("affectedRows"))->IsTrue()) {
mode |= EXEC_AFFECTED_ROWS;
}
Database* dbo = ObjectWrap::Unwrap<Database>(args.This()); Database* dbo = ObjectWrap::Unwrap<Database>(args.This());
......
...@@ -16,6 +16,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ...@@ -16,6 +16,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <string.h> #include <string.h>
#include "database.h"
#include "statement.h" #include "statement.h"
#include "sqlite3_bindings.h" #include "sqlite3_bindings.h"
...@@ -48,8 +49,9 @@ Handle<Value> Statement::New(const Arguments& args) { ...@@ -48,8 +49,9 @@ Handle<Value> Statement::New(const Arguments& args) {
HandleScope scope; HandleScope scope;
REQ_EXT_ARG(0, stmt); REQ_EXT_ARG(0, stmt);
int first_rc = args[1]->IntegerValue(); int first_rc = args[1]->IntegerValue();
int mode = args[2]->IntegerValue();
Statement *sto = new Statement((sqlite3_stmt*)stmt->Value(), first_rc); Statement *sto = new Statement((sqlite3_stmt*)stmt->Value(), first_rc, mode);
sto->Wrap(args.This()); sto->Wrap(args.This());
sto->Ref(); sto->Ref();
...@@ -107,12 +109,12 @@ int Statement::EIO_BindArray(eio_req *req) { ...@@ -107,12 +109,12 @@ int Statement::EIO_BindArray(eio_req *req) {
case KEY_STRING: case KEY_STRING:
index = sqlite3_bind_parameter_index(sto->stmt_, index = sqlite3_bind_parameter_index(sto->stmt_,
(char*)(pair->key)); (char*)(pair->key));
break; break;
default: { default: {
// this SHOULD be unreachable // this SHOULD be unreachable
} }
} }
if (!index) { if (!index) {
...@@ -130,15 +132,13 @@ int Statement::EIO_BindArray(eio_req *req) { ...@@ -130,15 +132,13 @@ int Statement::EIO_BindArray(eio_req *req) {
break; break;
case VALUE_STRING: case VALUE_STRING:
rc = sqlite3_bind_text(sto->stmt_, index, (char*)(pair->value), rc = sqlite3_bind_text(sto->stmt_, index, (char*)(pair->value),
pair->value_size, SQLITE_TRANSIENT); pair->value_size, SQLITE_TRANSIENT);
break; break;
case VALUE_NULL: case VALUE_NULL:
rc = sqlite3_bind_null(sto->stmt_, index); rc = sqlite3_bind_null(sto->stmt_, index);
break; break;
default: { // should be unreachable
// should be unreachable
}
} }
} }
...@@ -159,16 +159,16 @@ Handle<Value> Statement::BindObject(const Arguments& args) { ...@@ -159,16 +159,16 @@ Handle<Value> Statement::BindObject(const Arguments& args) {
if (! args[0]->IsObject()) if (! args[0]->IsObject())
return ThrowException(Exception::TypeError( return ThrowException(Exception::TypeError(
String::New("First argument must be an Array."))); String::New("First argument must be an Array.")));
Local<Object> obj = args[0]->ToObject(); Local<Object> obj = args[0]->ToObject();
Local<Array> properties = obj->GetPropertyNames(); Local<Array> properties = obj->GetPropertyNames();
struct bind_request *bind_req = (struct bind_request *) struct bind_request *bind_req = (struct bind_request *)
calloc(1, sizeof(struct bind_request)); calloc(1, sizeof(struct bind_request));
int len = bind_req->len = properties->Length(); int len = bind_req->len = properties->Length();
bind_req->pairs = (struct bind_pair *) bind_req->pairs = (struct bind_pair *)
calloc(len, sizeof(struct bind_pair)); calloc(len, sizeof(struct bind_pair));
struct bind_pair *pairs = bind_req->pairs; struct bind_pair *pairs = bind_req->pairs;
...@@ -177,7 +177,6 @@ Handle<Value> Statement::BindObject(const Arguments& args) { ...@@ -177,7 +177,6 @@ Handle<Value> Statement::BindObject(const Arguments& args) {
Local<Value> val = obj->Get(name->ToString()); Local<Value> val = obj->Get(name->ToString());
String::Utf8Value keyValue(name); String::Utf8Value keyValue(name);
printf("prop %d is %s\n", i, *keyValue);
// setting key type // setting key type
pairs->key_type = KEY_STRING; pairs->key_type = KEY_STRING;
...@@ -213,7 +212,7 @@ Handle<Value> Statement::BindObject(const Arguments& args) { ...@@ -213,7 +212,7 @@ Handle<Value> Statement::BindObject(const Arguments& args) {
else { else {
free(pairs->key); free(pairs->key);
return ThrowException(Exception::TypeError( return ThrowException(Exception::TypeError(
String::New("Unable to bind value of this type"))); String::New("Unable to bind value of this type")));
} }
} }
...@@ -235,15 +234,15 @@ Handle<Value> Statement::BindArray(const Arguments& args) { ...@@ -235,15 +234,15 @@ Handle<Value> Statement::BindArray(const Arguments& args) {
REQ_FUN_ARG(1, cb); REQ_FUN_ARG(1, cb);
if (! args[0]->IsArray()) if (! args[0]->IsArray())
return ThrowException(Exception::TypeError( return ThrowException(Exception::TypeError(
String::New("First argument must be an Array."))); String::New("First argument must be an Array.")));
struct bind_request *bind_req = (struct bind_request *) struct bind_request *bind_req = (struct bind_request *)
calloc(1, sizeof(struct bind_request)); calloc(1, sizeof(struct bind_request));
Local<Array> array = Local<Array>::Cast(args[0]); Local<Array> array = Local<Array>::Cast(args[0]);
int len = bind_req->len = array->Length(); int len = bind_req->len = array->Length();
bind_req->pairs = (struct bind_pair *) bind_req->pairs = (struct bind_pair *)
calloc(len, sizeof(struct bind_pair)); calloc(len, sizeof(struct bind_pair));
struct bind_pair *pairs = bind_req->pairs; struct bind_pair *pairs = bind_req->pairs;
...@@ -261,7 +260,6 @@ Handle<Value> Statement::BindArray(const Arguments& args) { ...@@ -261,7 +260,6 @@ Handle<Value> Statement::BindArray(const Arguments& args) {
// setup value // setup value
if (val->IsInt32()) { if (val->IsInt32()) {
printf("Binding int\n");
pairs->value_type = VALUE_INT; pairs->value_type = VALUE_INT;
int *value = (int *) malloc(sizeof(int)); int *value = (int *) malloc(sizeof(int));
*value = val->Int32Value(); *value = val->Int32Value();
...@@ -288,7 +286,7 @@ Handle<Value> Statement::BindArray(const Arguments& args) { ...@@ -288,7 +286,7 @@ Handle<Value> Statement::BindArray(const Arguments& args) {
else { else {
free(pairs->key); free(pairs->key);
return ThrowException(Exception::TypeError( return ThrowException(Exception::TypeError(
String::New("Unable to bind value of this type"))); String::New("Unable to bind value of this type")));
} }
} }
...@@ -328,24 +326,24 @@ Handle<Value> Statement::Bind(const Arguments& args) { ...@@ -328,24 +326,24 @@ Handle<Value> Statement::Bind(const Arguments& args) {
|| args[0]->IsArray() || args[0]->IsArray()
|| args[0]->IsObject())) || args[0]->IsObject()))
return ThrowException(Exception::TypeError( return ThrowException(Exception::TypeError(
String::New("First argument must be a string, number, array or object."))); String::New("First argument must be a string, number, array or object.")));
struct bind_request *bind_req = (struct bind_request *) struct bind_request *bind_req = (struct bind_request *)
calloc(1, sizeof(struct bind_request)); calloc(1, sizeof(struct bind_request));
bind_req->len = 1; bind_req->len = 1;
struct bind_pair *pair = bind_req->pairs = (struct bind_pair *) struct bind_pair *pair = bind_req->pairs = (struct bind_pair *)
calloc(1, sizeof(struct bind_pair)); calloc(1, sizeof(struct bind_pair));
// setup key // setup key
if (args[0]->IsString()) { if (args[0]->IsString()) {
String::Utf8Value keyValue(args[0]); String::Utf8Value keyValue(args[0]);
pair->key_type = KEY_STRING; pair->key_type = KEY_STRING;
char *key = (char *) calloc(1, keyValue.length() + 1); char *key = (char *) calloc(1, keyValue.length() + 1);
strcpy(key, *keyValue); strcpy(key, *keyValue);
pair->key = key; pair->key = key;
} }
else if (args[0]->IsInt32()) { else if (args[0]->IsInt32()) {
pair->key_type = KEY_INT; pair->key_type = KEY_INT;
...@@ -384,7 +382,7 @@ Handle<Value> Statement::Bind(const Arguments& args) { ...@@ -384,7 +382,7 @@ Handle<Value> Statement::Bind(const Arguments& args) {
else { else {
free(pair->key); free(pair->key);
return ThrowException(Exception::TypeError( return ThrowException(Exception::TypeError(
String::New("Unable to bind value of this type"))); String::New("Unable to bind value of this type")));
} }
bind_req->cb = Persistent<Function>::New(cb); bind_req->cb = Persistent<Function>::New(cb);
...@@ -434,7 +432,7 @@ Handle<Value> Statement::Finalize(const Arguments& args) { ...@@ -434,7 +432,7 @@ Handle<Value> Statement::Finalize(const Arguments& args) {
Statement* sto = ObjectWrap::Unwrap<Statement>(args.This()); Statement* sto = ObjectWrap::Unwrap<Statement>(args.This());
if (sto->HasCallback()) { if (sto->HasCallback()) {
return ThrowException(Exception::Error(String::New("Already stepping"))); return ThrowException(Exception::Error(String::New("Already stepping")));
} }
REQ_FUN_ARG(0, cb); REQ_FUN_ARG(0, cb);
...@@ -470,11 +468,12 @@ int Statement::EIO_AfterStep(eio_req *req) { ...@@ -470,11 +468,12 @@ int Statement::EIO_AfterStep(eio_req *req) {
Statement *sto = (class Statement *)(req->data); Statement *sto = (class Statement *)(req->data);
sqlite3* db = sqlite3_db_handle(sto->stmt_);
Local<Value> argv[2]; Local<Value> argv[2];
if (sto->error_) { if (sto->error_) {
argv[0] = Exception::Error( argv[0] = Exception::Error(
String::New(sqlite3_errmsg(sqlite3_db_handle(sto->stmt_)))); String::New(sqlite3_errmsg(db)));
} }
else { else {
argv[0] = Local<Value>::New(Undefined()); argv[0] = Local<Value>::New(Undefined());
...@@ -523,6 +522,16 @@ int Statement::EIO_AfterStep(eio_req *req) { ...@@ -523,6 +522,16 @@ int Statement::EIO_AfterStep(eio_req *req) {
argv[1] = row; argv[1] = row;
} }
if (sto->mode_ & EXEC_LAST_INSERT_ID) {
sto->handle_->Set(String::New("lastInsertRowID"),
Integer::New(sqlite3_last_insert_rowid(db)));
}
if (sto->mode_ & EXEC_AFFECTED_ROWS) {
sto->handle_->Set(String::New("affectedRows"),
Integer::New(sqlite3_changes(db)));
}
TryCatch try_catch; TryCatch try_catch;
Local<Function> cb = sto->GetCallback(); Local<Function> cb = sto->GetCallback();
......
...@@ -28,52 +28,52 @@ using namespace node; ...@@ -28,52 +28,52 @@ using namespace node;
class Statement : public EventEmitter { class Statement : public EventEmitter {
public: public:
static Persistent<FunctionTemplate> constructor_template; static Persistent<FunctionTemplate> constructor_template;
static void Init(v8::Handle<Object> target); static void Init(v8::Handle<Object> target);
static Handle<Value> New(const Arguments& args); static Handle<Value> New(const Arguments& args);
protected: protected:
Statement(sqlite3_stmt* stmt, int first_rc = -1) Statement(sqlite3_stmt* stmt, int first_rc = -1, int mode = 0)
: EventEmitter(), first_rc_(first_rc), stmt_(stmt) { : EventEmitter(), first_rc_(first_rc), mode_(mode), stmt_(stmt) {
column_count_ = -1; column_count_ = -1;
column_types_ = NULL; column_types_ = NULL;
column_names_ = NULL; column_names_ = NULL;
column_data_ = NULL; column_data_ = NULL;
} }
~Statement() { ~Statement() {
if (stmt_) sqlite3_finalize(stmt_); if (stmt_) sqlite3_finalize(stmt_);
if (column_types_) free(column_types_); if (column_types_) free(column_types_);
if (column_names_) free(column_names_); if (column_names_) free(column_names_);
if (column_data_) FreeColumnData(); if (column_data_) FreeColumnData();
} }
static Handle<Value> Bind(const Arguments& args); static Handle<Value> Bind(const Arguments& args);
static Handle<Value> BindObject(const Arguments& args); static Handle<Value> BindObject(const Arguments& args);
static Handle<Value> BindArray(const Arguments& args); static Handle<Value> BindArray(const Arguments& args);
static int EIO_BindArray(eio_req *req); static int EIO_BindArray(eio_req *req);
static int EIO_AfterBindArray(eio_req *req); static int EIO_AfterBindArray(eio_req *req);
static int EIO_AfterFinalize(eio_req *req); static int EIO_AfterFinalize(eio_req *req);
static int EIO_Finalize(eio_req *req); static int EIO_Finalize(eio_req *req);
static Handle<Value> Finalize(const Arguments& args); static Handle<Value> Finalize(const Arguments& args);
static Handle<Value> Reset(const Arguments& args); static Handle<Value> Reset(const Arguments& args);
static Handle<Value> ClearBindings(const Arguments& args); static Handle<Value> ClearBindings(const Arguments& args);
static int EIO_AfterStep(eio_req *req); static int EIO_AfterStep(eio_req *req);
static int EIO_Step(eio_req *req); static int EIO_Step(eio_req *req);
static Handle<Value> Step(const Arguments& args); static Handle<Value> Step(const Arguments& args);
void FreeColumnData(void); void FreeColumnData(void);
bool HasCallback(); bool HasCallback();
void SetCallback(Local<Function> cb); void SetCallback(Local<Function> cb);
Local<Function> GetCallback(); Local<Function> GetCallback();
private: private:
int column_count_; int column_count_;
...@@ -81,8 +81,9 @@ class Statement : public EventEmitter { ...@@ -81,8 +81,9 @@ class Statement : public EventEmitter {
char **column_names_; char **column_names_;
void **column_data_; void **column_data_;
bool error_; bool error_;
int first_rc_; int first_rc_;
int mode_;
sqlite3_stmt* stmt_; sqlite3_stmt* stmt_;
}; };
......
require.paths.push(__dirname + '/..');
sys = require('sys');
fs = require('fs');
path = require('path');
TestSuite = require('async-testing/async_testing').TestSuite;
sqlite = require('sqlite3_bindings');
puts = sys.puts;
inspect = sys.inspect;
// createa table
// prepare a statement (with options) that inserts
// do a step
// check that the result has a lastInsertedId property
var suite = exports.suite = new TestSuite("node-sqlite last inserted id test");
function createTestTable(db, callback) {
db.prepare('CREATE TABLE table1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)',
function (error, createStatement) {
if (error) throw error;
createStatement.step(function (error, row) {
if (error) throw error;
callback();
});
});
}
var tests = [
{ 'insert a row with lastinsertedid':
function (assert, finished) {
var self = this;
self.db.open(':memory:', function (error) {
function updateStatementCreated(error, statement) {
if (error) throw error;
statement.step(function (error, row) {
if (error) throw error;
puts("This is " + inspect(this));
assert.equal(this.affectedRows, 10, "Last inserted id should be 10");
finished();
});
}
createTestTable(self.db,
function () {
function insertRows(db, count, callback) {
var i = count;
db.prepare('INSERT INTO table1 (name) VALUES ("oh boy")',
function (error, statement) {
statement.step(function (error, row) {
if (error) throw error;
assert.ok(!row, "Row should be unset");
statement.reset();
if (--i)
statement.step(arguments.callee);
else
callback();
});
});
}
var updateSQL
= 'UPDATE table1 SET name="o hai"';
insertRows(self.db, 10, function () {
self.db.prepare(updateSQL
, { affectedRows: true }
, updateStatementCreated);
});
});
});
}
}
];
// order matters in our tests
for (var i=0,il=tests.length; i < il; i++) {
suite.addTests(tests[i]);
}
var currentTest = 0;
var testCount = tests.length;
suite.setup(function(finished, test) {
this.db = new sqlite.Database();
finished();
});
suite.teardown(function(finished) {
if (this.db) this.db.close(function (error) {
finished();
});
++currentTest == testCount;
});
if (module == require.main) {
suite.runTests();
}
require.paths.push(__dirname + '/..');
sys = require('sys');
fs = require('fs');
path = require('path');
TestSuite = require('async-testing/async_testing').TestSuite;
sqlite = require('sqlite3_bindings');
puts = sys.puts;
inspect = sys.inspect;
// createa table
// prepare a statement (with options) that inserts
// do a step
// check that the result has a lastInsertedId property
var suite = exports.suite = new TestSuite("node-sqlite last inserted id test");
function createTestTable(db, callback) {
db.prepare('CREATE TABLE table1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)',
function (error, createStatement) {
if (error) throw error;
createStatement.step(function (error, row) {
if (error) throw error;
callback();
});
});
}
function fetchAll(db, sql, callback) {
db.prepare(
sql,
function (error, statement) {
if (error) throw error;
var rows = [];
function doStep() {
statement.step(function (error, row) {
if (error) throw error;
if (row) {
rows.push(row);
doStep();
}
else {
callback(rows);
}
});
}
doStep();
});
}
var tests = [
{ 'insert a row with lastinsertedid':
function (assert, finished) {
var self = this;
self.db.open(':memory:', function (error) {
function createStatement(error, statement) {
if (error) throw error;
statement.step(function (error, row) {
puts("This is " + inspect(this));
assert.equal(this.lastInsertRowID, 101, "Last inserted id should be 1");
assert.equal(this.affectedRows, 1, "Last inserted id should be 1");
statement.reset();
statement.step(function (error, row) {
puts("This is " + inspect(this));
assert.equal(this.lastInsertRowID, 102, "Last inserted id should be 1");
assert.equal(this.affectedRows, 1, "Last inserted id should be 1");
finished();
});
});
}
createTestTable(self.db,
function () {
var insertSQL
= 'INSERT INTO table1 (id, name) VALUES (100, "first post!")';
self.db.prepareAndStep(insertSQL, function (error, row) {
if (error) throw error;
assert.ok(!row, "Row was trueish, but should be falseish");
self.db.prepare('INSERT INTO table1 (name) VALUES ("orlando")'
, { affectedRows: true, lastInsertRowID: true }
, createStatement);
});
});
});
}
}
];
// order matters in our tests
for (var i=0,il=tests.length; i < il; i++) {
suite.addTests(tests[i]);
}
var currentTest = 0;
var testCount = tests.length;
suite.setup(function(finished, test) {
this.db = new sqlite.Database();
finished();
});
suite.teardown(function(finished) {
if (this.db) this.db.close(function (error) {
finished();
});
++currentTest == testCount;
});
if (module == require.main) {
suite.runTests();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment