Permalink
Browse files

Allow bind of nulls. Clean up some.

  • Loading branch information...
1 parent ae95e3c commit 3992c84e0d8e8359a7737a6dd60967e486b3214f @grumdrig committed with Eric Fredricksen Dec 15, 2009
Showing with 189 additions and 36 deletions.
  1. +145 −0 examples.js
  2. +26 −25 sqlite.js
  3. +2 −0 sqlite3_bindings.cc
  4. +16 −11 test.js
View
@@ -0,0 +1,145 @@
+#!/usr/local/bin/node
+/*
+//!! To be processed by docbyex.py (or run by Node)
+
+<head>
+<title>node-sqlite</title>
+<style>
+ pre, code { color: #060; font-size: 11pt; }
+ pre { margin-left: 2ex; padding: 1ex; background: #eee; }
+ p { font-size: 12pt; }
+ body { margin: 2em; background-color: #fff; color: black }
+</style>
+</head>
+
+<body>
+<h1>node-sqlite</h1>
+
+<a href=http://sqlite.org/>SQLite</a> bindings for
+<a //href=http://nodejs.org/>Node</a>.
+
+The semantics conform somewhat to those of the <a
+href=http://dev.w3.org/html5/webdatabase/#sql>HTML5 Web SQL API</a>,
+plus some extensions. Also, only the synchronous API is implemented;
+the asynchronous API is a big TODO item.
+
+<h2>Documentation by Example</h2>
+*/
+
+// Import the library and open a database. (Only syncronous database
+// access is implemented at this time.)
+
+var sqlite = require("./sqlite");
+var db = sqlite.openDatabaseSync("example.db");
+
+// Perform an SQL query on the database:
+
+db.query("CREATE TABLE foo (a,b,c)");
+
+// This is a more convenient form than the HTML5 syntax for the same
+// thing, but which is also supported:
+
+db.transaction(function(tx) {
+ tx.executeSql("CREATE TABLE bar (x,y,z)");
+});
+
+// This allows the same or similar code to work on the client and
+// server end (modulo browser support of HTML5 Web SQL).
+
+// Transactions generate either a "commit" or "rollback" event.
+
+var rollbacks = 0;
+db.addListener("rollback", function () {
+ ++rollbacks;
+});
+
+// Both forms take an optional second parameter which is values to
+// bind to fields in the query, as an array:
+
+db.query("INSERT INTO foo (a,b,c) VALUES (?,?,?)", ['apple','banana',22]);
+
+// or as a map:
+
+db.query("INSERT INTO bar (x,y,z) VALUES ($x,$y,$zebra)",
+ {$x: 10, $y:20, $zebra:"stripes"});
+
+// Also optional is a callback function which is called with an object
+// representing the results of the query:
+
+db.query("SELECT x FROM bar", function (records) {
+ process.assert(records.length == 1);
+ process.assert(records[0].x == 10);
+
+ // The HTML5 semantics for the record set also work:
+
+ process.assert(records.rows.length == 1);
+ process.assert(records.rows.item(0).x == 10);
+});
+
+// INSERT, UPDATE & DELETE queries set `rowsAffected` on their result
+// set object:
+
+db.query("UPDATE foo SET a = ? WHERE a = ?", ['orange', 'apple'], function(r) {
+ process.assert(r.rowsAffected == 1);
+});
+
+// They also emit an `"update"` event.
+
+// INSERT queries set `insertId`:
+
+var insert = db.query("INSERT INTO foo VALUES (1,2,3)");
+process.assert(insert.insertId == 2);
+
+// Note here that the result set passed to the callback is also
+// returned by `query`.
+
+// Multiple-statement queries are supported; each statement's result set is retuned to the callback as a separate parameter:
+
+var q = db.query("UPDATE bar SET z=20; SELECT SUM(z) FROM bar;",
+ function (update, select) {
+ process.assert(update.rowsAffected == 1);
+ process.assert(select[0]['SUM(z)'] == 20);
+ });
+
+// An array of all result sets is available as the `.all` property on
+// each result set:
+
+process.assert(q.all[1].length == 1);
+
+// HTML5 semantics are supported.
+
+db.transaction(function(tx) {
+ tx.executeSql("SELECT * FROM foo WHERE c = ?", [3], function(tx,res) {
+ process.assert(res.rows.item(0).c == 3);
+ });
+});
+
+// The `query` and `transaction` APIs wrap lower level APIs that more
+// thinly wrap the underlying C api:
+
+var stmt = db.prepare("INSERT INTO foo VALUES (?,?,?)");
+stmt.bind(1, "curly");
+stmt.bind(2, "moe");
+stmt.bind(3, "larry");
+stmt.step(); // Insert Curly, Moe & Larry
+stmt.reset();
+stmt.step(); // Insert another row with same stooges
+stmt.reset();
+stmt.clearBindings();
+stmt.bind(2, "lonely");
+stmt.step(); // Insert (null, "lonely", null)
+stmt.finalize();
+
+// Close it!
+
+db.close();
+
+// !!**
+// Might as well clean up the mess we made.
+
+var posix = require("posix");
+posix.unlink('example.db');
+
+var sys = require("sys");
+sys.puts("OK");
+
View
@@ -16,7 +16,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// TODO: async
-var sys = require("sys");
var bindings = require("./sqlite3_bindings");
process.mixin(GLOBAL, bindings);
process.mixin(exports, bindings);
@@ -31,23 +30,23 @@ exports.SQLITE_UPDATE = 23;
exports.openDatabaseSync = function (name, version, displayName,
estimatedSize, creationCallback) {
+ // 2nd-4th parameters are ignored
var db = new DatabaseSync(name);
if (creationCallback) creationCallback(db);
return db;
}
-DatabaseSync.prototype.performQuery = function(sql, bindings,
- callback, errback) {
- var all = [];
-
- // bindings param is optional
- if (typeof bindings == 'function') {
- errback = callback;
- callback = bindings;
- bindings = null;
+DatabaseSync.prototype.query = function (sql, bindings, callback) {
+ // TODO: error callback
+ if (typeof(bindings) == "function") {
+ var tmp = bindings;
+ bindings = callback;
+ callback = tmp;
}
+ var all = [];
+
var stmt = this.prepare(sql);
while(stmt) {
if (bindings) {
@@ -77,19 +76,7 @@ DatabaseSync.prototype.performQuery = function(sql, bindings,
stmt.finalize();
stmt = this.prepare(stmt.tail);
}
-
- return all;
-}
-
-DatabaseSync.prototype.query = function (sql, bindings, callback) {
- // TODO: error callback
- if (typeof(bindings) == "function") {
- var tmp = bindings;
- bindings = callback;
- callback = tmp;
- }
- var all = this.performQuery(sql, bindings);
if (all.length == 0) {
var result = null;
} else {
@@ -116,7 +103,10 @@ DatabaseSync.prototype.query = function (sql, bindings, callback) {
function SQLTransactionSync(db, txCallback, errCallback, successCallback) {
this.database = db;
+ this.rolledBack = false;
+
this.executeSql = function(sqlStatement, arguments, callback) {
+ if (this.rolledBack) return;
var result = db.query(sqlStatement, arguments);
if (callback) {
var tx = this;
@@ -125,10 +115,21 @@ function SQLTransactionSync(db, txCallback, errCallback, successCallback) {
return result;
}
- db.query("BEGIN TRANSACTION");
+ var that = this;
+ function unroll() {
+ that.rolledBack = true;
+ }
+
+ db.addListener("rollback", unroll);
+
+ this.executeSql("BEGIN TRANSACTION");
txCallback(this);
- db.query("COMMIT");
- if (successCallback) successCallback(this);
+ this.executeSql("COMMIT");
+
+ db.removeListener("rollback", unroll);
+
+ if (!this.rolledBack && successCallback)
+ successCallback(this);
}
View
@@ -259,6 +259,8 @@ class Sqlite3Db : public EventEmitter
} else if (args[1]->IsString()) {
String::Utf8Value text(args[1]);
sqlite3_bind_text(*stmt, index, *text, text.length(),SQLITE_TRANSIENT);
+ } else if (args[1]->IsNull() || args[1]->IsUndefined()) {
+ sqlite3_bind_null(*stmt, index);
} else {
return ThrowException(Exception::TypeError(
String::New("Unable to bind value of this type")));
View
27 test.js
@@ -49,8 +49,8 @@ db.query("INSERT INTO egg (a,y,e) VALUES (?,?,?)", [1.01, 10e20, -0.0]);
db.query("INSERT INTO egg (a,y,e) VALUES (?,?,?)", ["one", "two", "three"]);
db.query("SELECT * FROM egg", function (rows) {
- sys.puts(JSON.stringify(rows));
- });
+ sys.puts(JSON.stringify(rows));
+});
db.query("SELECT a FROM egg; SELECT y FROM egg", function (as, ys) {
sys.puts("As " + JSON.stringify(as));
@@ -80,16 +80,15 @@ db.transaction(function(tx) {
db.query("CREATE TABLE test (x,y,z)", function () {
- db.query("INSERT INTO test (x,y) VALUES (?,?)", [5,10]);
- db.query("INSERT INTO test (x,y,z) VALUES ($x, $y, $z)", {$x:1, $y:2, $z:3});
- });
+ db.query("INSERT INTO test (x,y) VALUES (?,?)", [5,10]);
+ db.query("INSERT INTO test (x,y,z) VALUES ($x,$y,$z)", {$x:1, $y:2, $z:3});
+});
db.query("SELECT * FROM test WHERE rowid < ?;", [1]);
db.query("UPDATE test SET y = 10;", [], function () {
- sys.puts(this.rowsAffected + " rows affected");
- process.assert(this.rowsAffected == 2);
- });
+ process.assert(this.rowsAffected == 2);
+});
db.transaction(function(tx) {
tx.executeSql("SELECT * FROM test WHERE x = ?", [1], function (tx,records) {
@@ -107,10 +106,16 @@ try {
} catch (e) {
}
+db.transaction(function(tx){
+ for (var i = 0; i < 3; ++i)
+ tx.executeSql("INSERT INTO test VALUES (6,6,6)");
+ tx.executeSql("ROLLBACK");
+});
+
-sys.puts("commits: " + commits);
-sys.puts("rollbacks: " + rollbacks);
-sys.puts("updates: " + updates);
+asserteq(commits, 14);
+asserteq(rollbacks, 1);
+asserteq(updates, 19);
db.close();

0 comments on commit 3992c84

Please sign in to comment.