Commit 4093c784 by Eric Fredricksen Committed by Eric Fredricksen

Initial commit of contents of svn repo. node_sqlite is sqlite3 bindings for node.js

parents
syntax:glob
build
README.html
.svn
test.db
.lock-wscript
Node.js bindings for sqlite3
============================
Functions
-------------------
### `new sqlite3.Db(filename)`
Returns an object representing the sqlite3 database with given filename.
### `sqlite3.Db.query(sql [,bindings] [,callback])`
Executes the query `sql`, with variables bound from `bindings`. The
variables can take the form `?` or `?NNN` where `NNN` is a number, in which
case `bindings` should be an array of values, or the form `$VVV` where
`VVV` is an identifier, in which canse `bindings` should be an object
with keys matching the variable names.
If provided the `callback` is called with an argument for each
statement in the query. Each argument is an array of objects mapping
column names to values.
Each callback argument `rows` also has these properties
- **`rows.count`** is the number of rows affected by the query.
- **`rows.rowid`** is the `ROWID` of the last `INSERT` command
Within the callback, `this` is an array of all such arrays, with a
`count` property giving the total number of rows affected. That same
`this` object is returned by `query`.
### `sqlite3.Db.close()`
Closes the database.
Example
--------
var sqlite3 = require("./sqlite3");
var db = new sqlite3.Db("test.db");
db.query("INSERT INTO test (column) VALUES ($value)", {$value: 10});
db.query("SELECT column FROM test WHERE rowid<?", [5], function (rows) {
process.assert(rows[0].column == 10);
});
db.query("UPDATE test SET column=20; SELECT column FROM test;",
function (update, select) {
assert(update.count == 1);
assert(select[0].column == 20);
});
db.close();
Build
-----
`$` **`node-waf build`**
Test
----
`$` **`node test.js`**
var sys = require("sys");
function handler(curr, prev) {
sys.puts("Handling");
sys.puts("the current mtime is: " + curr.mtime);
sys.puts("the previous mtime was: " + prev.mtime);
sys.exec("clear;rm -f test.db; node-waf build && node test.js");
}
sys.puts(JSON.stringify(process.ARGV));
for (f in process.ARGV) {
f = process.ARGV[f]
sys.puts("Watching " + f);
process.watchFile(f, handler);
}
//var tcp = require("tcp");
//var server = tcp.createServer();
//server.listen(7000, "localhost");
for (;;) {
sys.exec("sleep 1").wait();
}
//var p = new process.Promise();
//p.wait();
\ No newline at end of file
#!/usr/bin/python
# Wait for changes for files specified on the command line, or here in the file
# Then compile and run test. And do this forever.
import os, sys, time
#filenames = sys.argv[1:]
filenames = ["sqlite3_bindings.cc", "wscript", "sqlite3.js", "test.js"]
mdname = "README"
def handler():
os.system("clear; rm -f test.db")
os.system("node-waf build && node test.js && sqlite3 test.db .dump");
mtime = []
mdtime = None
while True:
m = [os.stat(filename).st_mtime for filename in filenames]
if mtime != m:
handler()
mtime = m
m = os.stat(mdname).st_mtime
if mdtime != m:
os.system("Markdown.pl < %s > %s.html" % (mdname, mdname))
mdtime = m
time.sleep(1)
var sys = require("sys");
var bindings = require("./sqlite3_bindings");
var Db = bindings.Db;
Db.prototype.query = function (sql, bindings, callback) {
if (typeof(bindings) == "function") {
var tmp = bindings;
bindings = callback;
callback = tmp;
}
var result = this.performQuery(sql, bindings);
if (typeof(callback) == "function") {
callback.apply(result, result);
}
return result;
}
exports.Db = Db;
\ No newline at end of file
#include <sqlite3.h>
#include <v8.h>
#include <node.h>
#include <node_events.h>
#include <deque>
using namespace v8;
using namespace node;
class Sqlite3Db : public EventEmitter
{
public:
static void Init(v8::Handle<Object> target)
{
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(New);
t->Inherit(EventEmitter::constructor_template);
t->InstanceTemplate()->SetInternalFieldCount(1);
NODE_SET_PROTOTYPE_METHOD(t, "performQuery", PerformQuery);
NODE_SET_PROTOTYPE_METHOD(t, "close", Close);
target->Set(v8::String::NewSymbol("Db"), t->GetFunction());
}
protected:
Sqlite3Db(sqlite3* db) : db_(db) {
}
~Sqlite3Db() {
sqlite3_close(db_);
}
sqlite3* db_;
operator sqlite3* () { return db_; }
protected:
static Handle<Value> New(const Arguments& args)
{
HandleScope scope;
if (args.Length() == 0 || !args[0]->IsString()) {
return ThrowException(Exception::TypeError(
String::New("First argument must be a string")));
}
String::Utf8Value filename(args[0]->ToString());
sqlite3* db;
int rc = sqlite3_open(*filename, &db);
if (rc) {
Local<String> err = v8::String::New(sqlite3_errmsg(db));
sqlite3_close(db);
return ThrowException(Exception::Error(err));
}
(new Sqlite3Db(db))->Wrap(args.This());
return args.This();
}
static Handle<Value> PerformQuery(const Arguments& args)
{
HandleScope scope;
Sqlite3Db* db = ObjectWrap::Unwrap<Sqlite3Db>(args.This());
if (args.Length() == 0 || !args[0]->IsString()) {
return ThrowException(Exception::TypeError(
String::New("First argument must be a string")));
}
String::Utf8Value usql(args[0]->ToString());
const char* sql(*usql);
int changes = 0;
int param = 0;
std::deque< Handle<Array> > resulting;
for(;;) {
sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(*db, sql, -1, &stmt, &sql);
if (!stmt) break;
Statement statement(stmt);
if (args.Length() > 1) {
if (args[1]->IsArray()) {
Local<Array> a(Array::Cast(*args[1]));
int start = param;
int stop = start + sqlite3_bind_parameter_count(statement);
for (; param < a->Length() && param < stop; ++param) {
Local<Value> v = a->Get(Integer::New(param));
statement.Bind(param+1-start, v);
}
} else if (args[1]->IsObject()) {
Local<Array> keys(args[1]->ToObject()->GetPropertyNames());
for (int k = 0; k < keys->Length(); ++k) {
Local<Value> key(keys->Get(Integer::New(k)));
statement.Bind(key, args[1]->ToObject()->Get(key));
}
} else if (args[1]->IsUndefined() || args[1]->IsNull()) {
// That's okay
} else {
return ThrowException(Exception::TypeError(
String::New("Second argument invalid")));
}
}
std::deque< Handle<Object> > rows;
for (int r = 0; ; ++r) {
int rc = sqlite3_step(statement);
if (rc == SQLITE_ROW) {
Local<Object> row = Object::New();
for (int c = 0; c < sqlite3_column_count(statement); ++c) {
Handle<Value> value;
switch (sqlite3_column_type(statement, c)) {
case SQLITE_INTEGER:
value = Integer::New(sqlite3_column_int(statement, c));
break;
case SQLITE_FLOAT:
value = Number::New(sqlite3_column_double(statement, c));
break;
case SQLITE_TEXT:
value = String::New((const char*) sqlite3_column_text(statement, c));
break;
case SQLITE_NULL:
default: // We don't handle any other types just now
value = Undefined();
break;
}
row->Set(String::NewSymbol(sqlite3_column_name(statement, c)),
value);
}
rows.push_back(row);
} else if (rc == SQLITE_DONE) {
break;
} else {
return ThrowException(Exception::Error(
v8::String::New(sqlite3_errmsg(*db))));
}
}
changes += sqlite3_changes(*db);
Local<Array> rosult(Array::New(rows.size()));
std::deque< Handle<Object> >::const_iterator ri(rows.begin());
for (int r = 0; r < rows.size(); ++r, ++ri)
rosult->Set(Integer::New(r), *ri);
rosult->Set(String::New("changes"), Integer::New(sqlite3_changes(*db)));
rosult->Set(String::New("rowid"),
Integer::New(sqlite3_last_insert_rowid(*db)));
resulting.push_back(rosult);
}
Local<Array> result(Array::New(0));
result->Set(String::New("changes"), Integer::New(changes));
result->Set(String::New("rowid"),
Integer::New(sqlite3_last_insert_rowid(*db)));
std::deque< Handle<Array> >::iterator ri(resulting.begin());
for (int r = 0; r < resulting.size(); ++r, ++ri) {
result->Set(Integer::New(r), *ri);
}
return result;
}
static Handle<Value> Close (const Arguments& args)
{
Sqlite3Db* db = ObjectWrap::Unwrap<Sqlite3Db>(args.This());
HandleScope scope;
db->Close();
return Undefined();
}
void Close() {
sqlite3_close(db_);
db_ = NULL;
Detach();
}
class Statement : public EventEmitter
{
public:
Statement(sqlite3_stmt* stmt) : stmt_(stmt) {}
~Statement() { sqlite3_finalize(stmt_); }
operator sqlite3_stmt* () { return stmt_; }
bool Bind(int index, Handle<Value> value)
{
HandleScope scope;
if (value->IsInt32()) {
sqlite3_bind_int(stmt_, index, value->Int32Value());
} else if (value->IsNumber()) {
sqlite3_bind_double(stmt_, index, value->NumberValue());
} else if (value->IsString()) {
String::Utf8Value text(value);
sqlite3_bind_text(stmt_, index, *text, text.length(), SQLITE_TRANSIENT);
} else {
return false;
}
return true;
}
bool Bind(Handle<Value> key, Handle<Value> value) {
HandleScope scope;
String::Utf8Value skey(key);
//string x = ":" + key
int index = sqlite3_bind_parameter_index(stmt_, *skey);
Bind(index, value);
}
Handle<Object> Cast()
{
HandleScope scope;
Local<ObjectTemplate> t(ObjectTemplate::New());
t->SetInternalFieldCount(1);
Local<Object> thus = t->NewInstance();
thus->SetInternalField(0, External::New(this));
//Wrap(thus);
return thus;
}
protected:
sqlite3_stmt* stmt_;
};
};
extern "C" void init (v8::Handle<Object> target)
{
Sqlite3Db::Init(target);
}
build/default/sqlite3_bindings.node
\ No newline at end of file
// Test script for node_sqlite
var sys = require("sys");
var sqlite3 = require("./sqlite3");
var db = new sqlite3.Db('test.db');
db.query("CREATE TABLE egg (a,y,e)");
db.query("INSERT INTO egg (a) VALUES (1)", function () {
process.assert(this.rowid == 1);
});
var i2 = db.query("INSERT INTO egg (a) VALUES (?)", [5]);
process.assert(i2.rowid == 2);
db.query("UPDATE egg SET y='Y'; UPDATE egg SET e='E';");
db.query("UPDATE egg SET y=?; UPDATE egg SET e=? WHERE ROWID=1",
["arm","leg"] );
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));
});
db.query("SELECT a FROM egg; SELECT y FROM egg", function (as, ys) {
sys.puts("As " + JSON.stringify(as));
sys.puts("Ys " + JSON.stringify(ys));
});
db.query("SELECT e FROM egg WHERE a = ?", [5], function (rows) {
process.assert(rows[0].e == "E");
});
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("SELECT * FROM test WHERE rowid < ?;", [1],
function (stmt) {
sys.puts("rose:");
sys.puts(stmt);
});
db.query("UPDATE test SET y = 10;", [], function () {
sys.puts(this.changes + " rows affected");
process.assert(this.changes == 2);
});
db.close();
sys.puts("OK\n");
process.exit()
// Perhaps do this, one day
//var q = db.prepare("SELECT * FROM t WHERE rowid=?");
//var rows = q.execute([1]);
// Perhaps use this syntax if query starts returning a promise:
c.query("select * from test;").addCallback(function (rows) {
puts("result1:");
p(rows);
});
c.query("select * from test limit 1;").addCallback(function (rows) {
puts("result2:");
p(rows);
});
c.query("select ____ from test limit 1;").addCallback(function (rows) {
puts("result3:");
p(rows);
}).addErrback(function (e) {
puts("error! "+ e.message);
puts("full: "+ e.full);
puts("severity: "+ e.severity);
c.close();
});
srcdir = "."
blddir = "build"
VERSION = "0.0.1"
def set_options(opt):
opt.tool_options("compiler_cxx")
def configure(conf):
conf.check_tool("compiler_cxx")
conf.check_tool("node_addon")
def build(bld):
obj = bld.new_task_gen("cxx", "shlib", "node_addon")
obj.target = "sqlite3_bindings"
obj.source = "sqlite3_bindings.cc"
obj.lib = "sqlite3"
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