diff --git a/Changelog.md b/Changelog.md index 1b4147bd..aa392bc0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,6 @@ -### v2.1.14 - *** +### v2.1.14 - 22 May 2014 - Allow explicitly specifying `key: true` on properties rather than passing in an array of ids. +- Fix Property.mapsTo (#506) ### v2.1.13 - 21 May 2014 - Dont modify array passed to execQuery diff --git a/lib/AggregateFunctions.js b/lib/AggregateFunctions.js index da8544c1..4ce0ce75 100644 --- a/lib/AggregateFunctions.js +++ b/lib/AggregateFunctions.js @@ -55,9 +55,9 @@ function AggregateFunctions(opts) { throw new ORMError('PARAM_MISMATCH', "When using append you must at least define one property"); } if (Array.isArray(arguments[0])) { - opts.properties = opts.properties.concat(arguments[0]); + opts.propertyList = opts.propertyList.concat(arguments[0]); } else { - opts.properties = opts.properties.concat(Array.prototype.slice.apply(arguments)); + opts.propertyList = opts.propertyList.concat(Array.prototype.slice.apply(arguments)); } return this; }, @@ -97,7 +97,7 @@ function AggregateFunctions(opts) { throw new ORMError('PARAM_MISMATCH', "Missing aggregate functions"); } - var query = opts.driver.getQuery().select().from(opts.table).select(opts.properties); + var query = opts.driver.getQuery().select().from(opts.table).select(opts.propertyList); var i, j; for (i = 0; i < aggregates.length; i++) { diff --git a/lib/ChainFind.js b/lib/ChainFind.js index e52aa756..b2b52cfb 100644 --- a/lib/ChainFind.js +++ b/lib/ChainFind.js @@ -1,4 +1,5 @@ var _ = require("lodash"); +var Utilities = require("./Utilities"); var ChainInstance = require("./ChainInstance"); var Promise = require("./Promise").Promise; @@ -45,7 +46,7 @@ function ChainFind(Model, opts) { } else { omit = Array.prototype.slice.apply(arguments); } - this.only(_.difference(Object.keys(Model.allProperties), omit)); + this.only(_.difference(Object.keys(opts.properties), omit)); return this; }, limit: function (limit) { @@ -170,9 +171,18 @@ function ChainFind(Model, opts) { return this; }, all: function (cb) { - opts.driver.find(opts.only, opts.table, opts.conditions, { + var order, conditions; + + conditions = Utilities.transformPropertyNames( + opts.conditions, opts.properties + ); + order = Utilities.transformOrderPropertyNames( + opts.order, opts.properties + ); + + opts.driver.find(opts.only, opts.table, conditions, { limit : opts.limit, - order : opts.order, + order : order, merge : opts.merge, offset : opts.offset, exists : opts.exists diff --git a/lib/Drivers/DML/mongodb.js b/lib/Drivers/DML/mongodb.js index 45fc3657..06208999 100644 --- a/lib/Drivers/DML/mongodb.js +++ b/lib/Drivers/DML/mongodb.js @@ -264,7 +264,10 @@ Driver.prototype.hasMany = function (Model, association) { if (options.order) { options.order[0] = options.order[0][1]; - options.order = Utilities.standardizeOrder(options.order); + options.order = Utilities.transformOrderPropertyNames( + Utilities.standardizeOrder(options.order), + Model.allProperties + ); } options.extra_props = association.props; diff --git a/lib/Instance.js b/lib/Instance.js index 859be697..f7a9c3c3 100755 --- a/lib/Instance.js +++ b/lib/Instance.js @@ -1,6 +1,7 @@ -var Property = require("./Property"); -var Hook = require("./Hook"); -var enforce = require("enforce"); +var Utilities = require("./Utilities"); +var Property = require("./Property"); +var Hook = require("./Hook"); +var enforce = require("enforce"); exports.Instance = Instance; @@ -156,9 +157,9 @@ function Instance(Model, opts) { } if (opts.driver.propertyToValue) { - data[prop.mapsTo] = opts.driver.propertyToValue(opts.data[k], prop); + data[k] = opts.driver.propertyToValue(opts.data[k], prop); } else { - data[prop.mapsTo] = opts.data[k]; + data[k] = opts.data[k]; } } else { data[k] = opts.data[k]; @@ -191,6 +192,8 @@ function Instance(Model, opts) { }, true); } + data = Utilities.transformPropertyNames(data, Model.allProperties); + opts.driver.insert(opts.table, data, opts.id, function (save_err, info) { if (save_err) { return saveError(cb, save_err); @@ -248,6 +251,8 @@ function Instance(Model, opts) { for (i = 0; i < opts.id.length; i++) { conditions[opts.id[i]] = data[opts.id[i]]; } + changes = Utilities.transformPropertyNames(changes, Model.allProperties); + opts.driver.update(opts.table, changes, conditions, function (err) { if (err) { return saveError(cb, err); diff --git a/lib/Model.js b/lib/Model.js index f84e91f8..b1921680 100644 --- a/lib/Model.js +++ b/lib/Model.js @@ -110,7 +110,8 @@ function Model(opts) { many_associations : many_associations, extend_associations : extend_associations, association_properties : association_properties, - setupAssociations : setupAssociations + setupAssociations : setupAssociations, + fieldToPropertyMap : fieldToPropertyMap }); instance.on("ready", function (err) { if (--pending > 0) { @@ -143,18 +144,6 @@ 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; @@ -299,7 +288,7 @@ function Model(opts) { return cb(new ORMError("Not found", 'NOT_FOUND', { model: opts.table })); } - data = mapDatastoreFieldsToProperties(data[0]); + Utilities.renameDatastoreFieldsToPropertyNames(data[0], fieldToPropertyMap); var uid = opts.driver.uid + "/" + opts.table + "/" + ids.join("/"); @@ -307,7 +296,7 @@ function Model(opts) { cache : (options.hasOwnProperty("cache") ? options.cache : opts.cache), save_check : opts.settings.get("instance.cacheSaveCheck") }, function (cb) { - return createInstance(data, { + return createInstance(data[0], { uid : uid, autoSave : options.autoSave, autoFetch : (options.autoFetchLimit === 0 ? false : options.autoFetch), @@ -399,12 +388,15 @@ function Model(opts) { order : order, merge : merge, offset : options.offset, + properties : allProperties, 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]]; } + Utilities.renameDatastoreFieldsToPropertyNames(data, fieldToPropertyMap); + Singleton.get(uid, { cache : options.cache, save_check : opts.settings.get("instance.cacheSaveCheck") @@ -495,12 +487,12 @@ function Model(opts) { model.aggregate = function () { var conditions = {}; - var properties = []; + var propertyList = []; for (var i = 0; i < arguments.length; i++) { if (typeof arguments[i] === "object") { if (Array.isArray(arguments[i])) { - properties = arguments[i]; + propertyList = arguments[i]; } else { conditions = arguments[i]; } @@ -512,11 +504,12 @@ function Model(opts) { } return new require("./AggregateFunctions")({ - table : opts.table, - driver_name : opts.driver_name, - driver : opts.driver, - conditions : conditions, - properties : properties + table : opts.table, + driver_name : opts.driver_name, + driver : opts.driver, + conditions : conditions, + propertyList : propertyList, + properties : allProperties }); }; diff --git a/lib/Utilities.js b/lib/Utilities.js index b5f2a9ae..ce34bf0f 100644 --- a/lib/Utilities.js +++ b/lib/Utilities.js @@ -280,3 +280,56 @@ exports.getRealPath = function (path_str, stack_index) { return path_str; }; + +exports.transformPropertyNames = function (dataIn, properties) { + var k, prop; + var dataOut = {}; + + for (k in dataIn) { + prop = properties[k]; + if (prop) { + dataOut[prop.mapsTo] = dataIn[k]; + } else { + dataOut[k] = dataIn[k]; + } + } + return dataOut; +}; + +exports.transformOrderPropertyNames = function (order, properties) { + if (!order) return order; + + var i, item; + var newOrder = JSON.parse(JSON.stringify(order)); + + // Rename order properties according to mapsTo + for (var i = 0; i < newOrder.length; i++) { + item = newOrder[i]; + + // orderRaw + if (Array.isArray(item[1])) continue; + + if (Array.isArray(item[0])) { + // order on a hasMany + // [ ['modelName', 'propName'], 'Z'] + item[0][1] = properties[item[0][1]].mapsTo; + } else { + // normal order + item[0] = properties[item[0]].mapsTo; + } + } + return newOrder; +} + +exports.renameDatastoreFieldsToPropertyNames = function (data, fieldToPropertyMap) { + var k, prop; + + for (k in data) { + prop = fieldToPropertyMap[k]; + if (prop && prop.name != k) { + data[prop.name] = data[k]; + delete data[k]; + } + } + return data; +} diff --git a/package.json b/package.json index 2ac3af82..0ae682ff 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "sqlite", "mongodb" ], - "version" : "2.1.13", + "version" : "2.1.14", "license" : "MIT", "homepage" : "http://dresende.github.io/node-orm2", "repository" : "http://github.com/dresende/node-orm2.git", diff --git a/test/integration/property-maps-to.js b/test/integration/property-maps-to.js new file mode 100644 index 00000000..c982d470 --- /dev/null +++ b/test/integration/property-maps-to.js @@ -0,0 +1,134 @@ +var _ = require('lodash'); +var should = require('should'); +var helper = require('../support/spec_helper'); +var common = require('../common'); +var ORM = require('../../'); + +if (common.protocol() == "mongodb") return; + +describe("Property.mapsTo", function() { + var db = null; + var Book = null; + var id1 = null, id2 = null; + + before(function (done) { + helper.connect(function (connection) { + db = connection; + db.settings.set('instance.cache', false); + + return done(); + }); + }); + + before(function (done) { + Book = db.define("book", { + title: { type: 'text', mapsTo: 'book_title', required: true }, + pages: { type: 'integer', required: false } + }); + + return helper.dropSync(Book, done); + }); + + after(function () { + return db.close(); + }); + + it("should create", function (done) { + Book.create({ title: "History of the wheel", pages: 297 }, function (err, book) { + should.not.exist(err); + should.exist(book); + should.equal(book.title, "History of the wheel"); + id1 = book.id; + + done() + }); + }); + + it("should save new", function (done) { + book = new Book({ title: "Stuff", pages: 33 }) + book.save(function (err, book) { + should.not.exist(err); + should.exist(book); + should.equal(book.title, "Stuff"); + id2 = book.id; + + done() + }); + }); + + it("should get book1", function (done) { + Book.get(id1, function (err, book) { + should.not.exist(err); + should.exist(book); + should.equal(book.title, "History of the wheel"); + done(); + }); + }); + + it("should get book2", function (done) { + Book.get(id2, function (err, book) { + should.not.exist(err); + should.exist(book); + should.equal(book.title, "Stuff"); + done(); + }); + }); + + it("should find", function (done) { + Book.one({ title: "History of the wheel" }, function (err, book) { + should.not.exist(err); + should.exist(book); + should.equal(book.title, "History of the wheel"); + done(); + }); + }); + + it("should update", function (done) { + Book.one(function (err, book) { + should.not.exist(err); + should.exist(book); + should.equal(book.title, "History of the wheel"); + + book.title = "Quantum theory"; + book.pages = 5; + + book.save(function (err) { + should.not.exist(err); + should.equal(book.title, "Quantum theory"); + + Book.get(book.id, function (err, freshBook) { + should.not.exist(err); + should.exist(freshBook); + should.equal(book.title, "Quantum theory"); + done(); + }); + }); + }); + }); + + it("should order", function (done) { + Book.create({ title: "Zzz", pages: 2 }, function (err) { + should.not.exist(err); + + Book.create({ title: "Aaa", pages: 3 }, function (err) { + should.not.exist(err); + + Book.find().order("-title").all(function (err, items) { + should.not.exist(err); + should.equal( + _.pluck(items, 'title').join(','), + "Zzz,Stuff,Quantum theory,Aaa" + ) + Book.find().order("title").all(function (err, items) { + should.not.exist(err); + should.equal( + _.pluck(items, 'title').join(','), + "Aaa,Quantum theory,Stuff,Zzz" + ) + done(); + }); + }); + }); + }); + }); +});