Merge transactions
This commit is contained in:
commit
4943feb230
8
Makefile
8
Makefile
|
@ -56,20 +56,22 @@ about-docs:
|
||||||
GITBRANCH = $(shell git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
|
GITBRANCH = $(shell git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
|
||||||
|
|
||||||
REPO = marcusgreenwood/hatchjs
|
REPO = marcusgreenwood/hatchjs
|
||||||
|
TARGET = origin
|
||||||
FROM = $(GITBRANCH)
|
FROM = $(GITBRANCH)
|
||||||
TO = $(GITBRANCH)
|
TO = $(GITBRANCH)
|
||||||
|
|
||||||
pull:
|
pull:
|
||||||
git pull origin $(FROM)
|
git pull $(TARGET) $(FROM)
|
||||||
|
|
||||||
safe-pull:
|
safe-pull:
|
||||||
git pull origin $(FROM) --no-commit
|
git pull $(TARGET) $(FROM) --no-commit
|
||||||
|
|
||||||
push: test
|
push: test
|
||||||
git push origin $(TO)
|
git push $(TARGET) $(TO)
|
||||||
|
|
||||||
feature:
|
feature:
|
||||||
git checkout -b feature-$(filter-out $@,$(MAKECMDGOALS))
|
git checkout -b feature-$(filter-out $@,$(MAKECMDGOALS))
|
||||||
|
git push -u $(TARGET) feature-$(filter-out $@,$(MAKECMDGOALS))
|
||||||
%:
|
%:
|
||||||
@:
|
@:
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ jugglingdb-roadmap - The Future of JugglingDB
|
||||||
|
|
||||||
## MODEL CORE
|
## MODEL CORE
|
||||||
|
|
||||||
|
* schema switching
|
||||||
|
* common transaction support
|
||||||
* virtual attributes
|
* virtual attributes
|
||||||
* object presentation modes
|
* object presentation modes
|
||||||
* mass-assignment protection
|
* mass-assignment protection
|
||||||
|
|
|
@ -1,14 +1,30 @@
|
||||||
exports.initialize = function initializeSchema(schema, callback) {
|
exports.initialize = function initializeSchema(schema, callback) {
|
||||||
schema.adapter = new Memory();
|
schema.adapter = new Memory();
|
||||||
process.nextTick(callback);
|
schema.adapter.connect(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
function Memory() {
|
function Memory(m) {
|
||||||
this._models = {};
|
if (m) {
|
||||||
|
this.isTransaction = true;
|
||||||
|
this.cache = m.cache;
|
||||||
|
this.ids = m.ids;
|
||||||
|
this._models = m._models;
|
||||||
|
} else {
|
||||||
|
this.isTransaction = false;
|
||||||
this.cache = {};
|
this.cache = {};
|
||||||
this.ids = {};
|
this.ids = {};
|
||||||
|
this._models = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Memory.prototype.connect = function(callback) {
|
||||||
|
if (this.isTransaction) {
|
||||||
|
this.onTransactionExec = callback;
|
||||||
|
} else {
|
||||||
|
process.nextTick(callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Memory.prototype.define = function defineModel(descr) {
|
Memory.prototype.define = function defineModel(descr) {
|
||||||
var m = descr.model.modelName;
|
var m = descr.model.modelName;
|
||||||
this._models[m] = descr;
|
this._models[m] = descr;
|
||||||
|
@ -20,7 +36,7 @@ Memory.prototype.create = function create(model, data, callback) {
|
||||||
var id = data.id || this.ids[model]++;
|
var id = data.id || this.ids[model]++;
|
||||||
data.id = id;
|
data.id = id;
|
||||||
this.cache[model][id] = JSON.stringify(data);
|
this.cache[model][id] = JSON.stringify(data);
|
||||||
process.nextTick(function () {
|
process.nextTick(function() {
|
||||||
callback(null, id);
|
callback(null, id);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -185,6 +201,15 @@ Memory.prototype.updateAttributes = function updateAttributes(model, id, data, c
|
||||||
this.save(model, merge(base, data), cb);
|
this.save(model, merge(base, data), cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Memory.prototype.transaction = function () {
|
||||||
|
return new Memory(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
Memory.prototype.exec = function(callback) {
|
||||||
|
this.onTransactionExec();
|
||||||
|
setTimeout(callback, 50);
|
||||||
|
};
|
||||||
|
|
||||||
function merge(base, update) {
|
function merge(base, update) {
|
||||||
if (!base) return update;
|
if (!base) return update;
|
||||||
Object.keys(update).forEach(function (key) {
|
Object.keys(update).forEach(function (key) {
|
||||||
|
|
23
lib/model.js
23
lib/model.js
|
@ -174,23 +174,29 @@ AbstractClass.create = function (data, callback) {
|
||||||
callback = function () {};
|
callback = function () {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
data = {};
|
||||||
|
}
|
||||||
|
|
||||||
if (data instanceof Array) {
|
if (data instanceof Array) {
|
||||||
var instances = [];
|
var instances = [];
|
||||||
var errors = new Array(data.length);
|
var errors = Array(data.length);
|
||||||
var gotError = false;
|
var gotError = false;
|
||||||
var wait = data.length;
|
var wait = data.length;
|
||||||
if (wait === 0) callback(null, []);
|
if (wait === 0) callback(null, []);
|
||||||
|
|
||||||
var instances = data.map(function(d, i) {
|
var instances = [];
|
||||||
return Model.create(d, function(err, inst) {
|
for (var i = 0; i < data.length; i += 1) {
|
||||||
// console.log('got', i, err, inst, inst.errors);
|
(function(d, i) {
|
||||||
|
instances.push(Model.create(d, function(err, inst) {
|
||||||
if (err) {
|
if (err) {
|
||||||
errors[i] = err;
|
errors[i] = err;
|
||||||
gotError = true;
|
gotError = true;
|
||||||
}
|
}
|
||||||
modelCreated();
|
modelCreated();
|
||||||
});
|
}));
|
||||||
});
|
})(data[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
return instances;
|
return instances;
|
||||||
|
|
||||||
|
@ -252,6 +258,9 @@ AbstractClass.create = function (data, callback) {
|
||||||
|
|
||||||
function stillConnecting(schema, obj, args) {
|
function stillConnecting(schema, obj, args) {
|
||||||
if (schema.connected) return false;
|
if (schema.connected) return false;
|
||||||
|
if (!schema.connecting) {
|
||||||
|
schema.connect();
|
||||||
|
}
|
||||||
var method = args.callee;
|
var method = args.callee;
|
||||||
schema.on('connected', function () {
|
schema.on('connected', function () {
|
||||||
method.apply(obj, [].slice.call(args));
|
method.apply(obj, [].slice.call(args));
|
||||||
|
@ -697,7 +706,7 @@ AbstractClass.prototype.isNewRecord = function () {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
AbstractClass.prototype._adapter = function () {
|
AbstractClass.prototype._adapter = function () {
|
||||||
return this.constructor.schema.adapter;
|
return this.schema.adapter;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* Module dependencies
|
* Module dependencies
|
||||||
*/
|
*/
|
||||||
var AbstractClass = require('./model.js').AbstractClass;
|
var AbstractClass = require('./model.js').AbstractClass;
|
||||||
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
@ -65,6 +66,7 @@ function Schema(name, settings) {
|
||||||
|
|
||||||
// Disconnected by default
|
// Disconnected by default
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
|
this.connecting = true;
|
||||||
|
|
||||||
// create blank models pool
|
// create blank models pool
|
||||||
this.models = {};
|
this.models = {};
|
||||||
|
@ -115,9 +117,24 @@ function Schema(name, settings) {
|
||||||
this.emit('connected');
|
this.emit('connected');
|
||||||
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
|
schema.connect = function(cb) {
|
||||||
|
var schema = this;
|
||||||
|
schema.connecting = true;
|
||||||
|
schema.adapter.connect(function(err) {
|
||||||
|
if (!err) {
|
||||||
|
schema.connected = true;
|
||||||
|
schema.connecting = false;
|
||||||
|
schema.emit('connected');
|
||||||
|
}
|
||||||
|
if (cb) {
|
||||||
|
cb(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
util.inherits(Schema, require('events').EventEmitter);
|
util.inherits(Schema, EventEmitter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define class
|
* Define class
|
||||||
|
@ -160,20 +177,17 @@ Schema.prototype.define = function defineClass(className, properties, settings)
|
||||||
|
|
||||||
settings = settings || {};
|
settings = settings || {};
|
||||||
|
|
||||||
standartize(properties, settings);
|
|
||||||
|
|
||||||
// every class can receive hash of data as optional param
|
// every class can receive hash of data as optional param
|
||||||
var NewClass = function ModelConstructor(data) {
|
var NewClass = function ModelConstructor(data, schema) {
|
||||||
if (!(this instanceof ModelConstructor)) {
|
if (!(this instanceof ModelConstructor)) {
|
||||||
return new ModelConstructor(data);
|
return new ModelConstructor(data);
|
||||||
}
|
}
|
||||||
AbstractClass.call(this, data);
|
AbstractClass.call(this, data);
|
||||||
|
this.schema = schema || this.constructor.schema;
|
||||||
};
|
};
|
||||||
|
|
||||||
hiddenProperty(NewClass, 'schema', schema);
|
hiddenProperty(NewClass, 'schema', schema);
|
||||||
hiddenProperty(NewClass, 'modelName', className);
|
hiddenProperty(NewClass, 'modelName', className);
|
||||||
hiddenProperty(NewClass, 'cache', {});
|
|
||||||
hiddenProperty(NewClass, 'mru', []);
|
|
||||||
hiddenProperty(NewClass, 'relations', {});
|
hiddenProperty(NewClass, 'relations', {});
|
||||||
|
|
||||||
// inherit AbstractClass methods
|
// inherit AbstractClass methods
|
||||||
|
@ -187,6 +201,8 @@ Schema.prototype.define = function defineClass(className, properties, settings)
|
||||||
NewClass.getter = {};
|
NewClass.getter = {};
|
||||||
NewClass.setter = {};
|
NewClass.setter = {};
|
||||||
|
|
||||||
|
standartize(properties, settings);
|
||||||
|
|
||||||
// store class in model pool
|
// store class in model pool
|
||||||
this.models[className] = NewClass;
|
this.models[className] = NewClass;
|
||||||
this.definitions[className] = {
|
this.definitions[className] = {
|
||||||
|
@ -194,7 +210,7 @@ Schema.prototype.define = function defineClass(className, properties, settings)
|
||||||
settings: settings
|
settings: settings
|
||||||
};
|
};
|
||||||
|
|
||||||
// pass controll to adapter
|
// pass control to adapter
|
||||||
this.adapter.define({
|
this.adapter.define({
|
||||||
model: NewClass,
|
model: NewClass,
|
||||||
properties: properties,
|
properties: properties,
|
||||||
|
@ -251,7 +267,6 @@ Schema.prototype.define = function defineClass(className, properties, settings)
|
||||||
|
|
||||||
return NewClass;
|
return NewClass;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function standartize(properties, settings) {
|
function standartize(properties, settings) {
|
||||||
|
@ -269,6 +284,7 @@ Schema.prototype.define = function defineClass(className, properties, settings)
|
||||||
// or {timestamps: {created: 'created_at', updated: false}}
|
// or {timestamps: {created: 'created_at', updated: false}}
|
||||||
// by default property names: createdAt, updatedAt
|
// by default property names: createdAt, updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define single property named `prop` on `model`
|
* Define single property named `prop` on `model`
|
||||||
*
|
*
|
||||||
|
@ -416,6 +432,73 @@ Schema.prototype.disconnect = function disconnect(cb) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Schema.prototype.copyModel = function copyModel(Master) {
|
||||||
|
var schema = this;
|
||||||
|
var className = Master.modelName;
|
||||||
|
var md = Master.schema.definitions[className];
|
||||||
|
var Slave = function SlaveModel() {
|
||||||
|
Master.apply(this, [].slice.call(arguments));
|
||||||
|
this.schema = schema;
|
||||||
|
};
|
||||||
|
|
||||||
|
util.inherits(Slave, Master);
|
||||||
|
|
||||||
|
Slave.__proto__ = Master;
|
||||||
|
|
||||||
|
hiddenProperty(Slave, 'schema', schema);
|
||||||
|
hiddenProperty(Slave, 'modelName', className);
|
||||||
|
hiddenProperty(Slave, 'relations', Master.relations);
|
||||||
|
|
||||||
|
if (!(className in schema.models)) {
|
||||||
|
|
||||||
|
// store class in model pool
|
||||||
|
schema.models[className] = Slave;
|
||||||
|
schema.definitions[className] = {
|
||||||
|
properties: md.properties,
|
||||||
|
settings: md.settings
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!schema.isTransaction) {
|
||||||
|
schema.adapter.define({
|
||||||
|
model: Slave,
|
||||||
|
properties: md.properties,
|
||||||
|
settings: md.settings
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return Slave;
|
||||||
|
};
|
||||||
|
|
||||||
|
Schema.prototype.transaction = function() {
|
||||||
|
var schema = this;
|
||||||
|
var transaction = new EventEmitter;
|
||||||
|
transaction.isTransaction = true;
|
||||||
|
transaction.origin = schema;
|
||||||
|
transaction.name = schema.name;
|
||||||
|
transaction.settings = schema.settings;
|
||||||
|
transaction.connected = false;
|
||||||
|
transaction.connecting = false;
|
||||||
|
transaction.adapter = schema.adapter.transaction();
|
||||||
|
|
||||||
|
// create blank models pool
|
||||||
|
transaction.models = {};
|
||||||
|
transaction.definitions = {};
|
||||||
|
|
||||||
|
for (var i in schema.models) {
|
||||||
|
schema.copyModel.call(transaction, schema.models[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.connect = schema.connect;
|
||||||
|
|
||||||
|
transaction.exec = function(cb) {
|
||||||
|
transaction.adapter.exec(cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
return transaction;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define hidden property
|
* Define hidden property
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
var db = getSchema(), slave = getSchema(), Model, SlaveModel;
|
var db = getSchema(), slave = getSchema(), Model, SlaveModel;
|
||||||
var should = require('should');
|
var should = require('should');
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
describe.skip('schema', function() {
|
describe.skip('schema', function() {
|
||||||
|
=======
|
||||||
|
describe.only('schema', function() {
|
||||||
|
>>>>>>> feature-transactions
|
||||||
|
|
||||||
it('should define Model', function() {
|
it('should define Model', function() {
|
||||||
Model = db.define('Model');
|
Model = db.define('Model');
|
||||||
|
|
Loading…
Reference in New Issue