Comparing version 2.1.14 to 2.1.15
@@ -0,1 +1,8 @@ | ||
### v2.1.15 - 05 Jun 2014 | ||
- Feature: Enable plugging in custom third-party drivers (now known as adapters) (#512) | ||
- Add Instance.set() so that properties of type object can have their properties set and mark model as dirty (#517) | ||
- Add Instance.markAsDirty(propName) to force a properties state to dirty/changed. | ||
- Enable Property.mapsTo for keys (#509) | ||
- Fix hasMany join tables with custom key columns (#510) | ||
### v2.1.14 - 22 May 2014 | ||
@@ -2,0 +9,0 @@ - Allow explicitly specifying `key: true` on properties rather than passing in an array of ids. |
@@ -47,4 +47,4 @@ var _ = require("lodash"); | ||
mergeId = util.convertPropToJoinKeyProp( | ||
util.wrapFieldObject(opts.mergeId, OtherModel, Model.table, OtherModel.properties) || | ||
util.formatField(OtherModel, Model.table, true, opts.reversed), | ||
util.wrapFieldObject(opts.mergeId, Model, Model.table, Model.properties) || | ||
util.formatField(Model, Model.table, true, opts.reversed), | ||
{ makeKey: makeKey, required: true } | ||
@@ -54,4 +54,4 @@ ); | ||
mergeAssocId = util.convertPropToJoinKeyProp( | ||
util.wrapFieldObject(opts.mergeAssocId, Model, name, Model.properties) || | ||
util.formatField(Model, name, true, opts.reversed), | ||
util.wrapFieldObject(opts.mergeAssocId, OtherModel, name, OtherModel.properties) || | ||
util.formatField(OtherModel, name, true, opts.reversed), | ||
{ makeKey: makeKey, required: true } | ||
@@ -58,0 +58,0 @@ ) |
@@ -93,3 +93,3 @@ var _ = require("lodash"); | ||
remove: function (cb) { | ||
opts.driver.find([ opts.id ], opts.table, opts.conditions, { | ||
opts.driver.find([ opts.keys ], opts.table, opts.conditions, { | ||
limit : opts.limit, | ||
@@ -111,6 +111,2 @@ order : opts.order, | ||
if (!Array.isArray(opts.id)) { | ||
opts.id = [ opts.id ]; | ||
} | ||
conditions.or = []; | ||
@@ -120,4 +116,4 @@ | ||
or = {}; | ||
for (var j = 0; j < opts.id.length; j++) { | ||
or[opts.id[j]] = data[i][opts.id[j]]; | ||
for (var j = 0; j < opts.keys.length; j++) { | ||
or[opts.keys[j]] = data[i][opts.keys[j]]; | ||
} | ||
@@ -216,4 +212,4 @@ conditions.or.push(or); | ||
var ids = _.map(data, function (instance) { | ||
var id = instance[opts.id[0]]; | ||
var keys = _.map(data, function (instance) { | ||
var key = instance[opts.keys[0]]; | ||
// Create the association arrays | ||
@@ -224,8 +220,8 @@ for (var i = 0, association; association = opts.__eager[i]; i++) { | ||
idMap[id] = count++; | ||
return id; | ||
idMap[key] = count++; | ||
return key; | ||
}); | ||
_.map(opts.__eager, function (association) { | ||
opts.driver.eagerQuery(association, opts, ids, function (err, instances) { | ||
opts.driver.eagerQuery(association, opts, keys, function (err, instances) { | ||
for (var i = 0, instance; instance = instances[i]; i++) { | ||
@@ -232,0 +228,0 @@ // Perform a parent lookup with $p, and initialize it as an instance. |
@@ -24,3 +24,3 @@ var _ = require("lodash"); | ||
for (i = 0; i < opts.many_associations.length; i++) { | ||
for (var i = 0; i < opts.many_associations.length; i++) { | ||
props = {}; | ||
@@ -27,0 +27,0 @@ |
@@ -12,3 +12,20 @@ | ||
return this.execSimpleQuery(query, cb); | ||
}, | ||
eagerQuery: function (association, opts, keys, cb) { | ||
var desiredKey = Object.keys(association.field); | ||
var assocKey = Object.keys(association.mergeAssocId); | ||
var where = {}; | ||
where[desiredKey] = keys; | ||
var query = this.query.select() | ||
.from(association.model.table) | ||
.select(opts.only) | ||
.from(association.mergeTable, assocKey, opts.keys) | ||
.select(desiredKey).as("$p") | ||
.where(association.mergeTable, where) | ||
.build(); | ||
this.execSimpleQuery(query, cb); | ||
} | ||
}; |
@@ -188,3 +188,3 @@ var Utilities = require("../../Utilities"); | ||
Driver.prototype.insert = function (table, data, id_prop, cb) { | ||
Driver.prototype.insert = function (table, data, keyProperties, cb) { | ||
convertToDB(data, this.config.timezone); | ||
@@ -200,8 +200,10 @@ | ||
var ids = {}; | ||
var i, ids = {}, prop; | ||
if (id_prop !== null && docs.length) { | ||
for (var k in docs[0]) { | ||
if (id_prop.indexOf(k) >= 0) { | ||
ids[k] = docs[0][k]; | ||
if (keyProperties && docs.length) { | ||
for (i = 0; i < keyProperties.length; i++) { | ||
prop = keyProperties[i]; | ||
if (prop.mapsTo in docs[0]) { | ||
ids[prop.name] = docs[0][prop.mapsTo]; | ||
} | ||
@@ -208,0 +210,0 @@ } |
@@ -136,20 +136,2 @@ var _ = require("lodash"); | ||
Driver.prototype.eagerQuery = function (association, opts, ids, cb) { | ||
var desiredKey = Object.keys(association.field); | ||
var assocKey = Object.keys(association.mergeAssocId); | ||
var where = {}; | ||
where[desiredKey] = ids; | ||
var query = this.query.select() | ||
.from(association.model.table) | ||
.select(opts.only) | ||
.from(association.mergeTable, assocKey, opts.id) | ||
.select(desiredKey).as("$p") | ||
.where(association.mergeTable, where) | ||
.build(); | ||
this.execSimpleQuery(query, cb); | ||
}; | ||
Driver.prototype.count = function (table, conditions, opts, cb) { | ||
@@ -182,3 +164,3 @@ var q = this.query.select() | ||
Driver.prototype.insert = function (table, data, id_prop, cb) { | ||
Driver.prototype.insert = function (table, data, keyProperties, cb) { | ||
var q = this.query.insert() | ||
@@ -192,10 +174,11 @@ .into(table) | ||
var ids = {}; | ||
var i, ids = {}, prop; | ||
if (id_prop !== null) { | ||
if (id_prop.length == 1 && info.hasOwnProperty("insertId") && info.insertId !== 0 ) { | ||
ids[id_prop[0]] = info.insertId; | ||
if (keyProperties) { | ||
if (keyProperties.length == 1 && info.hasOwnProperty("insertId") && info.insertId !== 0 ) { | ||
ids[keyProperties[0].name] = info.insertId; | ||
} else { | ||
for (var i = 0; i < id_prop.length; i++) { | ||
ids[id_prop[i]] = data[id_prop[i]]; | ||
for(i = 0; i < keyProperties.length; i++) { | ||
prop = keyProperties[i]; | ||
ids[prop.name] = data[prop.mapsTo]; | ||
} | ||
@@ -202,0 +185,0 @@ } |
@@ -178,20 +178,2 @@ var _ = require("lodash"); | ||
Driver.prototype.eagerQuery = function (association, opts, ids, cb) { | ||
var desiredKey = Object.keys(association.field); | ||
var assocKey = Object.keys(association.mergeAssocId); | ||
var where = {}; | ||
where[desiredKey] = ids; | ||
var query = this.query.select() | ||
.from(association.model.table) | ||
.select(opts.only) | ||
.from(association.mergeTable, assocKey, opts.id) | ||
.select(desiredKey).as("$p") | ||
.where(association.mergeTable, where) | ||
.build(); | ||
this.execSimpleQuery(query, cb); | ||
}; | ||
Driver.prototype.count = function (table, conditions, opts, cb) { | ||
@@ -222,3 +204,3 @@ var q = this.query.select().from(table).count(null, 'c'); | ||
Driver.prototype.insert = function (table, data, id_prop, cb) { | ||
Driver.prototype.insert = function (table, data, keyProperties, cb) { | ||
var q = this.query.insert().into(table).set(data).build(); | ||
@@ -231,7 +213,9 @@ | ||
var ids = {}; | ||
var i, ids = {}, prop; | ||
if (id_prop !== null) { | ||
for (var i = 0; i < id_prop.length; i++) { | ||
ids[id_prop[i]] = results[0][id_prop[i]] || null; | ||
if (keyProperties) { | ||
for (i = 0; i < keyProperties.length; i++) { | ||
prop = keyProperties[i]; | ||
ids[prop.name] = results[0][prop.mapsTo] || null; | ||
} | ||
@@ -238,0 +222,0 @@ } |
@@ -12,3 +12,3 @@ var util = require("util"); | ||
Driver.prototype.insert = function (table, data, id_prop, cb) { | ||
Driver.prototype.insert = function (table, data, keyProperties, cb) { | ||
var q = this.query.insert() | ||
@@ -23,26 +23,23 @@ .into(table) | ||
this.execQuery(q, function (err, result) { | ||
if (err) { | ||
return cb(err); | ||
} | ||
if (err) return cb(err); | ||
if (!keyProperties) return cb(null); | ||
if (id_prop === null) { | ||
return cb(null); | ||
} | ||
var i, ids = {}, prop; | ||
if (id_prop.length == 1) { | ||
return this.execQuery("SELECT LASTVAL() AS id", function (err, results) { | ||
return cb(null, { | ||
id: !err && results[0].id || null | ||
}); | ||
if (keyNames.length == 1) { | ||
this.execQuery("SELECT LASTVAL() AS id", function (err, results) { | ||
if (err) return cb(err); | ||
ids[keyProperties[0].name] = results[0].id || null; | ||
return cb(null, ids); | ||
}); | ||
} | ||
} else { | ||
for(i = 0; i < keyProperties.length; i++) { | ||
prop = keyProperties[i]; | ||
ids[prop.name] = data[prop.mapsTo] || null; | ||
} | ||
var ids = {}; | ||
for (var i = 0; i < id_prop.length; i++) { | ||
ids[id_prop[i]] = data[id_prop[i]] || null; | ||
return cb(null, ids); | ||
} | ||
return cb(null, ids); | ||
}.bind(this)); | ||
}; |
@@ -120,20 +120,2 @@ var _ = require("lodash"); | ||
Driver.prototype.eagerQuery = function (association, opts, ids, cb) { | ||
var desiredKey = Object.keys(association.field); | ||
var assocKey = Object.keys(association.mergeAssocId); | ||
var where = {}; | ||
where[desiredKey] = ids; | ||
var query = this.query.select() | ||
.from(association.model.table) | ||
.select(opts.only) | ||
.from(association.mergeTable, assocKey, opts.id) | ||
.select(desiredKey).as("$p") | ||
.where(association.mergeTable, where) | ||
.build(); | ||
this.execSimpleQuery(query, cb); | ||
}; | ||
Driver.prototype.count = function (table, conditions, opts, cb) { | ||
@@ -169,3 +151,3 @@ var q = this.query.select() | ||
Driver.prototype.insert = function (table, data, id_prop, cb) { | ||
Driver.prototype.insert = function (table, data, keyProperties, cb) { | ||
var q = this.query.insert() | ||
@@ -179,14 +161,25 @@ .into(table) | ||
} | ||
this.db.all(q, function (err, info) { | ||
if (err) { | ||
return cb(err); | ||
if (err) return cb(err); | ||
if (!keyProperties) return cb(null); | ||
var i, ids = {}, prop; | ||
if (keyProperties.length == 1 && keyProperties[0].type == 'serial') { | ||
this.db.get("SELECT last_insert_rowid() AS last_row_id", function (err, row) { | ||
if (err) return cb(err); | ||
ids[keyProperties[0].name] = row.last_row_id; | ||
return cb(null, ids); | ||
}); | ||
} else { | ||
for (i = 0; i < keyProperties.length; i++) { | ||
prop = keyProperties[i]; | ||
ids[prop.name] = data[prop.mapsTo] || null; | ||
} | ||
return cb(null, ids); | ||
} | ||
this.db.get("SELECT last_insert_rowid() AS last_row_id", function (err, row) { | ||
if (err) { | ||
return cb(err); | ||
} | ||
return cb(null, { | ||
id: row.last_row_id | ||
}); | ||
}); | ||
}.bind(this)); | ||
@@ -193,0 +186,0 @@ }; |
@@ -8,4 +8,5 @@ var codes = { | ||
PARAM_MISMATCH : 6, | ||
CONNECTION_LOST : 10 | ||
} | ||
CONNECTION_LOST : 10, | ||
BAD_MODEL : 15 | ||
}; | ||
@@ -12,0 +13,0 @@ function ORMError(message, code, extras) { |
@@ -12,6 +12,7 @@ var Utilities = require("./Utilities"); | ||
opts.extra = opts.extra || {}; | ||
opts.id = opts.id || "id"; | ||
opts.keys = opts.keys || "id"; | ||
opts.changes = (opts.is_new ? Object.keys(opts.data) : []); | ||
opts.extrachanges = []; | ||
opts.associations = {}; | ||
opts.originalKeyValues = {}; | ||
@@ -31,2 +32,10 @@ var instance_saving = false; | ||
}; | ||
var rememberKeys = function () { | ||
var i, prop; | ||
for(i = 0; i < opts.keyProperties.length; i++) { | ||
prop = opts.keyProperties[i]; | ||
opts.originalKeyValues[prop.name] = opts.data[prop.name]; | ||
} | ||
}; | ||
var handleValidations = function (cb) { | ||
@@ -190,2 +199,4 @@ var pending = [], errors = [], required; | ||
var saveNew = function (saveOptions, data, cb) { | ||
var i, prop; | ||
var finish = function (err) { | ||
@@ -200,3 +211,3 @@ runAfterSaveActions(function () { | ||
opts.driver.insert(opts.table, data, opts.id, function (save_err, info) { | ||
opts.driver.insert(opts.table, data, opts.keyProperties, function (save_err, info) { | ||
if (save_err) { | ||
@@ -207,6 +218,9 @@ return saveError(cb, save_err); | ||
opts.changes.length = 0; | ||
for (var i = 0; i < opts.id.length; i++) { | ||
opts.data[opts.id[i]] = info.hasOwnProperty(opts.id[i]) ? info[opts.id[i]] : data[opts.id[i]]; | ||
for (i = 0; i < opts.keyProperties.length; i++) { | ||
prop = opts.keyProperties[i]; | ||
opts.data[prop.name] = info.hasOwnProperty(prop.name) ? info[prop.name] : data[prop.name]; | ||
} | ||
opts.is_new = false; | ||
rememberKeys(); | ||
@@ -221,3 +235,3 @@ if (saveOptions.saveAssociations === false) { | ||
var savePersisted = function (saveOptions, data, cb) { | ||
var changes = {}, conditions = {}; | ||
var changes = {}, conditions = {}, i, prop; | ||
@@ -254,7 +268,8 @@ var next = function (saved) { | ||
} else { | ||
for (var i = 0; i < opts.changes.length; i++) { | ||
for (i = 0; i < opts.changes.length; i++) { | ||
changes[opts.changes[i]] = data[opts.changes[i]]; | ||
} | ||
for (i = 0; i < opts.id.length; i++) { | ||
conditions[opts.id[i]] = data[opts.id[i]]; | ||
for (i = 0; i < opts.keyProperties.length; i++) { | ||
prop = opts.keyProperties[i]; | ||
conditions[prop.mapsTo] = opts.originalKeyValues[prop.name]; | ||
} | ||
@@ -268,2 +283,3 @@ changes = Utilities.transformPropertyNames(changes, Model.allProperties); | ||
opts.changes.length = 0; | ||
rememberKeys(); | ||
@@ -367,3 +383,3 @@ next(true); | ||
conditions[opts.extra_info.id_prop[i]] = opts.extra_info.id[i]; | ||
conditions[opts.extra_info.assoc_prop[i]] = opts.data[opts.id[i]]; | ||
conditions[opts.extra_info.assoc_prop[i]] = opts.data[opts.keys[i]]; | ||
} | ||
@@ -381,4 +397,4 @@ | ||
var conditions = {}; | ||
for (var i = 0; i < opts.id.length; i++) { | ||
conditions[opts.id[i]] = opts.data[opts.id[i]]; | ||
for (var i = 0; i < opts.keys.length; i++) { | ||
conditions[opts.keys[i]] = opts.data[opts.keys[i]]; | ||
} | ||
@@ -420,4 +436,4 @@ | ||
for (var i = 0; i < opts.id.length; i++) { | ||
conditions[opts.id[i]] = opts.data[opts.id[i]]; | ||
for (var i = 0; i < opts.keys.length; i++) { | ||
conditions[opts.keys[i]] = opts.data[opts.keys[i]]; | ||
} | ||
@@ -456,2 +472,35 @@ | ||
// ('data.a.b', 5) => opts.data.a.b = 5 | ||
var setPropertyByPath = function (path, value) { | ||
if (typeof path == 'string') { | ||
path = path.split('.'); | ||
} else if (!Array.isArray(path)) { | ||
return; | ||
} | ||
var propName = path.shift(); | ||
var prop = Model.allProperties[propName] || opts.extra[propName]; | ||
var currKey, currObj; | ||
if (!prop) { | ||
return; | ||
} | ||
if (path.length == 0) { | ||
instance[propName] = value; | ||
return; | ||
} | ||
currObj = instance[propName]; | ||
while(currObj && path.length > 0 ) { | ||
currKey = path.shift(); | ||
if (path.length > 0) { | ||
currObj = currObj[currKey]; | ||
} else if (currObj[currKey] !== value) { | ||
currObj[currKey] = value; | ||
opts.changes.push(propName); | ||
} | ||
} | ||
} | ||
var addInstanceProperty = function (key) { | ||
@@ -479,4 +528,8 @@ var defaultValue = null; | ||
set: function (val) { | ||
if (Model.allProperties[key].key === true && opts.data[key] != null) { | ||
return; | ||
if (prop.key === true) { | ||
if (prop.type == 'serial' && opts.data[key] != null) { | ||
return; | ||
} else { | ||
opts.originalKeyValues[prop.name] = opts.data[prop.name]; | ||
} | ||
} | ||
@@ -615,2 +668,16 @@ | ||
}); | ||
Object.defineProperty(instance, "set", { | ||
value: setPropertyByPath, | ||
enumerable: false, | ||
writable: true | ||
}); | ||
Object.defineProperty(instance, "markAsDirty", { | ||
value: function (propName) { | ||
if (propName != undefined) { | ||
opts.changes.push(propName); | ||
} | ||
}, | ||
enumerable: false, | ||
writable: true | ||
}); | ||
Object.defineProperty(instance, "isInstance", { | ||
@@ -659,4 +726,6 @@ value: true, | ||
for (i = 0; i < opts.id.length; i++) { | ||
if (!opts.data.hasOwnProperty(opts.id[i])) { | ||
for (i = 0; i < opts.keyProperties.length; i++) { | ||
var prop = opts.keyProperties[i]; | ||
if (!(prop.name in opts.data)) { | ||
opts.changes = Object.keys(opts.data); | ||
@@ -666,2 +735,3 @@ break; | ||
} | ||
rememberKeys(); | ||
@@ -668,0 +738,0 @@ opts.setupAssociations(instance); |
@@ -17,3 +17,3 @@ exports.extend = function (Instance, Model, properties) { | ||
Model.find(conditions, { cache: false }).only(property).first(function (err, item) { | ||
Model.find(conditions, { cache: false }).only(Model.id.concat(property)).first(function (err, item) { | ||
return cb(err, item ? item[property] : null); | ||
@@ -31,3 +31,3 @@ }); | ||
Model.find(conditions, { cache: false }).only(property).first(function (err, item) { | ||
Model.find(conditions, { cache: false }).only(Model.id.concat(property)).first(function (err, item) { | ||
if (err) { | ||
@@ -41,3 +41,2 @@ return cb(err); | ||
item[property] = null; | ||
item[Model.id] = Instance[Model.id]; | ||
@@ -44,0 +43,0 @@ return item.save(cb); |
@@ -27,5 +27,5 @@ var _ = require("lodash"); | ||
opts = _.defaults(opts || {}, { | ||
id: [] | ||
keys: [] | ||
}); | ||
opts.id = Array.isArray(opts.id) ? opts.id : [opts.id]; | ||
opts.keys = Array.isArray(opts.keys) ? opts.keys : [opts.keys]; | ||
@@ -39,2 +39,3 @@ var one_associations = []; | ||
var allProperties = {}; | ||
var keyProperties = []; | ||
@@ -62,3 +63,3 @@ var createHookHelper = function (hook) { | ||
if (inst_opts.extra && inst_opts.extra.hasOwnProperty(k)) continue; | ||
if (opts.id.indexOf(k) >= 0) continue; | ||
if (opts.keys.indexOf(k) >= 0) continue; | ||
if (association_properties.indexOf(k) >= 0) continue; | ||
@@ -100,3 +101,3 @@ | ||
uid : inst_opts.uid, // singleton unique id | ||
id : opts.id, | ||
keys : opts.keys, | ||
is_new : inst_opts.is_new || false, | ||
@@ -118,3 +119,4 @@ isShell : inst_opts.isShell || false, | ||
setupAssociations : setupAssociations, | ||
fieldToPropertyMap : fieldToPropertyMap | ||
fieldToPropertyMap : fieldToPropertyMap, | ||
keyProperties : keyProperties | ||
}); | ||
@@ -157,7 +159,7 @@ instance.on("ready", function (err) { | ||
if (Array.isArray(opts.id) && Array.isArray(data)) { | ||
if (data.length == opts.id.length) { | ||
if (Array.isArray(opts.keys) && Array.isArray(data)) { | ||
if (data.length == opts.keys.length) { | ||
var data2 = {}; | ||
for (i = 0; i < opts.id.length; i++) { | ||
data2[opts.id[i]] = data[i++]; | ||
for (i = 0; i < opts.keys.length; i++) { | ||
data2[opts.keys[i]] = data[i++]; | ||
} | ||
@@ -168,3 +170,3 @@ | ||
else { | ||
var err = new Error('Model requires ' + opts.id.length + ' keys, only ' + data.length + ' were provided'); | ||
var err = new Error('Model requires ' + opts.keys.length + ' keys, only ' + data.length + ' were provided'); | ||
err.model = opts.table; | ||
@@ -177,3 +179,3 @@ | ||
var data2 = {}; | ||
data2[opts.id[0]] = data; | ||
data2[opts.keys[0]] = data; | ||
@@ -187,4 +189,4 @@ return createInstance(data2, { isShell: true }); | ||
for (i = 0; i < opts.id.length; i++) { | ||
if (!data.hasOwnProperty(opts.id[i])) { | ||
for (i = 0; i < opts.keys.length; i++) { | ||
if (!data.hasOwnProperty(opts.keys[i])) { | ||
isNew = true; | ||
@@ -195,5 +197,5 @@ break; | ||
if (opts.id.length === 1 && opts.id[0] != 'id') { | ||
isNew = true; //Dubiously assume that it is a new instance if we're using custom keys | ||
} | ||
if (keyProperties.length != 1 || (keyProperties.length == 1 && keyProperties[0].type != 'serial')) { | ||
isNew = true; | ||
} | ||
@@ -237,3 +239,3 @@ return createInstance(data, { | ||
extension : opts.extension, | ||
id : opts.id, | ||
id : opts.keys, | ||
table : opts.table, | ||
@@ -263,2 +265,3 @@ properties : opts.properties, | ||
var cb = ids.pop(); | ||
var prop; | ||
@@ -277,8 +280,9 @@ if (typeof cb !== "function") { | ||
if (ids.length !== opts.id.length) { | ||
throw new ORMError("Model.get() IDs number mismatch (" + opts.id.length + " needed, " + ids.length + " passed)", 'PARAM_MISMATCH', { model: opts.table }); | ||
if (ids.length !== opts.keys.length) { | ||
throw new ORMError("Model.get() IDs number mismatch (" + opts.keys.length + " needed, " + ids.length + " passed)", 'PARAM_MISMATCH', { model: opts.table }); | ||
} | ||
for (var i = 0; i < opts.id.length; i++) { | ||
conditions[opts.id[i]] = ids[i]; | ||
for (var i = 0; i < keyProperties.length; i++) { | ||
prop = keyProperties[i]; | ||
conditions[prop.mapsTo] = ids[i]; | ||
} | ||
@@ -395,3 +399,3 @@ | ||
only : options.only || model_fields, | ||
id : opts.id, | ||
keys : opts.keys, | ||
table : opts.table, | ||
@@ -406,6 +410,7 @@ driver : opts.driver, | ||
properties : allProperties, | ||
keyProperties: keyProperties, | ||
newInstance : function (data, cb) { | ||
var uid = opts.driver.uid + "/" + opts.table + (merge ? "+" + merge.from.table : ""); | ||
for (var i = 0; i < opts.id.length; i++) { | ||
uid += "/" + data[opts.id[i]]; | ||
for (var i = 0; i < opts.keys.length; i++) { | ||
uid += "/" + data[opts.keys[i]]; | ||
} | ||
@@ -543,4 +548,4 @@ | ||
if (Array.isArray(ids[0])) { | ||
for (i = 0; i < opts.id.length; i++) { | ||
conditions[opts.id[i]] = ids[0][i]; | ||
for (i = 0; i < opts.keys.length; i++) { | ||
conditions[opts.keys[i]] = ids[0][i]; | ||
} | ||
@@ -551,4 +556,4 @@ } else { | ||
} else { | ||
for (i = 0; i < opts.id.length; i++) { | ||
conditions[opts.id[i]] = ids[i]; | ||
for (i = 0; i < opts.keys.length; i++) { | ||
conditions[opts.keys[i]] = ids[i]; | ||
} | ||
@@ -639,3 +644,3 @@ } | ||
Object.defineProperty(model, "id", { | ||
value: opts.id, | ||
value: opts.keys, | ||
enumerable: false | ||
@@ -648,3 +653,3 @@ }); | ||
Object.defineProperty(model, "uid", { | ||
value: opts.driver.uid + "/" + opts.table + "/" + opts.id.join("/"), | ||
value: opts.driver.uid + "/" + opts.table + "/" + opts.keys.join("/"), | ||
enumerable: false | ||
@@ -663,3 +668,3 @@ }); | ||
// If no keys are defined add the default one | ||
if (opts.id.length == 0 && !_.any(opts.properties, { key: true })) { | ||
if (opts.keys.length == 0 && !_.any(opts.properties, { key: true })) { | ||
name = opts.settings.get("properties.primary_key"); | ||
@@ -683,7 +688,10 @@ | ||
if (opts.id.indexOf(k) != -1) { | ||
if (opts.keys.indexOf(k) != -1) { | ||
prop.key = true; | ||
} else if (prop.key) { | ||
opts.id.push(k); | ||
opts.keys.push(k); | ||
} | ||
if (prop.key) { | ||
keyProperties.push(prop); | ||
} | ||
@@ -710,2 +718,6 @@ if (prop.lazyload !== true && !currFields[k]) { | ||
if (keyProperties.length == 0) { | ||
throw new ORMError("Model defined without any keys", 'BAD_MODEL', { model: opts.table }); | ||
} | ||
// setup hooks | ||
@@ -712,0 +724,0 @@ for (k in AvailableHooks) { |
@@ -11,2 +11,3 @@ var util = require("util"); | ||
var DriverAliases = require("./Drivers/aliases"); | ||
var adapters = require("./Adapters"); | ||
var Settings = require("./Settings"); | ||
@@ -52,3 +53,3 @@ var Singleton = require("./Singleton"); | ||
try { | ||
var Driver = require("./Drivers/DML/" + proto).Driver; | ||
var Driver = adapters.get(proto); | ||
var settings = new Settings.Container(exports.settings.get('*')); | ||
@@ -114,3 +115,3 @@ var driver = new Driver(null, connection, { | ||
try { | ||
var Driver = require("./Drivers/DML/" + proto).Driver; | ||
var Driver = adapters.get(proto); | ||
var settings = new Settings.Container(exports.settings.get('*')); | ||
@@ -148,2 +149,4 @@ var debug = extractOption(opts, "debug"); | ||
exports.addAdapter = adapters.add; | ||
function ORM(driver_name, driver, settings) { | ||
@@ -233,3 +236,3 @@ this.validators = exports.validators; | ||
cache : opts.hasOwnProperty("cache") ? opts.cache : this.settings.get("instance.cache"), | ||
id : opts.id,// || this.settings.get("properties.primary_key"), | ||
keys : opts.id, | ||
autoSave : opts.hasOwnProperty("autoSave") ? opts.autoSave : this.settings.get("instance.autoSave"), | ||
@@ -236,0 +239,0 @@ autoFetch : opts.hasOwnProperty("autoFetch") ? opts.autoFetch : this.settings.get("instance.autoFetch"), |
@@ -15,3 +15,3 @@ { | ||
], | ||
"version" : "2.1.14", | ||
"version" : "2.1.15", | ||
"license" : "MIT", | ||
@@ -42,3 +42,3 @@ "homepage" : "http://dresende.github.io/node-orm2", | ||
"sql-query" : "git+https://github.com/dresende/node-sql-query.git#v0.1.21", | ||
"sql-ddl-sync" : "git+https://github.com/dresende/node-sql-ddl-sync.git#v0.3.6", | ||
"sql-ddl-sync" : "git+https://github.com/dresende/node-sql-ddl-sync.git#v0.3.7", | ||
"hat" : "0.0.3", | ||
@@ -45,0 +45,0 @@ "lodash" : "2.4.1" |
@@ -642,3 +642,3 @@ ## Object Relational Mapping | ||
Is a **many to many** relationship (includes join table).<br/> | ||
Eg: `Patient.hasMany('doctors', Doctor, { why: String }, { reverse: 'patients' })`.<br/> | ||
Eg: `Patient.hasMany('doctors', Doctor, { why: String }, { reverse: 'patients', key: true })`.<br/> | ||
Patient can have many different doctors. Each doctor can have many different patients. | ||
@@ -650,4 +650,4 @@ | ||
:-----------|:-------- | ||
patient_id | Integer | ||
doctor_id | Integer | ||
patient_id | Integer (composite key) | ||
doctor_id | Integer (composite key) | ||
why | varchar(255) | ||
@@ -757,3 +757,3 @@ | ||
rate : Number | ||
}); | ||
}, {}, { key: true }); | ||
@@ -778,2 +778,3 @@ Person.get(123, function (err, John) { | ||
}, { | ||
key : true, // Turns the foreign keys in the join table into a composite key | ||
autoFetch : true | ||
@@ -797,2 +798,4 @@ }); | ||
rate : Number | ||
}, { | ||
key: true | ||
}); | ||
@@ -838,2 +841,3 @@ ``` | ||
}, { | ||
key : true, | ||
reverse : "owners" | ||
@@ -845,1 +849,12 @@ }); | ||
``` | ||
## Adding external database adapters | ||
To add an external database adapter to `orm`, call the `addAdapter` method, passing in the alias to use for connecting | ||
with this adapter, along with the constructor for the adapter: | ||
```js | ||
require('orm').addAdapter('cassandra', CassandraAdapter); | ||
``` | ||
See [the documentation for creating adapters](./Adapters.md) for more details. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Git dependency
Supply chain riskContains a dependency which resolves to a remote git URL. Dependencies fetched from git URLs are not immutable can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Git dependency
Supply chain riskContains a dependency which resolves to a remote git URL. Dependencies fetched from git URLs are not immutable can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
238284
65
5919
854
6