Permalink
Browse files

insert working

  • Loading branch information...
joeferner committed Dec 8, 2011
1 parent 58d8628 commit 42604c2644a0619cdace65c8f833e4ff128239c4
View
@@ -0,0 +1,2 @@
+node_modules
+test.db
View
@@ -0,0 +1,38 @@
+
+var util = require('util');
+var persistUtils = require('./persist_utils');
+var Transaction = require('./transaction');
+
+var Connection = persistUtils.Class.extend({
+ init: function(driver) {
+ this.driver = driver;
+ },
+
+ save: function(obj, callback) {
+ var sqlAndValues = this.driver.getInsertSql(obj);
+ this.runSql(sqlAndValues.sql, sqlAndValues.values, function(err, data) {
+ if(err) callback(err);
+ if(data.lastId) {
+ var idPropName = obj._model.getIdPropertyName();
+ obj[idPropName] = data.lastId;
+ }
+ callback(null, obj);
+ });
+ },
+
+ // sql, values, callback
+ // sql, callback
+ runSql: function() {
+ throw new Error("Not Implemented");
+ },
+
+ close: function() {
+ throw new Error("Not Implemented");
+ },
+
+ tx: function(callback) {
+ callback(null, new Transaction(this));
+ }
+});
+
+module.exports = Connection;
View
@@ -0,0 +1,30 @@
+
+var persistUtils = require('./persist_utils');
+
+var Driver = persistUtils.Class.extend({
+ init: function() {
+ },
+
+ connect: function(opts, callback) {
+ throw new Error("Not Implemented");
+ },
+
+ getInsertSql: function(obj) {
+ var columnNamesSql = [];
+ var valuesSql = [];
+ var values = [];
+
+ for(var columnKey in obj._model.columns) {
+ var column = obj._model.columns[columnKey];
+ if(column.primaryKey && column.autoIncrement) continue;
+ columnNamesSql.push(column.dbColumnName);
+ valuesSql.push('?');
+ values.push(obj[columnKey]);
+ }
+
+ var sql = 'INSERT INTO ' + obj._model.modelName + '(' + columnNamesSql.join(',') + ') VALUES (' + valuesSql.join(',') + ');';
+ return { sql: sql, values: values };
+ }
+});
+
+module.exports = Driver;
View
@@ -0,0 +1,62 @@
+
+var Driver = require('../driver');
+var Connection = require('../connection');
+var sqlite3 = require('sqlite3').verbose();
+
+var Sqlite3Driver = Driver.extend({
+ init: function() {
+ this._super();
+ },
+
+ connect: function(opts, callback) {
+ var filename = opts.filename;
+ if(!filename) throw new Error("Sqlite3 driver requires 'filename'");
+ var trace = opts.trace;
+
+ var db = new sqlite3.Database(filename);
+ if(trace) {
+ db.on('trace', function(sql) {
+ console.log(sql);
+ });
+ }
+ var connection = new Sqlite3Connection(this, db);
+ callback(null, connection);
+ }
+});
+
+var Sqlite3Connection = Connection.extend({
+ init: function(driver, db) {
+ this._super(driver);
+ this.db = db;
+ },
+
+ close: function() {
+ this.db.close();
+ },
+
+ runSql: function() {
+ var stmt;
+ if(arguments.length == 2) { // sql, callback
+ var callback = arguments[1];
+ this.db.run(arguments[0], function(err) {
+ if(err) callback(err);
+ callback(null, {});
+ });
+ } else if(arguments.length == 3) { // sql, values, callback
+ var callback = arguments[2];
+ stmt = this.db.prepare(arguments[0], function(err) {
+ if(err) callback(err);
+ });
+ stmt.run(arguments[1], function(err) {
+ if(err) callback(err);
+ callback(null, {
+ lastId: stmt.lastID,
+ changes: stmt.changes
+ });
+ });
+ stmt.finalize();
+ }
+ }
+});
+
+module.exports = Sqlite3Driver;
View
@@ -0,0 +1,113 @@
+
+var persistUtils = require('./persist_utils');
+var Query = require('./query');
+
+var Model = function() {
+
+}
+
+Model.normalizeType = function(typeName) {
+ return typeName; // TODO: all lower case, verify string, etc.
+}
+
+Model.normalizeColumnDef = function(columnDef) {
+ if(typeof(columnDef) == "string") {
+ columnDef = {
+ type: Model.normalizeType(columnDef)
+ };
+ }
+ return columnDef;
+}
+
+Model.define = function(name, columnDefs) {
+ var result = function(values) {
+ var self = this;
+ this._model = result;
+
+ this.save = function(connection, callback) {
+ connection.save(self, callback);
+ };
+
+ this.delete = function(callback) {
+ callback(null, self); // todo: write me
+ }
+
+ for(var column in result.columns) {
+ if(values[column]) {
+ this[column] = values[column];
+ } else {
+ this[column] = null;
+ }
+ }
+ for(var associationName in result.associations) {
+ var association = result.associations[associationName];
+ switch(association.type) {
+ case "hasMany":
+ this[associationName] = []; // todo: define getter setters
+ break;
+ case "hasOne":
+ this[associationName] = null; // todo: define getter setters
+ break;
+ default:
+ throw new Error("Invalid association type '" + association.type + "'");
+ }
+ }
+ };
+
+ result.addColumn = function(propertyName, columnDef) {
+ var col = Model.normalizeColumnDef(columnDef);
+ if(!col.dbColumnName) col.dbColumnName = propertyName;
+ this.columns[propertyName] = col;
+ };
+
+ result.getIdPropertyName = function() {
+ for(var name in this.columns) {
+ if(this.columns[name].primaryKey) {
+ return name;
+ }
+ }
+ return null;
+ }
+
+ result.hasMany = function(model) {
+ var name = persistUtils.toPropertyName(persistUtils.pluralize(model.modelName));
+ this.associations[name] = { type: "hasMany", model: model };
+
+ name = persistUtils.toPropertyName(this.modelName);
+ if(!model.associations[name]) {
+ model.associations[name] = { type: "hasOne", model: this };
+ }
+
+ return this;
+ };
+
+ result.hasOne = function(model) {
+ var name = persistUtils.toPropertyName(model.modelName);
+ this.associations[name] = { type: "hasOne", model: model };
+
+ name = persistUtils.toPropertyName(persistUtils.pluralize(this.modelName));
+ if(!model.associations[name]) {
+ model.associations[name] = { type: "hasMany", model: this };
+ }
+
+ return this;
+ };
+
+ result.using = function(connection) {
+ return new Query(connection, result);
+ };
+
+ result.modelName = name;
+ result.associations = {};
+ result.columns = {};
+ for(var propertyName in columnDefs) {
+ result.addColumn(propertyName, columnDefs[propertyName]);
+ }
+
+ // todo: only add if they haven't defined one yet
+ result.addColumn("id", { type: "integer", primaryKey: true, autoIncrement: true });
+
+ return result;
+}
+
+module.exports = Model;
View
@@ -1,24 +1,14 @@
+var util = require('util');
+var Model = require('./model');
-exports.define = function() {
- var result = function() {
- this.save = function(conn, callback) { callback(null, {}); };
- };
-
- result.all = function(callback) { callback(null, []); };
- result.hasMany = function() { return this; };
- result.hasOne = function() { return this; };
-
- return result;
+exports.define = function(name, columnDefs) {
+ return Model.define(name, columnDefs);
}
exports.connect = function(opts, callback) {
- callback({
- tx: function(callback) {
- callback(null, {
- commit: function(callback) { callback(); },
- rollback: function(callback) { callback(); }
- });
- }
- });
-}
+ var driverName = opts.driver;
+ var Driver = require('./drivers/' + driverName + '.js');
+ var driver = new Driver();
+ driver.connect(opts, callback);
+}
View
@@ -0,0 +1,72 @@
+
+exports.pluralize = function(str) {
+ return str + 's'; // TODO: we can do better
+}
+
+exports.toPropertyName = function(str) {
+ return str.charAt(0).toLowerCase() + str.substring(1);
+}
+
+/* Simple JavaScript Inheritance
+ * By John Resig http://ejohn.org/
+ * MIT Licensed.
+ */
+// Inspired by base2 and Prototype
+var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
+
+// The base Class implementation (does nothing)
+exports.Class = function(){};
+
+// Create a new Class that inherits from this class
+exports.Class.extend = function(prop) {
+ var _super = this.prototype;
+
+ // Instantiate a base class (but only create the instance,
+ // don't run the init constructor)
+ initializing = true;
+ var prototype = new this();
+ initializing = false;
+
+ // Copy the properties over onto the new prototype
+ for (var name in prop) {
+ // Check if we're overwriting an existing function
+ prototype[name] = typeof prop[name] == "function" &&
+ typeof _super[name] == "function" && fnTest.test(prop[name]) ?
+ (function(name, fn){
+ return function() {
+ var tmp = this._super;
+
+ // Add a new ._super() method that is the same method
+ // but on the super-class
+ this._super = _super[name];
+
+ // The method only need to be bound temporarily, so we
+ // remove it when we're done executing
+ var ret = fn.apply(this, arguments);
+ this._super = tmp;
+
+ return ret;
+ };
+ })(name, prop[name]) :
+ prop[name];
+ }
+
+ // The dummy class constructor
+ function Class() {
+ // All construction is actually done in the init method
+ if ( !initializing && this.init )
+ this.init.apply(this, arguments);
+ }
+
+ // Populate our constructed prototype object
+ Class.prototype = prototype;
+
+ // Enforce the constructor to be what we expect
+ Class.prototype.constructor = Class;
+
+ // And make this class extendable
+ Class.extend = arguments.callee;
+
+ return Class;
+};
+
View
@@ -0,0 +1,14 @@
+
+var Query = function() {
+
+}
+
+Query.prototype.all = function(callback) {
+ callback(null, []); // todo: write me
+}
+
+Query.prototype.deleteAll = function(callback) {
+ callback(null, null); // todo: write me
+}
+
+module.exports = Query;
View
@@ -0,0 +1,14 @@
+
+var Transaction = function(connection) {
+ this.connection = connection;
+}
+
+Transaction.prototype.commit = function(callback) {
+ callback(); // todo: write me
+}
+
+Transaction.prototype.rollback = function(callback) {
+ callback(); // todo: write me
+}
+
+module.exports = Transaction;
Oops, something went wrong.

0 comments on commit 42604c2

Please sign in to comment.