Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/Associations/Many.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ exports.prepare = function (Model, associations) {
props = {};
} else {
for (var k in props) {
props[k] = Property.normalize(props[k], {}, Model.settings);
props[k] = Property.normalize({
prop: props[k], name: k, customTypes: {}, settings: Model.settings
});
}
}

Expand All @@ -59,7 +61,6 @@ exports.prepare = function (Model, associations) {
delAccessor : opts.delAccessor || ("remove" + assocTemplateName),
addAccessor : opts.addAccessor || ("add" + assocTemplateName)
};

associations.push(association);

if (opts.reverse) {
Expand Down
16 changes: 9 additions & 7 deletions lib/Instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,14 @@ function Instance(Model, opts) {
prop = Model.allProperties[k];

if (prop) {
if (prop.type === 'serial' && opts.data[k] == null) continue;
if (opts.data[k] == null && (prop.type == 'serial' || typeof prop.defaultValue == 'function')) {
continue;
}

data[k] = Property.validate(opts.data[k], prop);
if (opts.driver.propertyToValue) {
data[k] = opts.driver.propertyToValue(data[k], prop);
data[prop.mapsTo] = opts.driver.propertyToValue(opts.data[k], prop);
} else {
data[prop.mapsTo] = opts.data[k];
}
} else {
data[k] = opts.data[k];
Expand Down Expand Up @@ -195,7 +198,7 @@ function Instance(Model, opts) {

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]];
opts.data[opts.id[i]] = info.hasOwnProperty(opts.id[i]) ? info[opts.id[i]] : data[opts.id[i]];
}
opts.is_new = false;

Expand Down Expand Up @@ -337,7 +340,7 @@ function Instance(Model, opts) {
if (!opts.data.hasOwnProperty(opts.extrachanges[i])) continue;

if (opts.extra[opts.extrachanges[i]]) {
data[opts.extrachanges[i]] = Property.validate(opts.data[opts.extrachanges[i]], opts.extra[opts.extrachanges[i]]);
data[opts.extrachanges[i]] = opts.data[opts.extrachanges[i]];
if (opts.driver.propertyToValue) {
data[opts.extrachanges[i]] = opts.driver.propertyToValue(data[opts.extrachanges[i]], opts.extra[opts.extrachanges[i]]);
}
Expand Down Expand Up @@ -394,8 +397,7 @@ function Instance(Model, opts) {
changes[key] = value;

if (Model.properties[key]) {
changes[key] = Property.validate(changes[key], Model.properties[key]);
if (opts.driver.propertyToValue) {
if (opts.driver.propertyToValue) {
changes[key] = opts.driver.propertyToValue(changes[key], Model.properties[key]);
}
}
Expand Down
55 changes: 42 additions & 13 deletions lib/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ function Model(opts) {
var extend_associations = [];
var association_properties = [];
var model_fields = [];
var fieldToPropertyMap = {};
var allProperties = {};

var createHookHelper = function (hook) {
Expand Down Expand Up @@ -142,6 +143,18 @@ function Model(opts) {
return instance;
};

var mapDatastoreFieldsToProperties = function (dataIn) {
var k, prop;
var dataOut = {};

for (k in dataIn) {
prop = fieldToPropertyMap[k];
if (!prop) dataOut[k] = dataIn[k];
else dataOut[prop.name] = dataIn[k];
}
return dataOut;
}

var model = function () {
var instance, i;

Expand Down Expand Up @@ -283,16 +296,18 @@ function Model(opts) {
return cb(new ORMError(err.message, 'QUERY_ERROR', { originalCode: err.code }));
}
if (data.length === 0) {
return cb(new ORMError("Not found", 'NOT_FOUND', { model: opts.table }));
return cb(new ORMError("Not found", 'NOT_FOUND', { model: opts.table }));
}

data = mapDatastoreFieldsToProperties(data[0]);

var uid = opts.driver.uid + "/" + opts.table + "/" + ids.join("/");

Singleton.get(uid, {
cache : (options.hasOwnProperty("cache") ? options.cache : opts.cache),
save_check : opts.settings.get("instance.cacheSaveCheck")
}, function (cb) {
return createInstance(data[0], {
return createInstance(data, {
uid : uid,
autoSave : options.autoSave,
autoFetch : (options.autoFetchLimit === 0 ? false : options.autoFetch),
Expand Down Expand Up @@ -630,20 +645,32 @@ function Model(opts) {
}
}

var currFields = {}, cType;

// standardize properties
for (k in opts.properties) {
opts.properties[k] = Property.normalize(opts.properties[k], opts.db.customTypes, opts.settings);
opts.properties[k].klass = 'primary';
allProperties[k] = opts.properties[k];
var prop = opts.properties[k] = Property.normalize({
prop: opts.properties[k], name: k,
customTypes: opts.db.customTypes, settings: opts.settings
});
prop.klass = 'primary';
allProperties[k] = prop;
fieldToPropertyMap[prop.mapsTo] = prop;

if (opts.id.indexOf(k) != -1) {
opts.properties[k].key = true;
prop.key = true;
}

if (opts.properties[k].lazyload !== true && model_fields.indexOf(k) == -1) {
model_fields.push(k);
if (prop.lazyload !== true && !currFields[k]) {
currFields[k] = true;
if ((cType = opts.db.customTypes[prop.type]) && cType.datastoreGet) {
model_fields.push({
a: prop.mapsTo, sql: cType.datastoreGet(prop, opts.db.driver.query)
});
} else {
model_fields.push(prop.mapsTo);
}
}
if (opts.properties[k].required) {
if (prop.required) {
// Prepend `required` validation
if(opts.validations.hasOwnProperty(k)) {
opts.validations[k].splice(0, 0, Validators.required());
Expand All @@ -655,9 +682,11 @@ function Model(opts) {

for (var i = 0; i < opts.id.length; i++) {
k = opts.id[i];
allProperties[k] = opts.properties[k] || {
type: 'serial', key: true, klass: 'key'
};
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);

Expand Down
62 changes: 32 additions & 30 deletions lib/Property.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,59 +3,61 @@ var ORMError = require("./Error");
var KNOWN_TYPES = [
"text", "number", "integer", "boolean", "date", "enum", "object",
"binary", "point", "serial"
]
];

exports.normalize = function (prop, customTypes, Settings) {
if (typeof prop === "function") {
switch (prop.name) {
exports.normalize = function (opts) {
if (typeof opts.prop === "function") {
switch (opts.prop.name) {
case "String":
prop = { type: "text" };
opts.prop = { type: "text" };
break;
case "Number":
prop = { type: "number" };
opts.prop = { type: "number" };
break;
case "Boolean":
prop = { type: "boolean" };
opts.prop = { type: "boolean" };
break;
case "Date":
prop = { type: "date" };
opts.prop = { type: "date" };
break;
case "Object":
prop = { type: "object" };
opts.prop = { type: "object" };
break;
case "Buffer":
prop = { type: "binary" };
opts.prop = { type: "binary" };
break;
}
} else if (typeof prop === "string") {
var tmp = prop;
prop = {};
prop.type = tmp;
} else if (Array.isArray(prop)) {
prop = { type: "enum", values: prop };
} else if (typeof opts.prop === "string") {
var tmp = opts.prop;
opts.prop = {};
opts.prop.type = tmp;
} else if (Array.isArray(opts.prop)) {
opts.prop = { type: "enum", values: opts.prop };
}

if (KNOWN_TYPES.indexOf(prop.type) === -1 && !(prop.type in customTypes)) {
throw new ORMError("Unknown property type: " + prop.type, 'NO_SUPPORT');
}
if (KNOWN_TYPES.indexOf(opts.prop.type) === -1 && !(opts.prop.type in opts.customTypes)) {
throw new ORMError("Unknown property type: " + opts.prop.type, 'NO_SUPPORT');
}

if (!prop.hasOwnProperty("required") && Settings.get("properties.required")) {
prop.required = true;
if (!opts.prop.hasOwnProperty("required") && opts.settings.get("properties.required")) {
opts.prop.required = true;
}

// Defaults to true. Rational means floating point here.
if (prop.type == "number" && prop.rational === undefined) {
prop.rational = true;
if (opts.prop.type == "number" && opts.prop.rational === undefined) {
opts.prop.rational = true;
}

if (prop.type == "number" && prop.rational === false) {
prop.type = "integer";
delete prop.rational;
if (!('mapsTo' in opts.prop)) {
opts.prop.mapsTo = opts.name
}

return prop;
};
if (opts.prop.type == "number" && opts.prop.rational === false) {
opts.prop.type = "integer";
delete opts.prop.rational;
}

opts.prop.name = opts.name;

exports.validate = function (value, prop) {
return value;
return opts.prop;
};
17 changes: 14 additions & 3 deletions lib/Utilities.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
_ = require('lodash')

/**
* Order should be a String (with the property name assumed ascending)
* or an Array or property String names.
Expand Down Expand Up @@ -176,7 +178,12 @@ exports.wrapFieldObject = function (obj, model, altName, alternatives) {

var new_obj = {};

new_obj[obj] = alternatives[obj] || alternatives[model.id[0]] || { type: 'number', unsigned: true, rational: false };
new_obj[obj] = _.cloneDeep(
alternatives[obj] || alternatives[model.id[0]] || { type: 'number', unsigned: true, rational: false }
);
new_obj[obj].name = obj;
new_obj[obj].mapsTo = obj;


return new_obj;
};
Expand Down Expand Up @@ -206,14 +213,18 @@ exports.formatField = function (model, name, required, reversed) {
time : p.time || false,
big : p.big || false,
values : p.values || null,
required : required
required : required,
name : field_name,
mapsTo : field_name
};
} else {
field_opts = {
type : "integer",
unsigned : true,
size : 4,
required : required
required : required,
name : field_name,
mapsTo : field_name
};
}

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
"analyse" : false,
"dependencies": {
"enforce" : "0.1.2",
"sql-query" : "0.1.16",
"sql-ddl-sync" : "git://github.com/dresende/node-sql-ddl-sync.git#v0.3.0",
"sql-query" : "git://github.com/dresende/node-sql-query.git#v0.1.17",
"sql-ddl-sync" : "git://github.com/dresende/node-sql-ddl-sync.git#v0.3.2",
"hat" : "0.0.3",
"lodash" : "2.4.1"
},
Expand Down
4 changes: 3 additions & 1 deletion test/integration/model-find-chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,9 @@ describe("Model.find() chaining", function() {
Person.find().omit("age", "surname").order("-age").run(function (err, instances) {
should.equal(err, null);
instances.should.have.property("length", 3);
should.exist(instances[0].id);
if (common.protocol() != "mongodb") {
should.exist(instances[0].id);
}
should.exist(instances[0].friend_id);
instances[0].should.have.property("age", null);
instances[0].should.have.property("surname", null);
Expand Down
31 changes: 30 additions & 1 deletion test/integration/model-get.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
var _ = require('lodash');
var should = require('should');
var helper = require('../support/spec_helper');
var common = require('../common');
var ORM = require('../../');
var protocol = common.protocol();

describe("Model.get()", function() {
var db = null;
Expand All @@ -11,7 +13,7 @@ describe("Model.get()", function() {
var setup = function (cache) {
return function (done) {
Person = db.define("person", {
name : String
name : { type: 'text', mapsTo: 'fullname' }
}, {
cache : cache,
methods: {
Expand Down Expand Up @@ -49,6 +51,33 @@ describe("Model.get()", function() {
return db.close();
});

describe("mapsTo", function () {
if (protocol == 'mongodb') return;

before(setup(true));

it("should create the table with a different column name than property name", function (done) {
var sql;

if (protocol == 'sqlite') {
sql = "PRAGMA table_info(?)";
} else {
sql = "SELECT column_name FROM information_schema.columns WHERE table_name = ?";
}

db.driver.execQuery(sql, [Person.table], function (err, data) {
should.not.exist(err);

var names = _.pluck(data, protocol == 'sqlite' ? 'name' : 'column_name')

should.equal(typeof Person.properties.name, 'object');
should.notEqual(names.indexOf('fullname'), -1);

done();
});
});
});

describe("with cache", function () {
before(setup(true));

Expand Down
Loading