Skip to content

Commit

Permalink
Allow specifying key: true on properties rather than passing array …
Browse files Browse the repository at this point in the history
…of ids
  • Loading branch information
dxg committed May 22, 2014
1 parent 3ffd583 commit 7234015
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 31 deletions.
3 changes: 3 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### v2.1.14 - ***
- Allow explicitly specifying `key: true` on properties rather than passing in an array of ids.

### v2.1.13 - 21 May 2014
- Dont modify array passed to execQuery

Expand Down
19 changes: 8 additions & 11 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,17 +232,16 @@ See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Synchin

ORM2 allows you some advanced tweaks on your Model definitions. You can configure these via settings or in the call to `define` when you setup the Model.

For example, each Model instance has a unique ID in the database. This table column is
by default "id" but you can change it.
For example, each Model instance has a unique ID in the database. This table column is added automatically, and called "id" by default.<br/>
If you define your own `key: true` column, "id" will not be added:

```js
var Person = db.define("person", {
name : String
}, {
id : "person_id"
personId : { type: 'serial', key: true },
name : String
});

// or just do it globally..
// You can also change the default "id" property name globally:
db.settings.set("properties.primary_key", "UID");

// ..and then define your Models
Expand All @@ -253,14 +252,12 @@ var Pet = db.define("pet", {

**Pet** model will have 2 columns, an `UID` and a `name`.

It is also possible to have multiple IDs for a model in the database, this is done by specifying an array of IDs to use.
It's also possible to have composite keys:

```js
var Person = db.define("person", {
firstname: String,
lastname: String
}, {
id: ['firstname', 'lastname']
firstname : { type: 'string', key: true },
lastname : { type: 'string', key: true }
});
```

Expand Down
20 changes: 17 additions & 3 deletions lib/Associations/Many.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ var util = require("../Utilities");

exports.prepare = function (db, Model, associations) {
Model.hasMany = function () {
var name;
var name, makeKey, mergeId, mergeAssocId;
var OtherModel = Model;
var props = null;
var opts = {};
Expand Down Expand Up @@ -41,6 +41,20 @@ exports.prepare = function (db, Model, associations) {
}
}

makeKey = opts.key || Settings.defaults().hasMany.key;

mergeId = util.convertPropToJoinKeyProp(
util.wrapFieldObject(opts.mergeId, OtherModel, Model.table, OtherModel.properties) ||
util.formatField(OtherModel, Model.table, true, opts.reversed),
{ makeKey: makeKey, required: true }
);

mergeAssocId = util.convertPropToJoinKeyProp(
util.wrapFieldObject(opts.mergeAssocId, Model, name, Model.properties) ||
util.formatField(Model, name, true, opts.reversed),
{ makeKey: makeKey, required: true }
)

var assocName = opts.name || ucfirst(name);
var assocTemplateName = opts.accessor || assocName;
var association = {
Expand All @@ -53,8 +67,8 @@ exports.prepare = function (db, Model, associations) {
// I'm not sure the next key is used..
field : util.wrapFieldObject(opts.field, OtherModel, Model.table, OtherModel.properties) || util.formatField(Model, name, true, opts.reversed),
mergeTable : opts.mergeTable || (Model.table + "_" + name),
mergeId : util.wrapFieldObject(opts.mergeId, OtherModel, Model.table, OtherModel.properties) || util.formatField(OtherModel, Model.table, true, opts.reversed),
mergeAssocId : util.wrapFieldObject(opts.mergeAssocId, Model, name, Model.properties) || util.formatField(Model, name, true, opts.reversed),
mergeId : mergeId,
mergeAssocId : mergeAssocId,
getAccessor : opts.getAccessor || ("get" + assocTemplateName),
setAccessor : opts.setAccessor || ("set" + assocTemplateName),
hasAccessor : opts.hasAccessor || ("has" + assocTemplateName),
Expand Down
1 change: 1 addition & 0 deletions lib/Associations/One.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ exports.prepare = function (Model, associations, association_properties, model_f
} else if(!association.extension) {
association.field = util.wrapFieldObject(association.field, Model, Model.table, Model.properties);
}
util.convertPropToJoinKeyProp(association.field, { makeKey: false, required: false });
for (var k in Accessors) {
if (!association.hasOwnProperty(k + "Accessor")) {
association[k + "Accessor"] = Accessors[k] + assocTemplateName;
Expand Down
35 changes: 19 additions & 16 deletions lib/Model.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var _ = require("lodash");
var ChainFind = require("./ChainFind");
var Instance = require("./Instance").Instance;
var LazyLoad = require("./LazyLoad");
Expand All @@ -22,11 +23,10 @@ var AvailableHooks = [
exports.Model = Model;

function Model(opts) {
opts = opts || {};

if (!Array.isArray(opts.id)) {
opts.id = [ opts.id ];
}
opts = _.defaults(opts || {}, {
id: []
});
opts.id = Array.isArray(opts.id) ? opts.id : [opts.id];

var one_associations = [];
var many_associations = [];
Expand Down Expand Up @@ -645,7 +645,17 @@ function Model(opts) {
}
}

var currFields = {}, cType;
var currFields = {}, cType, name;

// If no keys are defined add the default one
if (opts.id.length == 0 && !_.any(opts.properties, { key: true })) {
name = opts.settings.get("properties.primary_key");

opts.properties[name] = Property.normalize({
prop: { type: 'serial', key: true, required: false, klass: 'key' },
name: name, customTypes: opts.db.customTypes, settings: opts.settings
});
}

// standardize properties
for (k in opts.properties) {
Expand All @@ -659,7 +669,10 @@ function Model(opts) {

if (opts.id.indexOf(k) != -1) {
prop.key = true;
} else if (prop.key) {
opts.id.push(k);
}

if (prop.lazyload !== true && !currFields[k]) {
currFields[k] = true;
if ((cType = opts.db.customTypes[prop.type]) && cType.datastoreGet) {
Expand All @@ -680,16 +693,6 @@ function Model(opts) {
}
}

for (var i = 0; i < opts.id.length; i++) {
k = opts.id[i];
allProperties[k] = opts.properties[k] || Property.normalize({
prop: { type: 'serial', key: true, klass: 'key' },
name: k, customTypes: opts.db.customTypes, settings: opts.settings
});
fieldToPropertyMap[allProperties[k].mapsTo] = allProperties[k];
}
model_fields = opts.id.concat(model_fields);

// setup hooks
for (k in AvailableHooks) {
model[AvailableHooks[k]] = createHookHelper(AvailableHooks[k]);
Expand Down
2 changes: 1 addition & 1 deletion lib/ORM.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ ORM.prototype.define = function (name, properties, opts) {
extension : opts.extension || false,
indexes : opts.indexes || [],
cache : opts.hasOwnProperty("cache") ? opts.cache : this.settings.get("instance.cache"),
id : opts.id || this.settings.get("properties.primary_key"),
id : opts.id,// || this.settings.get("properties.primary_key"),
autoSave : opts.hasOwnProperty("autoSave") ? opts.autoSave : this.settings.get("instance.autoSave"),
autoFetch : opts.hasOwnProperty("autoFetch") ? opts.autoFetch : this.settings.get("instance.autoFetch"),
autoFetchLimit : opts.autoFetchLimit || this.settings.get("instance.autoFetchLimit"),
Expand Down
4 changes: 4 additions & 0 deletions lib/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ var default_settings = {
cascadeRemove : true,
returnAllErrors : false
},
hasMany : {
// Makes the foreign key fields a composite key
key : false
},
connection : {
reconnect : true,
pool : false,
Expand Down
23 changes: 23 additions & 0 deletions lib/Utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,29 @@ exports.formatField = function (model, name, required, reversed) {
return fields;
};

// If the parent associations key is `serial`, the join tables
// key should be changed to `integer`.
exports.convertPropToJoinKeyProp = function (props, opts) {
var prop;

for (var k in props) {
prop = props[k];

prop.required = opts.required;

if (prop.type == 'serial') {
prop.type = 'integer';
}
if (opts.makeKey) {
prop.key = true;
} else {
delete prop.key;
}
}

return props;
}

exports.getRealPath = function (path_str, stack_index) {
var path = require("path"); // for now, load here (only when needed)
var cwd = process.cwd();
Expand Down

0 comments on commit 7234015

Please sign in to comment.