不要怂,就是干,撸起袖子干!

You need to sign in or sign up before continuing.
Commit f2d62129 by Jan Aagaard Meier

Moved the sequelize promise code to a fork of bluebird, and made small changes t…

…o the bulkCraete promise code
1 parent 387abfa7
......@@ -32,3 +32,14 @@ branches:
cache:
directories:
- node_modules
matrix:
fast_finish: true
include:
- node_js: "0.12"
env: DB=mysql DIALECT=mysql
allow_failures:
- node_js: "0.12"
env: DB=mysql DIALECT=mysql
\ No newline at end of file
......@@ -960,6 +960,7 @@ module.exports = (function() {
* @deprecated The syntax is due for change, in order to make `where` more consistent with the rest of the API
*
* @return {Promise}
* @return {EventEmitter}
* @method
* @alias findOrBuild
*/
......@@ -1044,8 +1045,9 @@ module.exports = (function() {
/**
* Create and insert multiple instances in bulk.
*
* The success handler is not passed any arguments. To obtain DAOs for the newly created values, you will need to query for them again.
* This is because MySQL and SQLite do not make it easy to obtain back automatically generated IDs and other default values in a way that can be mapped to multiple records.
* The success handler is passed an array of instances, but please notice that these may not completely represent the state of the rows in the DB. This is because MySQL
* and SQLite do not make it easy to obtain back automatically generated IDs and other default values in a way that can be mapped to multiple records.
* To obtain DAOs for the newly created values, you will need to query for them again.
*
* @param {Array} records List of objects (key/value pairs) to create instances from
* @param {Object} [options]
......@@ -1075,7 +1077,7 @@ module.exports = (function() {
if (fieldsOrOptions instanceof Array) {
options.fields = fieldsOrOptions
} else {
options.fields = options.fields || []
options.fields = options.fields || Object.keys(this.attributes)
options = Utils._.extend(options, fieldsOrOptions)
}
......@@ -1098,16 +1100,13 @@ module.exports = (function() {
var skippedFields = Utils._.difference(Object.keys(self.attributes), options.fields);
}
var done = function() {
return self.runHooks('afterBulkCreate', daos, options.fields).then(function(newRecords, newFields) {
daos = newRecords || daos
options.fields = newFields || options.fields
return new self.sequelize.Promise.resolve(daos, options.fields)
var runAfterCreate = function() {
return self.runHooks('afterBulkCreate', daos, options.fields).spread(function(newRecords) {
return new self.sequelize.Promise.resolve(newRecords || daos)
})
}
return self.runHooks('beforeBulkCreate', daos, options.fields).then(function(newRecords, newFields) {
return self.runHooks('beforeBulkCreate', daos, options.fields).spread(function(newRecords, newFields) {
daos = newRecords || daos
options.fields = newFields || options.fields
......@@ -1132,7 +1131,7 @@ module.exports = (function() {
return values
}
return self.runHooks('beforeCreate', dao).then(function(newValues) {
return self.runHooks('beforeCreate', dao).spread(function(newValues) {
dao = newValues || dao
return dao.save({ transaction: options.transaction }).then(function() {
return self.runHooks('afterCreate', dao)
......@@ -1165,10 +1164,10 @@ module.exports = (function() {
return self.sequelize.Promise.reject(errors)
} else if (records.length) {
// Insert all records at once
return self.QueryInterface.bulkInsert(self.getTableName(), records, options, self).then(done)
return self.QueryInterface.bulkInsert(self.getTableName(), records, options, self).then(runAfterCreate)
} else {
// Records were already saved while running create / update hooks
return done()
return runAfterCreate()
}
})
})
......
......@@ -172,7 +172,7 @@ DaoValidator.prototype.hookValidate = function() {
}
});
}).then(function () {
return self.modelInstance.Model.runHooks('afterValidate', self.modelInstance);
return self.modelInstance.Model.runHooks('afterValidate', self.modelInstance)
}).return(self.modelInstance);
}
......
......@@ -61,7 +61,8 @@ Hooks.runHooks = function() {
, hooks = arguments[0]
, lastIndex = arguments.length-1
, fn = typeof arguments[lastIndex] === "function" ? arguments[lastIndex] : null
, args = Array.prototype.slice.call(arguments, 1, fn ? lastIndex : arguments.length)
, fnArgs = Array.prototype.slice.call(arguments, 1, fn ? lastIndex : arguments.length)
, resolveArgs = fnArgs
if (typeof hooks === "string") {
hooks = this.options.hooks[hooks] || []
......@@ -71,38 +72,42 @@ Hooks.runHooks = function() {
hooks = hooks === undefined ? [] : [hooks]
}
return new Promise(function (resolve, reject) {
var promise = new Promise(function (resolve, reject) {
if (hooks.length < 1) {
return resolve(args)
return resolve(fnArgs)
}
var run = function(hook) {
if (!hook) {
return resolve(args)
return resolve(resolveArgs)
}
if (typeof hook === "object") {
hook = hook.fn
}
hook.apply(self, args.concat(function() {
hook.apply(self, fnArgs.concat(function() {
tick++
if (!!arguments[0]) {
return reject(arguments[0])
}
resolveArgs = Array.prototype.slice.call(arguments, 1)
// daoValues = newValues
return run(hooks[tick])
}))
}
run(hooks[tick])
}).spread(function () {
})
if (fn) {
promise.spread(function () {
fn.apply(self, [null].concat(Array.prototype.slice.apply(arguments)));
}
}, fn);
}
return promise
}
Hooks.hook = function() {
......
......@@ -3,8 +3,6 @@ var util = require("util")
, EventEmitter = require("events").EventEmitter
, proxyEventKeys = ['success', 'error', 'sql']
, Utils = require('./utils')
, INTERNAL = function() {}
, async = require("bluebird/js/main/async.js")
/**
* A slightly modified version of bluebird promises. This means that, on top of the methods below, you can also call all the methods listed on the link below.
......@@ -14,215 +12,7 @@ var util = require("util")
* @mixes https://github.com/petkaantonov/bluebird/blob/master/API.md
* @class Promise
*/
var SequelizePromise = function(resolver) {
var self = this;
// Copied from Bluebird, bluebird doesn't like Promise.call(this)
// mhansen wrote and is no fan of this, but sees no other way of making Promises first class while preserving SQL logging capabilities and BC.
this._bitField = 0;
this._fulfillmentHandler0 = void 0;
this._rejectionHandler0 = void 0;
this._promise0 = void 0;
this._receiver0 = void 0;
this._settledValue = void 0;
this._boundTo = void 0;
// Intercept the resolver so we can resolve with emit's
this._resolveFromResolver(function resolverIntercept(resolve, reject) {
self.seqResolve = resolve;
self.seqReject = reject;
if (resolver) {
resolver.apply(this, arguments);
}
}.bind(this));
// Sequelize speific
this.$sql = [];
};
Promise = require("bluebird")
util.inherits(SequelizePromise, Promise)
Utils._.extend(SequelizePromise, Promise)
SequelizePromise.is = function (obj) {
if (obj === void 0) return false;
return obj instanceof Promise || obj instanceof SequelizePromise;
}
SequelizePromise.all = function(promises) {
var resolved = SequelizePromise.resolve(Promise.all(promises));
// Propagate sql events
promises.forEach(function (promise) {
if (SequelizePromise.is(promise)) {
promise.on('sql', function (sql) {
resolved.emit('sql', sql);
});
promise.$sql.forEach(function (sql) {
resolved.emit('sql', sql);
});
}
});
return resolved;
};
SequelizePromise.settle = function (promises) {
var settled = SequelizePromise.resolve(Promise.settle(promises))
// Propagate sql events
promises.forEach(function (promise) {
if (SequelizePromise.is(promise)) {
promise.on('sql', function (sql) {
settled.emit('sql', sql);
});
promise.$sql.forEach(function (sql) {
settled.emit('sql', sql);
});
}
});
return settled;
}
SequelizePromise.method = function (fn) {
return function Promise$_method() {
var value = tryCatchApply(fn, Array.prototype.slice.apply(arguments), this);
var ret = new SequelizePromise(INTERNAL);
ret._setTrace(void 0);
ret._resolveFromSyncValue(value);
return ret;
};
};
SequelizePromise.prototype._resolveFromSyncValue = function(value) {
if (value && value.hasOwnProperty('e')) {
this._cleanValues();
this._setRejected();
this._settledValue = value.e;
this._ensurePossibleRejectionHandled();
}
else {
var maybePromise = Promise._cast(value, void 0);
if (maybePromise instanceof Promise || maybePromise instanceof SequelizePromise) {
this._follow(maybePromise);
}
else {
this._cleanValues();
this._setFulfilled();
this._settledValue = value;
}
}
};
SequelizePromise.attempt = SequelizePromise.try = function (fn, args, ctx) {
var value = tryCatchApply(fn, args, ctx)
var ret = new SequelizePromise(INTERNAL);
ret._setTrace(void 0);
ret._resolveFromSyncValue(value);
return ret;
};
// Need to hack resolve cause we can't hack all directrly
SequelizePromise.resolve = SequelizePromise.fulfilled = function(value) {
var ret = new SequelizePromise(INTERNAL);
if (ret._tryFollow(value)) {
return ret;
}
ret._cleanValues();
ret._setFulfilled();
ret._settledValue = value;
return ret;
};
SequelizePromise.promisify = function (callback, receiver) {
function promisified() {
var _receiver = receiver;
var promise = new SequelizePromise(INTERNAL);
promise._setTrace(void 0);
var fn = function PromiseResolver$_callback(err, value) {
if (err) {
var wrapped = maybeWrapAsError(err);
promise._attachExtraTrace(wrapped);
promise._reject(wrapped);
}
else {
if (arguments.length > 2) {
promise._fulfill(Array.prototype.slice.call(arguments, 1));
}
else {
promise._fulfill(value);
}
}
}
try {
callback.apply(_receiver, withAppended(arguments, fn));
}
catch(e) {
var wrapped = maybeWrapAsError(e);
promise._attachExtraTrace(wrapped);
promise._reject(wrapped);
}
return promise;
}
promisified.__isPromisified__ = true;
return promisified;
}
// Need to hack _then to make sure our promise is chainable
SequelizePromise.prototype._then = function (
didFulfill,
didReject,
didProgress,
receiver,
internalData
) {
var haveInternalData = internalData !== void 0;
var ret = haveInternalData ? internalData : new SequelizePromise(INTERNAL); // The relevant line, rest is fine
if (!haveInternalData && this._isBound()) {
ret._setBoundTo(this._boundTo);
}
// Start of sequelize specific
// Needed to transfer sql events accross .then() calls
if (this.proxySql && ret && ret.emit) {
this.proxySql(ret);
}
// End of sequelize specific
var callbackIndex = this._addCallbacks(didFulfill, didReject, didProgress, ret, receiver);
if (!haveInternalData && this._cancellable()) {
ret._setCancellable();
ret._cancellationParent = this;
}
if (this.isResolved()) {
async.invoke(this._queueSettleAt, this, callbackIndex);
}
return ret;
};
SequelizePromise.prototype._settlePromiseAt = function (index) {
var receiver = this._receiverAt(index);
if (this.$sql && receiver && receiver.emit) {
this.$sql.forEach(function (sql) {
receiver.emit('sql', sql);
});
}
return Promise.prototype._settlePromiseAt.apply(this, arguments);
};
var SequelizePromise = Promise = require('bluebird')
/**
* Listen for events, event emitter style. Mostly for backwards compat. with EventEmitter
......@@ -381,41 +171,4 @@ SequelizePromise.prototype.proxySql = function(promise) {
});
};
// Utility methods
function withAppended(target, appendee) {
var len = target.length;
var ret = new Array(len + 1);
var i;
for (i = 0; i < len; ++i) {
ret[i] = target[i];
}
ret[i] = appendee;
return ret;
}
function isPrimitive(val) {
return val == null || val === true || val === false ||
typeof val === "string" || typeof val === "number";
}
function maybeWrapAsError(maybeError) {
if (!isPrimitive(maybeError)) return maybeError;
return new Error(asString(maybeError));
}
function tryCatchApply(fn, args, receiver) {
try {
return fn.apply(receiver, args);
}
catch (e) {
return {e: e};
}
}
function asString(val) {
return typeof val === "string" ? val : ("" + val);
}
module.exports = SequelizePromise;
\ No newline at end of file
......@@ -51,7 +51,7 @@
"generic-pool": "2.0.4",
"sql": "~0.35.0",
"circular-json": "~0.1.5",
"bluebird": "~1.0.0",
"bluebird": "git://github.com/sequelize/bluebird.git",
"node-uuid": "~1.4.1"
},
"devDependencies": {
......
......@@ -945,7 +945,7 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
self.Task.create({ id: 15, title: 'task2' }).success(function(task2) {
user.setTasks([task1, task2]).on('sql', spy).on('sql', _.after(2, function (sql) {
var tickChar = (Support.getTestDialect() === 'postgres') ? '"' : '`'
expect(sql).to.have.string("INSERT INTO %TasksUsers% (%UserId%,%TaskId%) VALUES (1,12),(1,15)".replace(/%/g, tickChar))
expect(sql).to.have.string("INSERT INTO %TasksUsers% (%TaskId%,%UserId%) VALUES (12,1),(15,1)".replace(/%/g, tickChar))
})).success(function () {
expect(spy.calledTwice).to.be.ok // Once for SELECT, once for INSERT
done()
......
......@@ -119,6 +119,24 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
})
})
})
it('can modify fields', function () {
var self = this
this.User.beforeBulkCreate(function (daos, fields, fn) {
fn(null, daos, ['username'])
})
return this.User.bulkCreate([
{username: 'Bob', mood: 'cold'},
{username: 'Tobi', mood: 'hot'}
], { fields: [], hooks: false }).success(function(bulkUsers) {
return self.User.all().success(function(users) {
expect(users[0].mood).to.equal(null)
expect(users[1].mood).to.equal(null)
})
})
})
})
it('#create', function(done) {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!