From e8c6f683532034e397b9b934eec80160f3d13ebf Mon Sep 17 00:00:00 2001 From: Anatoliy Chakkaev Date: Mon, 20 Feb 2012 22:33:11 +0400 Subject: [PATCH] Add schema.isActual and automigrate on sqlite start --- lib/abstract-class.js | 1 + lib/adapters/mysql.js | 40 ++++++++++++++++++++++++++++++++++---- lib/adapters/sqlite3.js | 6 +++++- lib/schema.js | 12 ++++++++++++ lib/utils.js | 4 ++-- test/common_test.js | 14 +++++++++++++ test/migration_test.coffee | 19 +++++++++++++----- 7 files changed, 84 insertions(+), 12 deletions(-) diff --git a/lib/abstract-class.js b/lib/abstract-class.js index d5bc85c4..599b4dbb 100644 --- a/lib/abstract-class.js +++ b/lib/abstract-class.js @@ -179,6 +179,7 @@ AbstractClass.find = function find(id, cb) { substractDirtyAttributes(obj, data); this.call(obj, data); } else { + data.id = id; obj = new this(data); this.cache[data.id] = obj; } diff --git a/lib/adapters/mysql.js b/lib/adapters/mysql.js index 5f66b195..f4517bcc 100644 --- a/lib/adapters/mysql.js +++ b/lib/adapters/mysql.js @@ -306,7 +306,11 @@ MySQL.prototype.autoupdate = function (cb) { Object.keys(this._models).forEach(function (model) { wait += 1; self.query('SHOW FIELDS FROM ' + model, function (err, fields) { - self.alterTable(model, fields, done); + if (!err && fields.length) { + self.alterTable(model, fields, done); + } else { + self.createTable(model, done); + } }); }); @@ -320,10 +324,34 @@ MySQL.prototype.autoupdate = function (cb) { } }; -MySQL.prototype.alterTable = function (model, actualFields, done) { +MySQL.prototype.isActual = function (cb) { + var ok = false; + var self = this; + var wait = 0; + Object.keys(this._models).forEach(function (model) { + wait += 1; + self.query('SHOW FIELDS FROM ' + model, function (err, fields) { + self.alterTable(model, fields, done, true); + }); + }); + + function done(err, needAlter) { + if (err) { + console.log(err); + } + ok = ok || needAlter; + if (--wait === 0 && cb) { + cb(null, !ok); + } + } +}; + +MySQL.prototype.alterTable = function (model, actualFields, done, checkOnly) { var self = this; var m = this._models[model]; - var propNames = Object.keys(m.properties); + var propNames = Object.keys(m.properties).filter(function (name) { + return !!m.properties[name]; + }); var sql = []; // change/add new fields @@ -352,7 +380,11 @@ MySQL.prototype.alterTable = function (model, actualFields, done) { }); if (sql.length) { - this.query('ALTER TABLE `' + model + '` ' + sql.join(',\n'), done); + if (checkOnly) { + done(null, true); + } else { + this.query('ALTER TABLE `' + model + '` ' + sql.join(',\n'), done); + } } else { done(); } diff --git a/lib/adapters/sqlite3.js b/lib/adapters/sqlite3.js index c5edf2bc..2d80882b 100644 --- a/lib/adapters/sqlite3.js +++ b/lib/adapters/sqlite3.js @@ -14,7 +14,11 @@ exports.initialize = function initializeSchema(schema, callback) { schema.client = db; schema.adapter = new SQLite3(schema.client); - process.nextTick(callback); + if (s.database === ':memory:') { + schema.adapter.automigrate(callback); + } else { + process.nextTick(callback); + } }; function SQLite3(client) { diff --git a/lib/schema.js b/lib/schema.js index 124cba32..f2a858f9 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -100,6 +100,18 @@ Schema.prototype.autoupdate = function (cb) { } }; +/** + * Check whether migrations needed + */ +Schema.prototype.isActual = function (cb) { + this.freeze(); + if (this.adapter.isActual) { + this.adapter.isActual(cb); + } else if (cb) { + cb(null, true); + } +}; + Schema.prototype.log = function (sql, t) { this.emit('log', sql, t); }; diff --git a/lib/utils.js b/lib/utils.js index ba4729ee..e867265b 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -4,8 +4,8 @@ function safeRequire(module) { try { return require(module); } catch (e) { - console.log('Run "npm install ' + module + '" command to use jugglingdb using this database'); - return false + console.log('Run "npm install ' + module + '" command to use jugglingdb using this database engine'); + process.exit(1); } } diff --git a/test/common_test.js b/test/common_test.js index 2032e803..fb5305c4 100644 --- a/test/common_test.js +++ b/test/common_test.js @@ -584,6 +584,20 @@ function testOrm(schema) { } }); + it('should return id in find result even after updateAttributes', function (test) { + Post.create(function (err, post) { + var id = post.id; + test.ok(post.published === false); + post.updateAttributes({title: 'hey', published: true}, function () { + Post.find(id, function (err, post) { + test.ok(post.published === true); + test.ok(post.id); + test.done(); + }); + }); + }); + }); + it('all tests done', function (test) { test.done(); process.nextTick(allTestsDone); diff --git a/test/migration_test.coffee b/test/migration_test.coffee index 9bf25532..65f618a5 100644 --- a/test/migration_test.coffee +++ b/test/migration_test.coffee @@ -119,21 +119,30 @@ it 'should autoupgrade', (test) -> schema.autoupdate (err) -> getFields 'User', (err, fields) -> # change nullable for email - test.equal fields.email.Null, 'YES' + test.equal fields.email.Null, 'YES', 'Email is not null' # change type of name - test.equal fields.name.Type, 'varchar(50)' + test.equal fields.name.Type, 'varchar(50)', 'Name is not varchar(50)' # add new column - test.ok fields.newProperty + test.ok fields.newProperty, 'New column was not added' if fields.newProperty - test.equal fields.newProperty.Type, 'int(11)' + test.equal fields.newProperty.Type, 'int(11)', 'New column type is not int(11)' # drop column - test.ok not fields.pendingPeriod + test.ok not fields.pendingPeriod, 'drop column' # user still exists userExists (yep) -> test.ok yep test.done() +it 'should check actuality of schema', (test) -> + # drop column + User.schema.isActual (err, ok) -> + test.ok ok + User.defineProperty 'email', false + User.schema.isActual (err, ok) -> + test.ok not ok + test.done() + it 'should disconnect when done', (test) -> schema.disconnect() test.done()