Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

pushStar is starting to work

  • Loading branch information...
commit 451772db72bffa74224efc0eadbb59a73988d820 1 parent f8e0de8
Chris Dew authored
19 lib/database.js
View
@@ -43,15 +43,26 @@ Database.prototype.selectStar = function(spec, callback) {
var table = this.tablesByName[spec.from[0]];
if (!table) return callback("Error: table '" + spec.from[0] + "' does not exist.");
table.selectStar(spec, callback);
- return this;
+ //return this;
+}
+
+Database.prototype.pushStar = function(spec, callback) {
+ // TODO: handle multi table selects
+ assert(spec.from.length === 1);
+ var table = this.tablesByName[spec.from[0]];
+ if (!table) return callback("Error: table '" + spec.from[0] + "' does not exist.");
+ return table.pushStar(spec, callback);
}
+
// command is a Javascript object, the result of parsing a line
Database.prototype.exec = function(command, callback) {
//console.log(command);
for (var p in command) { // there will only be one
- if (p === 'createTable') this.createTable(command[p], callback);
- if (p === 'insert') this.insert(command[p], callback);
- if (p === 'selectStar') this.selectStar(command[p], callback);
+ if (p === 'createTable') return this.createTable(command[p], callback);
+ if (p === 'insert') return this.insert(command[p], callback);
+ if (p === 'selectStar') return this.selectStar(command[p], callback);
+ if (p === 'pushStar') return this.pushStar(command[p], callback);
}
+ return callback("unhandled command: " + JSON.stringify(command));
}
123 lib/query.js
View
@@ -0,0 +1,123 @@
+// This class represents a Database
+
+var util = require('util');
+var events = require('events');
+var row = require('./row');
+var assert = require('assert');
+
+exports.hello = hello;
+exports.Query = Query;
+
+function hello() {
+ return "hello query";
+}
+
+
+function Query(table, spec) {
+ console.log("Query::Query spec:", spec);
+ var that = this;
+
+ // subscribe to table changes
+ this.table = table;
+
+ table.on('delta', function(delta) {
+ console.log('received delta from table', delta);
+ that.emit('delta', delta);
+ });
+
+ var whereFn = function() { return true; };
+ if (spec.where && spec.where.expr) {
+ whereFn = createFn(spec.where.expr);
+ }
+
+ var ret = [];
+ for (var p in table.rowsByPk) {
+ var row = table.rowsByPk[p];
+ if (whereFn(row)) {
+ ret.push(row);
+ }
+ }
+
+ // we make a separate init event, rather than making them all deltas, as
+ // there needs to be a clear divide beween the
+ // a) accumulated change over all history before the query (i.e. initial state) and the
+ // b) realtime deltas after the query
+ process.nextTick(function() {
+ console.log('init', ret);
+ that.emit('init', ret);
+ });
+}
+
+util.inherits(Query, events.EventEmitter);
+
+
+function createFn(expr) {
+ console.log("createFn", expr);
+ if (typeof(expr) === "string") {
+ return function() {
+ return expr;
+ }
+ }
+ if (typeof(expr) === "number") {
+ return function() {
+ return expr;
+ }
+ }
+ if (expr.field) {
+ return function(r) {
+ return r[expr.field];
+ }
+ }
+
+ assert(expr.fn);
+ var arity = expr.args.length;
+ var fns = [];
+ for (var i = 0; i < arity; i++) {
+ fns.push(createFn(expr.args[i]));
+ }
+
+ if (arity === 0) {
+ } else if (arity === 1) {
+ if (expr.fn === 'equalsOne') {
+ return function(r) {
+ return fns[0](r) === 1;
+ }
+ }
+ } else if (arity === 2) {
+ if (expr.fn === 'equal') {
+ return function(r) {
+ return fns[0](r) === fns[1](r);
+ }
+ }
+ if (expr.fn === 'and') {
+ return function(r) {
+ return fns[0](r) && fns[1](r);
+ }
+ }
+ if (expr.fn === 'gt') {
+ return function(r) {
+ return fns[0](r) > fns[1](r);
+ }
+ }
+ if (expr.fn === 'gte') {
+ return function(r) {
+ return fns[0](r) >= fns[1](r);
+ }
+ }
+ if (expr.fn === 'lt') {
+ return function(r) {
+ return fns[0](r) < fns[1](r);
+ }
+ }
+ if (expr.fn === 'lte') {
+ return function(r) {
+ return fns[0](r) <= fns[1](r);
+ }
+ }
+ } else {
+ throw "cannot handle arity of " + arity + " in " + JSON.stringify(expr);
+ }
+ throw "cannot handle " + JSON.stringify(expr);
+}
+
+
8 lib/session.js
View
@@ -47,12 +47,16 @@ Session.prototype.exec = function(line, callback) {
console.log('emitting result Table created.');
return callback(null, 'Table created.');
});
- this.db.exec(command, function(err, res) {
+ var query = this.db.exec(command, function(err, res) {
console.log("command", command);
console.log("err", err);
console.log("res", res);
- callback(err, res);
+ if (typeof(callback) === 'function') {
+ callback(err, res);
+ }
});
+ console.log("6query", query);
+ return query;
}
// the unregisters all the resources this session is using
15 lib/table.js
View
@@ -3,6 +3,7 @@
var util = require('util');
var events = require('events');
var row = require('./row');
+var qry = require('./query');
var assert = require('assert');
exports.hello = hello;
@@ -76,8 +77,9 @@ Table.prototype.insert = function(spec, callback) {
var r = new row.Row(spec.fields, spec.values);
this.rowsByPk[pk] = r;
- if (callback) callback(null, "1 row inserted.");
+ console.log('Table::insert emitting');
this.emit('delta', {op:'insert',table:this.name,row:r});
+ if (callback) callback(null, "1 row inserted.");
return this;
}
@@ -116,6 +118,17 @@ Table.prototype.selectStar = function(spec, callback) {
callback(null, ret);
}
+Table.prototype.pushStar = function(spec, callback) {
+ console.log("Table::pushStar", spec);
+
+ var query = new qry.Query(this, spec);
+
+ return query;
+}
+
+
+
+
function createFn(expr) {
console.log("createFn", expr);
if (typeof(expr) === "string") {
21 test/database-test.js
View
@@ -45,5 +45,26 @@ describe('Database', function() {
});
/*
*/
+
+ it('should run a complex pushStar query', function(done) {
+ var query = db.pushStar({"from":["mytable"],"where":{"expr":{"fn":"and","args":[{"fn":"gte","args":[{"field":"id"},1]},{"fn":"lt","args":[{"field":"id"},4]}]}}});
+ var initialised = false;
+ query.once('init', function(data) {
+ console.log("initialised = true");
+ initialised = true;
+ assert.deepEqual([{"_version":1,"id":1,"foo":"hello"}], data);
+ db.insert( {"table":"mytable","fields":["id","foo"],"values":[2,"world"]});
+ });
+ query.on('delta', function(delta) {
+ console.log('delta received');
+ console.log("initilised", initialised);
+ assert(initialised);
+ assert.deepEqual({"op":"insert","table":"mytable","row":{"_version":1,"id":2,"foo":"world"}}, delta);
+ done();
+ });
+ //console.log('query', query.constructor, JSON.stringify(query));
+
+ });
+
});
34 test/demo-test.js
View
@@ -25,5 +25,39 @@ describe('Session', function() {
});
});
});
+ var db2 = new database.Database();
+ var sess2 = new session.Session(db2);
+ it('should run a complex realtime script', function(done) {
+ sess2.exec('create table events (id integer primary key auto_increment, name varchar, start integer, duration integer)', function(err, res) {
+ assert.equal('Table created.', res);
+ sess2.exec('insert into events (name, start, duration) values ("dentist", 1000, 100)', function(err, res) {
+ assert.equal('1 row inserted.', res);
+ sess2.exec('insert into events (name, start, duration) values ("doctor", 3000, 100)', function(err, res) {
+ assert.equal('1 row inserted.', res);
+ sess2.exec('insert into events (name, start, duration) values ("accountant", 5000, 100)', function(err, res) {
+ assert.equal('1 row inserted.', res);
+ var query = sess2.exec('push * from events where start >= 1000 and start < 4000');
+ var initialised = false;
+console.log("AAA", query);
+ query.once('init', function(data) {
+ console.log("init", data);
+ assert.deepEqual([ { _version: 1, name: 'dentist', start: 1000, duration: 100 },
+ { _version: 1, name: 'doctor', start: 3000, duration: 100 } ], data)
+ initialised = true;
+ sess2.exec('insert into events (name, start, duration) values ("barber", 3000, 100)', function(err, res) {
+ assert.equal('1 row inserted.', res);
+ console.log("got here");
+ });
+ });
+ query.once('delta', function(delta) {
+ console.log("delta", delta);
+ assert(initialised);
+ done();
+ });
+ });
+ });
+ });
+ });
+ });
});
5 test/grammar-test.js
View
@@ -68,4 +68,9 @@ This test takes 25s to run! All the others take 149ms in total.
assert.deepEqual({"selectStar":{"from":["bar"],"where":{"expr":{"fn":"and","args":[{"fn":"equal","args":[{"field":"x"},1]},{"fn":"gt","args":[{"field":"x"},0]}]}}}},
parser.parse('select * from bar where x = 1 and x > 0'));
});
+ it('push * from events where start >= 1000 and start < 4000', function() {
+ //console.log(JSON.stringify(parser.parse('push * from events where start >= 1000 and start < 4000')));
+ assert.deepEqual({"pushStar":{"from":["events"],"where":{"expr":{"fn":"and","args":[{"fn":"gte","args":[{"field":"start"},1000]},{"fn":"lt","args":[{"field":"start"},4000]}]}}}},
+ parser.parse('push * from events where start >= 1000 and start < 4000'));
+ });
});
9 test/query-test.js
View
@@ -0,0 +1,9 @@
+var assert = require("assert")
+
+var query = require('../lib/query.js');
+describe('Query', function() {
+ it('should say "hello query"', function() {
+ assert.equal("hello query", query.hello());
+ });
+});
+
Please sign in to comment.
Something went wrong with that request. Please try again.