From 5c4bc2409e2c06669a05aef4d78fa77a853f4d76 Mon Sep 17 00:00:00 2001 From: Sonali Samantaray Date: Mon, 11 Jul 2016 14:28:33 +0530 Subject: [PATCH 1/6] changes to dao.js and memory.js --- lib/connectors/memory.js | 99 +++ lib/dao.js | 1437 +++++++++++++++++++++----------------- 2 files changed, 902 insertions(+), 634 deletions(-) diff --git a/lib/connectors/memory.js b/lib/connectors/memory.js index 29fe9255e..2aadd1c22 100644 --- a/lib/connectors/memory.js +++ b/lib/connectors/memory.js @@ -792,6 +792,105 @@ Memory.prototype.replaceOrCreate = function(model, data, options, callback) { }); }; +Memory.prototype.upsertWithWhere = function(model,data,options,callback){ + +var self = this; + try { + + var response; + + var element = Object.keys(where)[0]; + + var filter = { + "where": where + }; + + + var response = null; + if (Object.keys(data).length === 0) + response = false; + else + response = true; + + if (!data.hasOwnProperty(element)) { + data[element] = where[element]; + } + + if (response == true) { + + self.all(filter, function (err, models) { + + if (err) { + + callback(err); + } else { + + var idName = idName(Model); + + if (models.length > 1) { + + callback("Error message:" + "Multiple records exists.Upsert can't be performed."); + } else if (models.length == 0 && data.hasOwnProperty(idName)) { + + self.create(data, function (err, results) { + + if (err) + callback(err); + + else { + + callback(null, results); + + } + + + }); + } else if (models.length == 0 && data.hasOwnProperty(idName) == false) { + + callback("Error message: Primary key is not provided in the payload"); + } else if (models.length ==1){ + + + var idName = idName(Model); + + var idVal = models[0][idName]; + + self.findById(idVal, function (err, modelInst) { + if (err) { + + callback(err); + } + else { + + modelInst.updateAttributes(data, function (err, info) { + + if (err) { + + callback(err); + } else { + + callback(null, info); + + } + + + }); + } + }); + } + } + }); + } else + callback("Error Message: Data/payload can't be empty"); + } catch (ex) { + + + callback(ex); + } + + +} + Memory.prototype.transaction = function() { return new Memory(this); }; diff --git a/lib/dao.js b/lib/dao.js index 816ae4a0f..ea8d37a52 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -2,7 +2,6 @@ // Node module: loopback-datasource-juggler // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT - /*! * Module exports class Model */ @@ -68,8 +67,8 @@ function convertSubsetOfPropertiesByType(inst, data) { // Convert the properties by type typedData[key] = inst[key]; if (typeof typedData[key] === 'object' && - typedData[key] !== null && - typeof typedData[key].toObject === 'function') { + typedData[key] !== null && + typeof typedData[key].toObject === 'function') { typedData[key] = typedData[key].toObject(); } } @@ -83,7 +82,8 @@ function convertSubsetOfPropertiesByType(inst, data) { function applyStrictCheck(model, strict, data, inst, cb) { var props = model.definition.properties; var keys = Object.keys(data); - var result = {}, key; + var result = {}, + key; for (var i = 0; i < keys.length; i++) { key = keys[i]; if (props[key]) { @@ -106,11 +106,14 @@ function setIdValue(m, data, value) { function byIdQuery(m, id) { var pk = idName(m); - var query = { where: {}}; + var query = { + where: {} + }; query.where[pk] = id; return query; } + function isWhereByGivenId(Model, where, idValue) { var keys = Object.keys(where); if (keys.length != 1) return false; @@ -251,7 +254,10 @@ DataAccessObject.create = function(data, options, cb) { async.map(data, function(item, done) { self.create(item, options, function(err, result) { // Collect all errors and results - done(null, { err: err, result: result || item }); + done(null, { + err: err, + result: result || item + }); }); }, function(err, results) { if (err) { @@ -329,6 +335,7 @@ DataAccessObject.create = function(data, options, cb) { var _idName = idName(Model); var modelName = Model.modelName; var val = removeUndefined(obj.toObject(true)); + function createCallback(err, id, rev) { if (id) { obj.__data[_idName] = id; @@ -412,7 +419,7 @@ function stillConnecting(dataSource, obj, args) { // promise variant var promiseArgs = Array.prototype.slice.call(args); promiseArgs.callee = args.callee; - var cb = utils.createPromiseCallback(); + var cb = utils.createPromiseCallback(); promiseArgs.push(cb); if (dataSource.ready(obj, promiseArgs)) { return cb.promise; @@ -435,195 +442,197 @@ function stillConnecting(dataSource, obj, args) { // 'upsert' will be used as the name for strong-remoting to keep it backward // compatible for angular SDK DataAccessObject.updateOrCreate = -DataAccessObject.patchOrCreate = -DataAccessObject.upsert = function(data, options, cb) { - var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); - if (connectionPromise) { - return connectionPromise; - } - - if (options === undefined && cb === undefined) { - if (typeof data === 'function') { - // upsert(cb) - cb = data; - data = {}; - } - } else if (cb === undefined) { - if (typeof options === 'function') { - // upsert(data, cb) - cb = options; - options = {}; - } - } - - cb = cb || utils.createPromiseCallback(); - data = data || {}; - options = options || {}; + DataAccessObject.patchOrCreate = + DataAccessObject.upsert = function(data, options, cb) { + var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); + if (connectionPromise) { + return connectionPromise; + } - assert(typeof data === 'object', 'The data argument must be an object'); - assert(typeof options === 'object', 'The options argument must be an object'); - assert(typeof cb === 'function', 'The cb argument must be a function'); + if (options === undefined && cb === undefined) { + if (typeof data === 'function') { + // upsert(cb) + cb = data; + data = {}; + } + } else if (cb === undefined) { + if (typeof options === 'function') { + // upsert(data, cb) + cb = options; + options = {}; + } + } - var hookState = {}; + cb = cb || utils.createPromiseCallback(); + data = data || {}; + options = options || {}; - var self = this; - var Model = this; - var connector = Model.getConnector(); + assert(typeof data === 'object', 'The data argument must be an object'); + assert(typeof options === 'object', 'The options argument must be an object'); + assert(typeof cb === 'function', 'The cb argument must be a function'); - var id = getIdValue(this, data); - if (id === undefined || id === null) { - return this.create(data, options, cb); - } + var hookState = {}; - var context = { - Model: Model, - query: byIdQuery(Model, id), - hookState: hookState, - options: options, - }; - Model.notifyObserversOf('access', context, doUpdateOrCreate); - function doUpdateOrCreate(err, ctx) { - if (err) return cb(err); - var isOriginalQuery = isWhereByGivenId(Model, ctx.query.where, id); - if (connector.updateOrCreate && isOriginalQuery) { var context = { Model: Model, - where: ctx.query.where, - data: data, + query: byIdQuery(Model, id), hookState: hookState, options: options, }; - Model.notifyObserversOf('before save', context, function(err, ctx) { + Model.notifyObserversOf('access', context, doUpdateOrCreate); + + function doUpdateOrCreate(err, ctx) { if (err) return cb(err); - data = ctx.data; - var update = data; - var inst = data; - if (!(data instanceof Model)) { - inst = new Model(data, { applyDefaultValues: false }); - } - update = inst.toObject(false); + var isOriginalQuery = isWhereByGivenId(Model, ctx.query.where, id); + if (connector.updateOrCreate && isOriginalQuery) { + var context = { + Model: Model, + where: ctx.query.where, + data: data, + hookState: hookState, + options: options, + }; + Model.notifyObserversOf('before save', context, function(err, ctx) { + if (err) return cb(err); - Model.applyProperties(update, inst); - Model = Model.lookupModel(update); + data = ctx.data; + var update = data; + var inst = data; + if (!(data instanceof Model)) { + inst = new Model(data, { + applyDefaultValues: false + }); + } + update = inst.toObject(false); - var connector = self.getConnector(); + Model.applyProperties(update, inst); + Model = Model.lookupModel(update); - var doValidate = undefined; - if (options.validate === undefined) { - if (Model.settings.validateUpsert === undefined) { - if (Model.settings.automaticValidation !== undefined) { - doValidate = Model.settings.automaticValidation; - } - } else { - doValidate = Model.settings.validateUpsert; - } - } else { - doValidate = options.validate; - } + var connector = self.getConnector(); - if (doValidate === false) { - callConnector(); - } else { - inst.isValid(function(valid) { - if (!valid) { - if (doValidate) { // backwards compatibility with validateUpsert:undefined - return cb(new ValidationError(inst), inst); + var doValidate = undefined; + if (options.validate === undefined) { + if (Model.settings.validateUpsert === undefined) { + if (Model.settings.automaticValidation !== undefined) { + doValidate = Model.settings.automaticValidation; + } } else { - // TODO(bajtos) Remove validateUpsert:undefined in v3.0 - console.warn('Ignoring validation errors in updateOrCreate():'); - console.warn(' %s', new ValidationError(inst).message); - // continue with updateOrCreate + doValidate = Model.settings.validateUpsert; } + } else { + doValidate = options.validate; } - callConnector(); - }, update, options); - } - function callConnector() { - update = removeUndefined(update); - context = { - Model: Model, - where: ctx.where, - data: update, - currentInstance: inst, - hookState: ctx.hookState, - options: options, - }; - Model.notifyObserversOf('persist', context, function(err) { - if (err) return done(err); - if (connector.updateOrCreate.length === 4) { - connector.updateOrCreate(Model.modelName, update, options, done); + if (doValidate === false) { + callConnector(); } else { - connector.updateOrCreate(Model.modelName, update, done); + inst.isValid(function(valid) { + if (!valid) { + if (doValidate) { // backwards compatibility with validateUpsert:undefined + return cb(new ValidationError(inst), inst); + } else { + // TODO(bajtos) Remove validateUpsert:undefined in v3.0 + console.warn('Ignoring validation errors in updateOrCreate():'); + console.warn(' %s', new ValidationError(inst).message); + // continue with updateOrCreate + } + } + callConnector(); + }, update, options); } - }); - } - function done(err, data, info) { - if (err) return cb(err); - var context = { - Model: Model, - data: data, - isNewInstance: info && info.isNewInstance, - hookState: ctx.hookState, - options: options, - }; - Model.notifyObserversOf('loaded', context, function(err) { - if (err) return cb(err); - var obj; - if (data && !(data instanceof Model)) { - inst._initProperties(data, { persisted: true }); - obj = inst; - } else { - obj = data; + function callConnector() { + update = removeUndefined(update); + context = { + Model: Model, + where: ctx.where, + data: update, + currentInstance: inst, + hookState: ctx.hookState, + options: options, + }; + Model.notifyObserversOf('persist', context, function(err) { + if (err) return done(err); + if (connector.updateOrCreate.length === 4) { + connector.updateOrCreate(Model.modelName, update, options, done); + } else { + connector.updateOrCreate(Model.modelName, update, done); + } + }); } - if (err) { - cb(err, obj); - } else { + + function done(err, data, info) { + if (err) return cb(err); var context = { Model: Model, - instance: obj, - isNewInstance: info ? info.isNewInstance : undefined, - hookState: hookState, + data: data, + isNewInstance: info && info.isNewInstance, + hookState: ctx.hookState, options: options, }; + Model.notifyObserversOf('loaded', context, function(err) { + if (err) return cb(err); - Model.notifyObserversOf('after save', context, function(err) { - cb(err, obj); + var obj; + if (data && !(data instanceof Model)) { + inst._initProperties(data, { + persisted: true + }); + obj = inst; + } else { + obj = data; + } + if (err) { + cb(err, obj); + } else { + var context = { + Model: Model, + instance: obj, + isNewInstance: info ? info.isNewInstance : undefined, + hookState: hookState, + options: options, + }; + + Model.notifyObserversOf('after save', context, function(err) { + cb(err, obj); + }); + } }); } }); - } - }); - } else { - var opts = { notify: false }; - if (ctx.options && ctx.options.transaction) { - opts.transaction = ctx.options.transaction; - } - Model.findOne({ where: ctx.query.where }, opts, function(err, inst) { - if (err) { - return cb(err); - } - if (!isOriginalQuery) { - // The custom query returned from a hook may hide the fact that - // there is already a model with `id` value `data[idName(Model)]` - delete data[idName(Model)]; - } - if (inst) { - inst.updateAttributes(data, options, cb); } else { - Model = self.lookupModel(data); - var obj = new Model(data); - obj.save(options, cb); + var opts = { + notify: false + }; + if (ctx.options && ctx.options.transaction) { + opts.transaction = ctx.options.transaction; + } + Model.findOne({ + where: ctx.query.where + }, opts, function(err, inst) { + if (err) { + return cb(err); + } + if (!isOriginalQuery) { + // The custom query returned from a hook may hide the fact that + // there is already a model with `id` value `data[idName(Model)]` + delete data[idName(Model)]; + } + if (inst) { + inst.updateAttributes(data, options, cb); + } else { + Model = self.lookupModel(data); + var obj = new Model(data); + obj.save(options, cb); + } + }); } - }); - } - } - return cb.promise; -}; + } + return cb.promise; + }; /** * Replace or insert a model instance: replace exiting record if one is found, such that parameter `data.id` matches `id` of model instance; @@ -740,6 +749,7 @@ DataAccessObject.replaceOrCreate = function replaceOrCreate(data, options, cb) { connector.replaceOrCreate(Model.modelName, context.data, options, done); }); } + function done(err, data, info) { if (err) return cb(err); var context = { @@ -754,7 +764,9 @@ DataAccessObject.replaceOrCreate = function replaceOrCreate(data, options, cb) { var obj; if (data && !(data instanceof Model)) { - inst._initProperties(data, { persisted: true }); + inst._initProperties(data, { + persisted: true + }); obj = inst; } else { obj = data; @@ -779,11 +791,15 @@ DataAccessObject.replaceOrCreate = function replaceOrCreate(data, options, cb) { } }); } else { - var opts = { notify: false }; + var opts = { + notify: false + }; if (ctx.options && ctx.options.transaction) { opts.transaction = ctx.options.transaction; } - Model.findOne({ where: ctx.query.where }, opts, function(err, found) { + Model.findOne({ + where: ctx.query.where + }, opts, function(err, found) { if (err) return cb(err); if (!isOriginalQuery) { // The custom query returned from a hook may hide the fact that @@ -828,14 +844,18 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb) // findOrCreate(data); // query will be built from data, and method will return Promise data = query; - query = { where: data }; - } else if (options === undefined && cb === undefined) { + query = { + where: data + }; + } else if (options === undefined && cb === undefined) { if (typeof data === 'function') { // findOrCreate(data, cb); // query will be built from data cb = data; data = query; - query = { where: data }; + query = { + where: data + }; } } else if (cb === undefined) { if (typeof options === 'function') { @@ -846,7 +866,9 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb) } cb = cb || utils.createPromiseCallback(); - query = query || { where: {}}; + query = query || { + where: {} + }; data = data || {}; options = options || {}; @@ -863,6 +885,7 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb) function _findOrCreate(query, data, currentInstance) { var modelName = self.modelName; + function findOrCreateCallback(err, data, created) { var context = { Model: Model, @@ -877,8 +900,11 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb) var obj, Model = self.lookupModel(data); if (data) { - obj = new Model(data, { fields: query.fields, applySetters: false, - persisted: true }); + obj = new Model(data, { + fields: query.fields, + applySetters: false, + persisted: true + }); } if (created) { @@ -1160,13 +1186,19 @@ DataAccessObject.findByIds = function(ids, query, options, cb) { if (isPKMissing(this, cb)) { return cb.promise; } else if (ids.length === 0) { - process.nextTick(function() { cb(null, []); }); + process.nextTick(function() { + cb(null, []); + }); return cb.promise; } - var filter = { where: {}}; + var filter = { + where: {} + }; var pk = idName(this); - filter.where[pk] = { inq: [].concat(ids) }; + filter.where[pk] = { + inq: [].concat(ids) + }; mergeQuery(filter, query || {}); // to know if the result need to be sorted by ids or not @@ -1257,7 +1289,7 @@ DataAccessObject._normalize = function(filter) { } if (isNaN(offset) || offset < 0 || Math.ceil(offset) !== offset) { err = new Error(util.format('The offset/skip parameter %j is not valid', - filter.skip || filter.offset)); + filter.skip || filter.offset)); err.statusCode = 400; throw err; } @@ -1314,7 +1346,7 @@ DataAccessObject._normalize = function(filter) { Object.keys(this.definition.properties), this.settings.strict); } - var handleUndefined = this._getSetting('normalizeUndefinedInQuery'); + var handleUndefined = this._getSetting('normalizeUndefinedInQuery'); // alter configuration of how removeUndefined handles undefined values filter = removeUndefined(filter, handleUndefined); this._coerce(filter.where); @@ -1681,90 +1713,90 @@ DataAccessObject.find = function find(query, options, cb) { var results = []; if (!err && Array.isArray(data)) { async.each(data, function(item, callback) { - var d = item;//data[i]; - var Model = self.lookupModel(d); - if (options.notify === false) { - buildResult(d); - } else { - withNotify(); - } - - function buildResult(data) { - d = data; + var d = item; //data[i]; + var Model = self.lookupModel(d); + if (options.notify === false) { + buildResult(d); + } else { + withNotify(); + } - var ctorOpts = { - fields: query.fields, - applySetters: false, - persisted: true, - }; - var obj = new Model(d, ctorOpts); - - if (query && query.include) { - if (query.collect) { - // The collect property indicates that the query is to return the - // standalone items for a related model, not as child of the parent object - // For example, article.tags - obj = obj.__cachedRelations[query.collect]; - if (obj === null) { - obj = undefined; - } - } else { - // This handles the case to return parent items including the related - // models. For example, Article.find({include: 'tags'}, ...); - // Try to normalize the include - var includes = Inclusion.normalizeInclude(query.include || []); - includes.forEach(function(inc) { - var relationName = inc; - if (utils.isPlainObject(inc)) { - relationName = Object.keys(inc)[0]; - } + function buildResult(data) { + d = data; - // Promote the included model as a direct property - var included = obj.__cachedRelations[relationName]; - if (Array.isArray(included)) { - included = new List(included, null, obj); + var ctorOpts = { + fields: query.fields, + applySetters: false, + persisted: true, + }; + var obj = new Model(d, ctorOpts); + + if (query && query.include) { + if (query.collect) { + // The collect property indicates that the query is to return the + // standalone items for a related model, not as child of the parent object + // For example, article.tags + obj = obj.__cachedRelations[query.collect]; + if (obj === null) { + obj = undefined; } - if (included) obj.__data[relationName] = included; - }); - delete obj.__data.__cachedRelations; + } else { + // This handles the case to return parent items including the related + // models. For example, Article.find({include: 'tags'}, ...); + // Try to normalize the include + var includes = Inclusion.normalizeInclude(query.include || []); + includes.forEach(function(inc) { + var relationName = inc; + if (utils.isPlainObject(inc)) { + relationName = Object.keys(inc)[0]; + } + + // Promote the included model as a direct property + var included = obj.__cachedRelations[relationName]; + if (Array.isArray(included)) { + included = new List(included, null, obj); + } + if (included) obj.__data[relationName] = included; + }); + delete obj.__data.__cachedRelations; + } } - } - if (obj !== undefined) { - results.push(obj); - callback(); - } else { - callback(); + if (obj !== undefined) { + results.push(obj); + callback(); + } else { + callback(); + } } - } - function withNotify() { - context = { - Model: Model, - data: d, - isNewInstance: false, - hookState: hookState, - options: options, - }; + function withNotify() { + context = { + Model: Model, + data: d, + isNewInstance: false, + hookState: hookState, + options: options, + }; - Model.notifyObserversOf('loaded', context, function(err) { - if (err) return callback(err); - buildResult(context.data); - }); - } - }, - function(err) { - if (err) return cb(err); + Model.notifyObserversOf('loaded', context, function(err) { + if (err) return callback(err); + buildResult(context.data); + }); + } + }, + function(err) { + if (err) return cb(err); - if (data && data.countBeforeLimit) { - results.countBeforeLimit = data.countBeforeLimit; - } - if (!supportsGeo && near) { - results = geo.filter(results, near); - } + if (data && data.countBeforeLimit) { + results.countBeforeLimit = data.countBeforeLimit; + } + if (!supportsGeo && near) { + results = geo.filter(results, near); + } - cb(err, results); - }); + cb(err, results); + }); } else { cb(err, data || []); } @@ -1777,7 +1809,7 @@ DataAccessObject.find = function find(query, options, cb) { connector.all(self.modelName, query, allCb); } } else { - var context = { + var context = { Model: this, query: query, hookState: hookState, @@ -1851,126 +1883,130 @@ DataAccessObject.findOne = function findOne(query, options, cb) { * @param {Function} [cb] Callback called with (err, info) */ DataAccessObject.remove = -DataAccessObject.deleteAll = -DataAccessObject.destroyAll = function destroyAll(where, options, cb) { - var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); - if (connectionPromise) { - return connectionPromise; - } + DataAccessObject.deleteAll = + DataAccessObject.destroyAll = function destroyAll(where, options, cb) { + var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); + if (connectionPromise) { + return connectionPromise; + } - var Model = this; - var connector = Model.getConnector(); + var Model = this; + var connector = Model.getConnector(); - assert(typeof connector.destroyAll === 'function', - 'destroyAll() must be implemented by the connector'); + assert(typeof connector.destroyAll === 'function', + 'destroyAll() must be implemented by the connector'); - if (options === undefined && cb === undefined) { - if (typeof where === 'function') { - cb = where; - where = {}; - } - } else if (cb === undefined) { - if (typeof options === 'function') { - cb = options; - options = {}; - } - } + if (options === undefined && cb === undefined) { + if (typeof where === 'function') { + cb = where; + where = {}; + } + } else if (cb === undefined) { + if (typeof options === 'function') { + cb = options; + options = {}; + } + } - cb = cb || utils.createPromiseCallback(); - where = where || {}; - options = options || {}; + cb = cb || utils.createPromiseCallback(); + where = where || {}; + options = options || {}; - assert(typeof where === 'object', 'The where argument must be an object'); - assert(typeof options === 'object', 'The options argument must be an object'); - assert(typeof cb === 'function', 'The cb argument must be a function'); + assert(typeof where === 'object', 'The where argument must be an object'); + assert(typeof options === 'object', 'The options argument must be an object'); + assert(typeof cb === 'function', 'The cb argument must be a function'); - var hookState = {}; + var hookState = {}; - var query = { where: where }; - this.applyScope(query); - where = query.where; + var query = { + where: where + }; + this.applyScope(query); + where = query.where; - var context = { - Model: Model, - where: whereIsEmpty(where) ? {} : where, - hookState: hookState, - options: options, - }; - - if (options.notify === false) { - doDelete(where); - } else { - query = { where: whereIsEmpty(where) ? {} : where }; - var context = { - Model: Model, - query: query, - hookState: hookState, - options: options, - }; - Model.notifyObserversOf('access', context, function(err, ctx) { - if (err) return cb(err); var context = { Model: Model, - where: ctx.query.where, + where: whereIsEmpty(where) ? {} : where, hookState: hookState, options: options, }; - Model.notifyObserversOf('before delete', context, function(err, ctx) { - if (err) return cb(err); - doDelete(ctx.where); - }); - }); - } - function doDelete(where) { - if (whereIsEmpty(where)) { - if (connector.destroyAll.length === 4) { - connector.destroyAll(Model.modelName, {}, options, done); + if (options.notify === false) { + doDelete(where); } else { - connector.destroyAll(Model.modelName, {}, done); - } - } else { - try { - // Support an optional where object - where = removeUndefined(where); - where = Model._coerce(where); - } catch (err) { - return process.nextTick(function() { - cb(err); + query = { + where: whereIsEmpty(where) ? {} : where + }; + var context = { + Model: Model, + query: query, + hookState: hookState, + options: options, + }; + Model.notifyObserversOf('access', context, function(err, ctx) { + if (err) return cb(err); + var context = { + Model: Model, + where: ctx.query.where, + hookState: hookState, + options: options, + }; + Model.notifyObserversOf('before delete', context, function(err, ctx) { + if (err) return cb(err); + doDelete(ctx.where); + }); }); } - if (connector.destroyAll.length === 4) { - connector.destroyAll(Model.modelName, where, options, done); - } else { - connector.destroyAll(Model.modelName, where, done); - } - } + function doDelete(where) { + if (whereIsEmpty(where)) { + if (connector.destroyAll.length === 4) { + connector.destroyAll(Model.modelName, {}, options, done); + } else { + connector.destroyAll(Model.modelName, {}, done); + } + } else { + try { + // Support an optional where object + where = removeUndefined(where); + where = Model._coerce(where); + } catch (err) { + return process.nextTick(function() { + cb(err); + }); + } - function done(err, info) { - if (err) return cb(err); + if (connector.destroyAll.length === 4) { + connector.destroyAll(Model.modelName, where, options, done); + } else { + connector.destroyAll(Model.modelName, where, done); + } + } - if (options.notify === false) { - return cb(err, info); - } + function done(err, info) { + if (err) return cb(err); - var context = { - Model: Model, - where: where, - hookState: hookState, - options: options, - }; - Model.notifyObserversOf('after delete', context, function(err) { - cb(err, info); - }); - } - } - return cb.promise; -}; + if (options.notify === false) { + return cb(err, info); + } + + var context = { + Model: Model, + where: where, + hookState: hookState, + options: options, + }; + Model.notifyObserversOf('after delete', context, function(err) { + cb(err, info); + }); + } + } + return cb.promise; + }; function whereIsEmpty(where) { return !where || - (typeof where === 'object' && Object.keys(where).length === 0); + (typeof where === 'object' && Object.keys(where).length === 0); } /** @@ -1984,53 +2020,53 @@ function whereIsEmpty(where) { // 'deleteById' will be used as the name for strong-remoting to keep it backward // compatible for angular SDK DataAccessObject.removeById = -DataAccessObject.destroyById = -DataAccessObject.deleteById = function deleteById(id, options, cb) { - var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); - if (connectionPromise) { - return connectionPromise; - } + DataAccessObject.destroyById = + DataAccessObject.deleteById = function deleteById(id, options, cb) { + var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); + if (connectionPromise) { + return connectionPromise; + } - assert(arguments.length >= 1, 'The id argument is required'); - if (cb === undefined) { - if (typeof options === 'function') { - // destroyById(id, cb) - cb = options; - options = {}; - } - } + assert(arguments.length >= 1, 'The id argument is required'); + if (cb === undefined) { + if (typeof options === 'function') { + // destroyById(id, cb) + cb = options; + options = {}; + } + } - options = options || {}; - cb = cb || utils.createPromiseCallback(); + options = options || {}; + cb = cb || utils.createPromiseCallback(); - assert(typeof options === 'object', 'The options argument must be an object'); - assert(typeof cb === 'function', 'The cb argument must be a function'); + assert(typeof options === 'object', 'The options argument must be an object'); + assert(typeof cb === 'function', 'The cb argument must be a function'); - if (isPKMissing(this, cb)) { - return cb.promise; - } else if (id == null || id === '') { - process.nextTick(function() { - cb(new Error('Model::deleteById requires the id argument')); - }); - return cb.promise; - } + if (isPKMissing(this, cb)) { + return cb.promise; + } else if (id == null || id === '') { + process.nextTick(function() { + cb(new Error('Model::deleteById requires the id argument')); + }); + return cb.promise; + } - var Model = this; + var Model = this; - this.remove(byIdQuery(this, id).where, options, function(err, info) { - if (err) return cb(err); - var deleted = info && info.count > 0; - if (Model.settings.strictDelete && !deleted) { - err = new Error('No instance with id ' + id + ' found for ' + Model.modelName); - err.code = 'NOT_FOUND'; - err.statusCode = 404; - return cb(err); - } + this.remove(byIdQuery(this, id).where, options, function(err, info) { + if (err) return cb(err); + var deleted = info && info.count > 0; + if (Model.settings.strictDelete && !deleted) { + err = new Error('No instance with id ' + id + ' found for ' + Model.modelName); + err.code = 'NOT_FOUND'; + err.statusCode = 404; + return cb(err); + } - cb(null, info); - }); - return cb.promise; -}; + cb(null, info); + }); + return cb.promise; + }; /** * Return count of matched records. Optional query parameter allows you to count filtered set of model instances. @@ -2083,7 +2119,9 @@ DataAccessObject.count = function(where, options, cb) { var hookState = {}; - var query = { where: where }; + var query = { + where: where + }; this.applyScope(query); where = query.where; @@ -2099,7 +2137,9 @@ DataAccessObject.count = function(where, options, cb) { var context = { Model: Model, - query: { where: where }, + query: { + where: where + }, hookState: hookState, options: options, }; @@ -2148,7 +2188,7 @@ DataAccessObject.prototype.save = function(options, cb) { if (isPKMissing(Model, cb)) { return cb.promise; - } else if (this.isNewRecord()) { + } else if (this.isNewRecord()) { return Model.create(this, options, cb); } @@ -2206,6 +2246,7 @@ DataAccessObject.prototype.save = function(options, cb) { inst.trigger('save', function(saveDone) { inst.trigger('update', function(updateDone) { data = removeUndefined(data); + function saveCallback(err, unusedData, result) { if (err) { return cb(err, inst); @@ -2221,7 +2262,9 @@ DataAccessObject.prototype.save = function(options, cb) { Model.notifyObserversOf('loaded', context, function(err) { if (err) return cb(err); - inst._initProperties(data, { persisted: true }); + inst._initProperties(data, { + persisted: true + }); var context = { Model: Model, @@ -2283,94 +2326,110 @@ DataAccessObject.prototype.save = function(options, cb) { * @param {Function} cb Callback, called with (err, info) */ DataAccessObject.update = -DataAccessObject.updateAll = function(where, data, options, cb) { - var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); - if (connectionPromise) { - return connectionPromise; - } + DataAccessObject.updateAll = function(where, data, options, cb) { + var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); + if (connectionPromise) { + return connectionPromise; + } - assert(arguments.length >= 1, 'At least one argument is required'); + assert(arguments.length >= 1, 'At least one argument is required'); - if (data === undefined && options === undefined && cb === undefined && arguments.length === 1) { - data = where; - where = {}; - } else if (options === undefined && cb === undefined) { - // One of: - // updateAll(data, cb) - // updateAll(where, data) -> Promise - if (typeof data === 'function') { - cb = data; + if (data === undefined && options === undefined && cb === undefined && arguments.length === 1) { data = where; where = {}; + } else if (options === undefined && cb === undefined) { + // One of: + // updateAll(data, cb) + // updateAll(where, data) -> Promise + if (typeof data === 'function') { + cb = data; + data = where; + where = {}; + } + } else if (cb === undefined) { + // One of: + // updateAll(where, data, options) -> Promise + // updateAll(where, data, cb) + if (typeof options === 'function') { + cb = options; + options = {}; + } } - } else if (cb === undefined) { - // One of: - // updateAll(where, data, options) -> Promise - // updateAll(where, data, cb) - if (typeof options === 'function') { - cb = options; - options = {}; - } - } - data = data || {}; - options = options || {}; - cb = cb || utils.createPromiseCallback(); + data = data || {}; + options = options || {}; + cb = cb || utils.createPromiseCallback(); - assert(typeof where === 'object', 'The where argument must be an object'); - assert(typeof data === 'object', 'The data argument must be an object'); - assert(typeof options === 'object', 'The options argument must be an object'); - assert(typeof cb === 'function', 'The cb argument must be a function'); + assert(typeof where === 'object', 'The where argument must be an object'); + assert(typeof data === 'object', 'The data argument must be an object'); + assert(typeof options === 'object', 'The options argument must be an object'); + assert(typeof cb === 'function', 'The cb argument must be a function'); - var Model = this; - var connector = Model.getDataSource().connector; - assert(typeof connector.update === 'function', - 'update() must be implemented by the connector'); + var Model = this; + var connector = Model.getDataSource().connector; + assert(typeof connector.update === 'function', + 'update() must be implemented by the connector'); - var hookState = {}; + var hookState = {}; - var query = { where: where }; - this.applyScope(query); - this.applyProperties(data); + var query = { + where: where + }; + this.applyScope(query); + this.applyProperties(data); - where = query.where; + where = query.where; - var context = { - Model: Model, - query: { where: where }, - hookState: hookState, - options: options, - }; - Model.notifyObserversOf('access', context, function(err, ctx) { - if (err) return cb(err); var context = { Model: Model, - where: ctx.query.where, - data: data, + query: { + where: where + }, hookState: hookState, options: options, }; - Model.notifyObserversOf('before save', context, - function(err, ctx) { - if (err) return cb(err); - doUpdate(ctx.where, ctx.data); - }); - }); + Model.notifyObserversOf('access', context, function(err, ctx) { + if (err) return cb(err); + var context = { + Model: Model, + where: ctx.query.where, + data: data, + hookState: hookState, + options: options, + }; + Model.notifyObserversOf('before save', context, + function(err, ctx) { + if (err) return cb(err); + doUpdate(ctx.where, ctx.data); + }); + }); - function doUpdate(where, data) { - try { - where = removeUndefined(where); - where = Model._coerce(where); - data = removeUndefined(data); - data = Model._coerce(data); - } catch (err) { - return process.nextTick(function() { - cb(err); - }); - } + function doUpdate(where, data) { + try { + where = removeUndefined(where); + where = Model._coerce(where); + data = removeUndefined(data); + data = Model._coerce(data); + } catch (err) { + return process.nextTick(function() { + cb(err); + }); + } - function updateCallback(err, info) { - if (err) return cb (err); + function updateCallback(err, info) { + if (err) return cb(err); + + var context = { + Model: Model, + where: where, + data: data, + hookState: hookState, + options: options, + }; + Model.notifyObserversOf('after save', context, function(err, ctx) { + return cb(err, info); + }); + } var context = { Model: Model, @@ -2379,30 +2438,18 @@ DataAccessObject.updateAll = function(where, data, options, cb) { hookState: hookState, options: options, }; - Model.notifyObserversOf('after save', context, function(err, ctx) { - return cb(err, info); + Model.notifyObserversOf('persist', context, function(err, ctx) { + if (err) return cb(err); + + if (connector.update.length === 5) { + connector.update(Model.modelName, where, data, options, updateCallback); + } else { + connector.update(Model.modelName, where, data, updateCallback); + } }); } - - var context = { - Model: Model, - where: where, - data: data, - hookState: hookState, - options: options, - }; - Model.notifyObserversOf('persist', context, function(err, ctx) { - if (err) return cb (err); - - if (connector.update.length === 5) { - connector.update(Model.modelName, where, data, options, updateCallback); - } else { - connector.update(Model.modelName, where, data, updateCallback); - } - }); - } - return cb.promise; -}; + return cb.promise; + }; DataAccessObject.prototype.isNewRecord = function() { return !this.__persisted; @@ -2480,7 +2527,9 @@ DataAccessObject.prototype.remove = // A hook modified the query, it is no longer // a simple 'delete model with the given id'. // We must switch to full query-based delete. - Model.deleteAll(where, { notify: false }, function(err, info) { + Model.deleteAll(where, { + notify: false + }, function(err, info) { if (err) return cb(err, false); var deleted = info && info.count > 0; if (Model.settings.strictDelete && !deleted) { @@ -2626,19 +2675,21 @@ DataAccessObject.replaceById = function(id, data, options, cb) { options = options || {}; assert((typeof data === 'object') && (data !== null), - 'The data argument must be an object'); + 'The data argument must be an object'); assert(typeof options === 'object', 'The options argument must be an object'); assert(typeof cb === 'function', 'The cb argument must be a function'); var connector = this.getConnector(); assert(typeof connector.replaceById === 'function', - 'replaceById() must be implemented by the connector'); + 'replaceById() must be implemented by the connector'); var pkName = idName(this); if (!data[pkName]) data[pkName] = id; var Model = this; - var inst = new Model(data, { persisted: true }); + var inst = new Model(data, { + persisted: true + }); var enforced = {}; this.applyProperties(enforced, inst); inst.setAttributes(enforced); @@ -2654,9 +2705,11 @@ DataAccessObject.replaceById = function(id, data, options, cb) { if (id !== data[pkName]) { var err = new Error('id property (' + pkName + ') ' + - 'cannot be updated from ' + id + ' to ' + data[pkName]); + 'cannot be updated from ' + id + ' to ' + data[pkName]); err.statusCode = 400; - process.nextTick(function() { cb(err); }); + process.nextTick(function() { + cb(err); + }); return cb.promise; } @@ -2783,192 +2836,308 @@ DataAccessObject.replaceById = function(id, data, options, cb) { * @param {Function} cb Callback function called with (err, instance) */ DataAccessObject.prototype.updateAttributes = -DataAccessObject.prototype.patchAttributes = -function(data, options, cb) { - var self = this; + DataAccessObject.prototype.patchAttributes = + function(data, options, cb) { + var self = this; + var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); + if (connectionPromise) { + return connectionPromise; + } + + if (options === undefined && cb === undefined) { + if (typeof data === 'function') { + // updateAttributes(cb) + cb = data; + data = undefined; + } + } else if (cb === undefined) { + if (typeof options === 'function') { + // updateAttributes(data, cb) + cb = options; + options = {}; + } + } + + cb = cb || utils.createPromiseCallback(); + options = options || {}; + + assert((typeof data === 'object') && (data !== null), + 'The data argument must be an object'); + assert(typeof options === 'object', 'The options argument must be an object'); + assert(typeof cb === 'function', 'The cb argument must be a function'); + + var inst = this; + var Model = this.constructor; + var connector = inst.getConnector(); + assert(typeof connector.updateAttributes === 'function', + 'updateAttributes() must be implemented by the connector'); + + if (isPKMissing(Model, cb)) + return cb.promise; + + var allowExtendedOperators = connector.settings && + connector.settings.allowExtendedOperators; + + var strict = this.__strict; + var model = Model.modelName; + var hookState = {}; + + // Convert the data to be plain object so that update won't be confused + if (data instanceof Model) { + data = data.toObject(false); + } + data = removeUndefined(data); + + // Make sure id(s) cannot be changed + var idNames = Model.definition.idNames(); + for (var i = 0, n = idNames.length; i < n; i++) { + var idName = idNames[i]; + if (data[idName] !== undefined && !idEquals(data[idName], inst[idName])) { + var err = new Error('id property (' + idName + ') ' + + 'cannot be updated from ' + inst[idName] + ' to ' + data[idName]); + err.statusCode = 400; + process.nextTick(function() { + cb(err); + }); + return cb.promise; + } + } + + var context = { + Model: Model, + where: byIdQuery(Model, getIdValue(Model, inst)).where, + data: data, + currentInstance: inst, + hookState: hookState, + options: options, + }; + + Model.notifyObserversOf('before save', context, function(err, ctx) { + if (err) return cb(err); + data = ctx.data; + + if (strict && !allowExtendedOperators) { + applyStrictCheck(self.constructor, strict, data, inst, validateAndSave); + } else { + validateAndSave(null, data); + } + + function validateAndSave(err, data) { + if (err) return cb(err); + data = removeUndefined(data); + var doValidate = true; + if (options.validate === undefined) { + if (Model.settings.automaticValidation !== undefined) { + doValidate = Model.settings.automaticValidation; + } + } else { + doValidate = options.validate; + } + + // update instance's properties + inst.setAttributes(data); + + if (doValidate) { + inst.isValid(function(valid) { + if (!valid) { + cb(new ValidationError(inst), inst); + return; + } + + triggerSave(); + }, data, options); + } else { + triggerSave(); + } + + function triggerSave() { + inst.trigger('save', function(saveDone) { + inst.trigger('update', function(done) { + copyData(data, inst); + var typedData = convertSubsetOfPropertiesByType(inst, data); + context.data = typedData; + + function updateAttributesCallback(err) { + if (err) return cb(err); + var ctx = { + Model: Model, + data: context.data, + hookState: hookState, + options: options, + }; + Model.notifyObserversOf('loaded', ctx, function(err) { + if (err) return cb(err); + + inst.__persisted = true; + + // By default, the instance passed to updateAttributes callback is NOT updated + // with the changes made through persist/loaded hooks. To preserve + // backwards compatibility, we introduced a new setting updateOnLoad, + // which if set, will apply these changes to the model instance too. + if (Model.settings.updateOnLoad) { + inst.setAttributes(ctx.data); + } + done.call(inst, function() { + saveDone.call(inst, function() { + if (err) return cb(err, inst); + + var context = { + Model: Model, + instance: inst, + isNewInstance: false, + hookState: hookState, + options: options, + }; + Model.notifyObserversOf('after save', context, function(err) { + cb(err, inst); + }); + }); + }); + }); + } + + var ctx = { + Model: Model, + where: byIdQuery(Model, getIdValue(Model, inst)).where, + data: context.data, + currentInstance: inst, + isNewInstance: false, + hookState: hookState, + options: options, + }; + Model.notifyObserversOf('persist', ctx, function(err) { + if (connector.updateAttributes.length === 5) { + connector.updateAttributes(model, getIdValue(inst.constructor, inst), + inst.constructor._forDB(context.data), options, updateAttributesCallback); + } else { + connector.updateAttributes(model, getIdValue(inst.constructor, inst), + inst.constructor._forDB(context.data), updateAttributesCallback); + } + }); + }, data, cb); + }, data, cb); + } + } + }); + return cb.promise; + }; +/** + * Performs upsert based on the instance that matches the where clause + . This is a PUT operation and based on + * non-primary key. The filter takes one key value pair and updates single matching instance.* + */ + + +DataAccessObject.upsertWithWhere = function(where, data, options, cb) { + var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); if (connectionPromise) { return connectionPromise; } - - if (options === undefined && cb === undefined) { + assert(arguments.length >= 1, 'At least one argument is required'); + if (data === undefined && options === undefined && cb === undefined && arguments.length === 1) { + data = where; + where = {}; + } else if (options === undefined && cb === undefined) { if (typeof data === 'function') { - // updateAttributes(cb) cb = data; - data = undefined; + data = where; + where = {}; } } else if (cb === undefined) { if (typeof options === 'function') { - // updateAttributes(data, cb) cb = options; options = {}; } } - - cb = cb || utils.createPromiseCallback(); + data = data || {}; options = options || {}; - - assert((typeof data === 'object') && (data !== null), - 'The data argument must be an object'); + cb = cb || utils.createPromiseCallback(); + assert(typeof where === 'object', 'The where argument must be an object'); + assert(typeof data === 'object', 'The data argument must be an object'); assert(typeof options === 'object', 'The options argument must be an object'); assert(typeof cb === 'function', 'The cb argument must be a function'); - - var inst = this; - var Model = this.constructor; - var connector = inst.getConnector(); - assert(typeof connector.updateAttributes === 'function', - 'updateAttributes() must be implemented by the connector'); - - if (isPKMissing(Model, cb)) - return cb.promise; - - var allowExtendedOperators = connector.settings && - connector.settings.allowExtendedOperators; - - var strict = this.__strict; - var model = Model.modelName; var hookState = {}; + var self = this; + var Model=this; + var connector = Model.getConnector(); - // Convert the data to be plain object so that update won't be confused - if (data instanceof Model) { - data = data.toObject(false); - } - data = removeUndefined(data); - - // Make sure id(s) cannot be changed - var idNames = Model.definition.idNames(); - for (var i = 0, n = idNames.length; i < n; i++) { - var idName = idNames[i]; - if (data[idName] !== undefined && !idEquals(data[idName], inst[idName])) { - var err = new Error('id property (' + idName + ') ' + - 'cannot be updated from ' + inst[idName] + ' to ' + data[idName]); - err.statusCode = 400; - process.nextTick(function() { - cb(err); - }); - return cb.promise; - } - } + var element = Object.keys(where)[0]; + console.log(element); - var context = { - Model: Model, - where: byIdQuery(Model, getIdValue(Model, inst)).where, - data: data, - currentInstance: inst, - hookState: hookState, - options: options, + var filter = { + "where": where }; - Model.notifyObserversOf('before save', context, function(err, ctx) { - if (err) return cb(err); - data = ctx.data; - - if (strict && !allowExtendedOperators) { - applyStrictCheck(self.constructor, strict, data, inst, validateAndSave); - } else { - validateAndSave(null, data); + if (Object.keys(data).length != 0) { + if (!data.hasOwnProperty(element)) { + data[element] = where[element]; } - function validateAndSave(err, data) { - if (err) return cb(err); - data = removeUndefined(data); - var doValidate = true; - if (options.validate === undefined) { - if (Model.settings.automaticValidation !== undefined) { - doValidate = Model.settings.automaticValidation; - } - } else { - doValidate = options.validate; - } + var pk = idName(Model); - // update instance's properties - inst.setAttributes(data); + self.find(filter, function (err, instances) { - if (doValidate) { - inst.isValid(function(valid) { - if (!valid) { - cb(new ValidationError(inst), inst); - return; - } + var modelsLength = instances.length; + console.log("modelsLength", modelsLength); + if (modelsLength === 0 && data.hasOwnProperty(pk)) { + return self.create(data, options, cb); + } - triggerSave(); - }, data, options); - } else { - triggerSave(); + else if (modelsLength == 0 && data.hasOwnProperty(pk) == false) { + + cb("Error message: No matching instance found. Found error while trying to create a new instance.Primary key is not provided in the payload"); } - function triggerSave() { - inst.trigger('save', function(saveDone) { - inst.trigger('update', function(done) { - copyData(data, inst); - var typedData = convertSubsetOfPropertiesByType(inst, data); - context.data = typedData; + else if (modelsLength === 1) { + var pkName = idName(Model); + console.log("idName", pkName); + var idVal = instances[0][pkName]; + self.findById(idVal, function (err, modelInst) { + if (err) { + cb(err); + } + else { - function updateAttributesCallback(err) { - if (err) return cb(err); - var ctx = { - Model: Model, - data: context.data, - hookState: hookState, - options: options, - }; - Model.notifyObserversOf('loaded', ctx, function(err) { - if (err) return cb(err); + modelInst.updateAttributes(data, function (err, info) { - inst.__persisted = true; + if (err) { - // By default, the instance passed to updateAttributes callback is NOT updated - // with the changes made through persist/loaded hooks. To preserve - // backwards compatibility, we introduced a new setting updateOnLoad, - // which if set, will apply these changes to the model instance too. - if (Model.settings.updateOnLoad) { - inst.setAttributes(ctx.data); - } - done.call(inst, function() { - saveDone.call(inst, function() { - if (err) return cb(err, inst); - - var context = { - Model: Model, - instance: inst, - isNewInstance: false, - hookState: hookState, - options: options, - }; - Model.notifyObserversOf('after save', context, function(err) { - cb(err, inst); - }); - }); - }); - }); - } - var ctx = { - Model: Model, - where: byIdQuery(Model, getIdValue(Model, inst)).where, - data: context.data, - currentInstance: inst, - isNewInstance: false, - hookState: hookState, - options: options, - }; - Model.notifyObserversOf('persist', ctx, function(err) { - if (connector.updateAttributes.length === 5) { - connector.updateAttributes(model, getIdValue(inst.constructor, inst), - inst.constructor._forDB(context.data), options, updateAttributesCallback); + cb(err); } else { - connector.updateAttributes(model, getIdValue(inst.constructor, inst), - inst.constructor._forDB(context.data), updateAttributesCallback); + + cb(null, info); + } + + }); - }, data, cb); - }, data, cb); + + } + + }); + + } + + + else { + + cb("There are multiple instances found.Upsert Operation can't be performed "); } - }); - return cb.promise; -}; + }); + } + + + +else +{ +cb("data field can't be empty"); +} + +} /** * Reload object from persistence * Requires `id` member of `object` to be able to call `find` From 6027d5ecdbc6c225e0be7873ea27af1bd4edaed2 Mon Sep 17 00:00:00 2001 From: mountain1234585 Date: Tue, 12 Jul 2016 15:57:33 +0530 Subject: [PATCH 2/6] Changes to pick up connector implemented method for upsertWithWhere --- lib/dao.js | 104 +++++++++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 46 deletions(-) diff --git a/lib/dao.js b/lib/dao.js index ea8d37a52..cbac864a8 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -3060,82 +3060,94 @@ DataAccessObject.upsertWithWhere = function(where, data, options, cb) { var hookState = {}; var self = this; var Model=this; + + var connector = Model.getConnector(); - var element = Object.keys(where)[0]; - console.log(element); - var filter = { - "where": where - }; + var modelObject = connector._models; + var modelName = Object.keys(modelObject)[0]; - if (Object.keys(data).length != 0) { - if (!data.hasOwnProperty(element)) { - data[element] = where[element]; - } - var pk = idName(Model); + if(connector.upsertWithWhere) { - self.find(filter, function (err, instances) { + return connector.upsertWithWhere(modelName,where,data,cb); - var modelsLength = instances.length; - console.log("modelsLength", modelsLength); - if (modelsLength === 0 && data.hasOwnProperty(pk)) { - return self.create(data, options, cb); - } + } +else { + var element = Object.keys(where)[0]; - else if (modelsLength == 0 && data.hasOwnProperty(pk) == false) { - cb("Error message: No matching instance found. Found error while trying to create a new instance.Primary key is not provided in the payload"); + var filter = { + "where": where + }; + + if (Object.keys(data).length != 0) { + if (!data.hasOwnProperty(element)) { + data[element] = where[element]; } - else if (modelsLength === 1) { - var pkName = idName(Model); - console.log("idName", pkName); - var idVal = instances[0][pkName]; - self.findById(idVal, function (err, modelInst) { - if (err) { - cb(err); - } - else { + var pk = idName(Model); - modelInst.updateAttributes(data, function (err, info) { + self.find(filter, function (err, instances) { - if (err) { + var modelsLength = instances.length; + if (modelsLength === 0 && data.hasOwnProperty(pk)) { + return self.create(data, options, cb); + } - cb(err); - } else { + else if (modelsLength == 0 && data.hasOwnProperty(pk) == false) { - cb(null, info); + cb("Error message: No matching instance found. Found error while trying to create a new instance.Primary key is not provided in the payload"); + } - } + else if (modelsLength === 1) { + var pkName = idName(Model); + var idVal = instances[0][pkName]; + self.findById(idVal, function (err, modelInst) { + if (err) { + cb(err); + } + else { - }); + modelInst.updateAttributes(data, function (err, info) { - } + if (err) { - }); + cb(err); + } else { - } + cb(null, info); + } - else { - cb("There are multiple instances found.Upsert Operation can't be performed "); - } - }); + }); - } + } + }); -else -{ -cb("data field can't be empty"); -} + } + + + else { + + cb("There are multiple instances found.Upsert Operation can't be performed "); + } + }); + + } + + + else { + cb("data field can't be empty"); + } + } } /** From f2453ab85bea986f8ef0979b3c4c9ce99d644b44 Mon Sep 17 00:00:00 2001 From: mountain1234585 Date: Tue, 12 Jul 2016 18:26:32 +0530 Subject: [PATCH 3/6] Removed the code for upsertWithWhere from memory.js dao.js handles the logic. --- memory.js | 905 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 905 insertions(+) create mode 100644 memory.js diff --git a/memory.js b/memory.js new file mode 100644 index 000000000..cf59fc4e7 --- /dev/null +++ b/memory.js @@ -0,0 +1,905 @@ +// Copyright IBM Corp. 2013,2016. All Rights Reserved. +// Node module: loopback-datasource-juggler +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT +var util = require('util'); +var Connector = require('loopback-connector').Connector; +var geo = require('../geo'); +var utils = require('../utils'); +var fs = require('fs'); +var async = require('async'); + +/** + * Initialize the Memory connector against the given data source + * + * @param {DataSource} dataSource The loopback-datasource-juggler dataSource + * @param {Function} [callback] The callback function + */ +exports.initialize = function initializeDataSource(dataSource, callback) { + dataSource.connector = new Memory(null, dataSource.settings); + dataSource.connector.connect(callback); +}; + +exports.Memory = Memory; +exports.applyFilter = applyFilter; + +function Memory(m, settings) { + if (m instanceof Memory) { + this.isTransaction = true; + this.cache = m.cache; + this.ids = m.ids; + this.constructor.super_.call(this, 'memory', settings); + this._models = m._models; + } else { + this.isTransaction = false; + this.cache = {}; + this.ids = {}; + this.constructor.super_.call(this, 'memory', settings); + } +} + +util.inherits(Memory, Connector); + +Memory.prototype.getDefaultIdType = function() { + return Number; +}; + +Memory.prototype.getTypes = function() { + return ['db', 'nosql', 'memory']; +}; + +Memory.prototype.connect = function(callback) { + if (this.isTransaction) { + this.onTransactionExec = callback; + } else { + this.loadFromFile(callback); + } +}; + +function serialize(obj) { + if (obj === null || obj === undefined) { + return obj; + } + return JSON.stringify(obj); +} + +function deserialize(dbObj) { + if (dbObj === null || dbObj === undefined) { + return dbObj; + } + if (typeof dbObj === 'string') { + return JSON.parse(dbObj); + } else { + return dbObj; + } +} + +Memory.prototype.getCollection = function(model) { + var modelClass = this._models[model]; + if (modelClass && modelClass.settings.memory) { + model = modelClass.settings.memory.collection || model; + } + return model; +}; + +Memory.prototype.initCollection = function(model) { + this.collection(model, {}); + this.collectionSeq(model, 1); +}; + +Memory.prototype.collection = function(model, val) { + model = this.getCollection(model); + if (arguments.length > 1) this.cache[model] = val; + return this.cache[model]; +}; + +Memory.prototype.collectionSeq = function(model, val) { + model = this.getCollection(model); + if (arguments.length > 1) this.ids[model] = val; + return this.ids[model]; +}; + +Memory.prototype.loadFromFile = function(callback) { + var self = this; + var hasLocalStorage = typeof window !== 'undefined' && window.localStorage; + var localStorage = hasLocalStorage && this.settings.localStorage; + + if (self.settings.file) { + fs.readFile(self.settings.file, { + encoding: 'utf8', + flag: 'r' + }, function(err, data) { + if (err && err.code !== 'ENOENT') { + callback && callback(err); + } else { + parseAndLoad(data); + } + }); + } else if (localStorage) { + var data = window.localStorage.getItem(localStorage); + data = data || '{}'; + parseAndLoad(data); + } else { + process.nextTick(callback); + } + + function parseAndLoad(data) { + if (data) { + try { + data = JSON.parse(data.toString()); + } catch (e) { + return callback(e); + } + + self.ids = data.ids || {}; + self.cache = data.models || {}; + } else { + if (!self.cache) { + self.ids = {}; + self.cache = {}; + } + } + callback && callback(); + } +}; + +/*! + * Flush the cache into the json file if necessary + * @param {Function} callback + */ +Memory.prototype.saveToFile = function(result, callback) { + var self = this; + var file = this.settings.file; + var hasLocalStorage = typeof window !== 'undefined' && window.localStorage; + var localStorage = hasLocalStorage && this.settings.localStorage; + if (file) { + if (!self.writeQueue) { + // Create a queue for writes + self.writeQueue = async.queue(function(task, cb) { + // Flush out the models/ids + var data = JSON.stringify({ + ids: self.ids, + models: self.cache, + }, null, ' '); + + fs.writeFile(self.settings.file, data, function(err) { + cb(err); + task.callback && task.callback(err, task.data); + }); + }, 1); + } + // Enqueue the write + self.writeQueue.push({ + data: result, + callback: callback, + }); + } else if (localStorage) { + // Flush out the models/ids + var data = JSON.stringify({ + ids: self.ids, + models: self.cache, + }, null, ' '); + window.localStorage.setItem(localStorage, data); + process.nextTick(function() { + callback && callback(null, result); + }); + } else { + process.nextTick(function() { + callback && callback(null, result); + }); + } +}; + +Memory.prototype.define = function defineModel(definition) { + this.constructor.super_.prototype.define.apply(this, [].slice.call(arguments)); + var m = definition.model.modelName; + if (!this.collection(m)) this.initCollection(m); +}; + +Memory.prototype._createSync = function(model, data, fn) { + // FIXME: [rfeng] We need to generate unique ids based on the id type + // FIXME: [rfeng] We don't support composite ids yet + var currentId = this.collectionSeq(model); + if (currentId === undefined) { // First time + currentId = this.collectionSeq(model, 1); + } + var id = this.getIdValue(model, data) || currentId; + if (id > currentId) { + // If the id is passed in and the value is greater than the current id + currentId = id; + } + this.collectionSeq(model, Number(currentId) + 1); + + var props = this._models[model].properties; + var idName = this.idName(model); + id = (props[idName] && props[idName].type && props[idName].type(id)) || id; + this.setIdValue(model, data, id); + if (!this.collection(model)) { + this.collection(model, {}); + } + + if (this.collection(model)[id]) + return fn(new Error('Duplicate entry for ' + model + '.' + idName)); + + this.collection(model)[id] = serialize(data); + fn(null, id); +}; + +Memory.prototype.create = function create(model, data, options, callback) { + var self = this; + this._createSync(model, data, function(err, id) { + if (err) { + return process.nextTick(function() { + callback(err); + }); + }; + self.saveToFile(id, callback); + }); +}; + +Memory.prototype.updateOrCreate = function(model, data, options, callback) { + var self = this; + this.exists(model, self.getIdValue(model, data), options, function(err, exists) { + if (exists) { + self.save(model, data, options, function(err, data) { + callback(err, data, { + isNewInstance: false + }); + }); + } else { + self.create(model, data, options, function(err, id) { + self.setIdValue(model, data, id); + callback(err, data, { + isNewInstance: true + }); + }); + } + }); +}; + +Memory.prototype.findOrCreate = function(model, filter, data, callback) { + var self = this; + var nodes = self._findAllSkippingIncludes(model, filter); + var found = nodes[0]; + + if (!found) { + // Calling _createSync to update the collection in a sync way and to guarantee to create it in the same turn of even loop + return self._createSync(model, data, function(err, id) { + if (err) return callback(err); + self.saveToFile(id, function(err, id) { + self.setIdValue(model, data, id); + callback(err, data, true); + }); + }); + } + + if (!filter || !filter.include) { + return process.nextTick(function() { + callback(null, found, false); + }); + } + + self._models[model].model.include(nodes[0], filter.include, {}, function(err, nodes) { + process.nextTick(function() { + if (err) return callback(err); + callback(null, nodes[0], false); + }); + }); +}; + +Memory.prototype.save = function save(model, data, options, callback) { + var self = this; + var id = this.getIdValue(model, data); + var cachedModels = this.collection(model); + var modelData = cachedModels && this.collection(model)[id]; + modelData = modelData && deserialize(modelData); + if (modelData) { + data = merge(modelData, data); + } + this.collection(model)[id] = serialize(data); + this.saveToFile(data, function(err) { + callback(err, self.fromDb(model, data), { + isNewInstance: !modelData + }); + }); +}; + +Memory.prototype.exists = function exists(model, id, options, callback) { + process.nextTick(function() { + callback(null, this.collection(model) && this.collection(model).hasOwnProperty(id)); + }.bind(this)); +}; + +Memory.prototype.find = function find(model, id, options, callback) { + process.nextTick(function() { + callback(null, id in this.collection(model) && this.fromDb(model, this.collection(model)[id])); + }.bind(this)); +}; + +Memory.prototype.destroy = function destroy(model, id, options, callback) { + var exists = this.collection(model)[id]; + delete this.collection(model)[id]; + this.saveToFile({ + count: exists ? 1 : 0 + }, callback); +}; + +Memory.prototype.fromDb = function(model, data) { + if (!data) return null; + data = deserialize(data); + var props = this._models[model].properties; + for (var key in data) { + var val = data[key]; + if (val === undefined || val === null) { + continue; + } + if (props[key]) { + switch (props[key].type.name) { + case 'Date': + val = new Date(val.toString().replace(/GMT.*$/, 'GMT')); + break; + case 'Boolean': + val = Boolean(val); + break; + case 'Number': + val = Number(val); + break; + } + } + data[key] = val; + } + return data; +}; + +function getValue(obj, path) { + if (obj == null) { + return undefined; + } + var keys = path.split('.'); + var val = obj; + for (var i = 0, n = keys.length; i < n; i++) { + val = val[keys[i]]; + if (val == null) { + return val; + } + } + return val; +} + +Memory.prototype._findAllSkippingIncludes = function(model, filter) { + var nodes = Object.keys(this.collection(model)).map(function(key) { + return this.fromDb(model, this.collection(model)[key]); + }.bind(this)); + + if (filter) { + if (!filter.order) { + var idNames = this.idNames(model); + if (idNames && idNames.length) { + filter.order = idNames; + } + } + // do we need some sorting? + if (filter.order) { + var orders = filter.order; + if (typeof filter.order === 'string') { + orders = [filter.order]; + } + orders.forEach(function(key, i) { + var reverse = 1; + var m = key.match(/\s+(A|DE)SC$/i); + if (m) { + key = key.replace(/\s+(A|DE)SC/i, ''); + if (m[1].toLowerCase() === 'de') reverse = -1; + } + orders[i] = { + 'key': key, + 'reverse': reverse + }; + }); + nodes = nodes.sort(sorting.bind(orders)); + } + + var nearFilter = geo.nearFilter(filter.where); + + // geo sorting + if (nearFilter) { + nodes = geo.filter(nodes, nearFilter); + } + + // do we need some filtration? + if (filter.where && nodes) + nodes = nodes.filter(applyFilter(filter)); + + // field selection + if (filter.fields) { + nodes = nodes.map(utils.selectFields(filter.fields)); + } + + // limit/skip + var skip = filter.skip || filter.offset || 0; + var limit = filter.limit || nodes.length; + nodes = nodes.slice(skip, skip + limit); + } + return nodes; + + function sorting(a, b) { + var undefinedA, undefinedB; + + for (var i = 0, l = this.length; i < l; i++) { + var aVal = getValue(a, this[i].key); + var bVal = getValue(b, this[i].key); + undefinedB = bVal === undefined && aVal !== undefined; + undefinedA = aVal === undefined && bVal !== undefined; + + if (undefinedB || aVal > bVal) { + return 1 * this[i].reverse; + } else if (undefinedA || aVal < bVal) { + return -1 * this[i].reverse; + } + } + + return 0; + } +}; + +Memory.prototype.all = function all(model, filter, options, callback) { + var self = this; + var nodes = self._findAllSkippingIncludes(model, filter); + + process.nextTick(function() { + if (filter && filter.include) { + self._models[model].model.include(nodes, filter.include, options, callback); + } else { + callback(null, nodes); + } + }); +}; + +function applyFilter(filter) { + var where = filter.where; + if (typeof where === 'function') { + return where; + } + var keys = Object.keys(where); + return function(obj) { + return keys.every(function(key) { + if (key === 'and' || key === 'or') { + if (Array.isArray(where[key])) { + if (key === 'and') { + return where[key].every(function(cond) { + return applyFilter({ + where: cond + })(obj); + }); + } + if (key === 'or') { + return where[key].some(function(cond) { + return applyFilter({ + where: cond + })(obj); + }); + } + } + } + + var value = getValue(obj, key); + // Support referencesMany and other embedded relations + // Also support array types. Mongo, possibly PostgreSQL + if (Array.isArray(value)) { + var matcher = where[key]; + // The following condition is for the case where we are querying with + // a neq filter, and when the value is an empty array ([]). + if (matcher.neq !== undefined && value.length <= 0) { + return true; + } + return value.some(function(v, i) { + var filter = { + where: {} + }; + filter.where[i] = matcher; + return applyFilter(filter)(value); + }); + } + + if (test(where[key], value)) { + return true; + } + + // If we have a composed key a.b and b would resolve to a property of an object inside an array + // then, we attempt to emulate mongo db matching. Helps for embedded relations + var dotIndex = key.indexOf('.'); + var subValue = obj[key.substring(0, dotIndex)]; + if (dotIndex !== -1 && Array.isArray(subValue)) { + var subFilter = { + where: {} + }; + var subKey = key.substring(dotIndex + 1); + subFilter.where[subKey] = where[key]; + return subValue.some(applyFilter(subFilter)); + } + + return false; + }); + }; + + function toRegExp(pattern) { + if (pattern instanceof RegExp) { + return pattern; + } + var regex = ''; + // Escaping user input to be treated as a literal string within a regular expression + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Writing_a_Regular_Expression_Pattern + pattern = pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1'); + for (var i = 0, n = pattern.length; i < n; i++) { + var char = pattern.charAt(i); + if (char === '\\') { + i++; // Skip to next char + if (i < n) { + regex += pattern.charAt(i); + } + continue; + } else if (char === '%') { + regex += '.*'; + } else if (char === '_') { + regex += '.'; + } else if (char === '.') { + regex += '\\.'; + } else if (char === '*') { + regex += '\\*'; + } else { + regex += char; + } + } + return regex; + } + + function test(example, value) { + if (typeof value === 'string' && (example instanceof RegExp)) { + return value.match(example); + } + + if (example === undefined) { + return undefined; + } + + if (typeof example === 'object' && example !== null) { + if (example.regexp) { + return value ? value.match(example.regexp) : false; + } + + // ignore geo near filter + if (example.near) { + return true; + } + + if (example.inq) { + // if (!value) return false; + for (var i = 0; i < example.inq.length; i++) { + if (example.inq[i] == value) { + return true; + } + } + return false; + } + + if (example.nin) { + for (var i = 0; i < example.nin.length; i++) { + if (example.nin[i] == value) { + return false; + } + } + return true; + } + + if ('neq' in example) { + return compare(example.neq, value) !== 0; + } + + if ('between' in example) { + return (testInEquality({ + gte: example.between[0] + }, value) && + testInEquality({ + lte: example.between[1] + }, value)); + } + + if (example.like || example.nlike) { + var like = example.like || example.nlike; + if (typeof like === 'string') { + like = toRegExp(like); + } + if (example.like) { + return !!new RegExp(like).test(value); + } + + if (example.nlike) { + return !new RegExp(like).test(value); + } + } + + if (testInEquality(example, value)) { + return true; + } + } + // not strict equality + return (example !== null ? example.toString() : example) == + (value != null ? value.toString() : value); + } + + /** + * Compare two values + * @param {*} val1 The 1st value + * @param {*} val2 The 2nd value + * @returns {number} 0: =, positive: >, negative < + * @private + */ + function compare(val1, val2) { + if (val1 == null || val2 == null) { + // Either val1 or val2 is null or undefined + return val1 == val2 ? 0 : NaN; + } + if (typeof val1 === 'number') { + return val1 - val2; + } + if (typeof val1 === 'string') { + return (val1 > val2) ? 1 : ((val1 < val2) ? -1 : (val1 == val2) ? 0 : NaN); + } + if (typeof val1 === 'boolean') { + return val1 - val2; + } + if (val1 instanceof Date) { + var result = val1 - val2; + return result; + } + // Return NaN if we don't know how to compare + return (val1 == val2) ? 0 : NaN; + } + + function testInEquality(example, val) { + if ('gt' in example) { + return compare(val, example.gt) > 0; + } + if ('gte' in example) { + return compare(val, example.gte) >= 0; + } + if ('lt' in example) { + return compare(val, example.lt) < 0; + } + if ('lte' in example) { + return compare(val, example.lte) <= 0; + } + return false; + } +} + +Memory.prototype.destroyAll = function destroyAll(model, where, options, callback) { + var cache = this.collection(model); + var filter = null; + var count = 0; + if (where) { + filter = applyFilter({ + where: where + }); + Object.keys(cache).forEach(function(id) { + if (!filter || filter(this.fromDb(model, cache[id]))) { + count++; + delete cache[id]; + } + }.bind(this)); + } else { + count = Object.keys(cache).length; + this.collection(model, {}); + } + this.saveToFile({ + count: count + }, callback); +}; + +Memory.prototype.count = function count(model, where, options, callback) { + var cache = this.collection(model); + var data = Object.keys(cache); + if (where) { + var filter = { + where: where + }; + data = data.map(function(id) { + return this.fromDb(model, cache[id]); + }.bind(this)); + data = data.filter(applyFilter(filter)); + } + process.nextTick(function() { + callback(null, data.length); + }); +}; + +Memory.prototype.update = + Memory.prototype.updateAll = function updateAll(model, where, data, options, cb) { + var self = this; + var cache = this.collection(model); + var filter = null; + where = where || {}; + filter = applyFilter({ + where: where + }); + + var ids = Object.keys(cache); + var count = 0; + async.each(ids, function(id, done) { + var inst = self.fromDb(model, cache[id]); + if (!filter || filter(inst)) { + count++; + // The id value from the cache is string + // Get the real id from the inst + id = self.getIdValue(model, inst); + self.updateAttributes(model, id, data, options, done); + } else { + process.nextTick(done); + } + }, function(err) { + if (err) return cb(err); + self.saveToFile({ + count: count + }, cb); + }); + }; + +Memory.prototype.updateAttributes = function updateAttributes(model, id, data, options, cb) { + if (!id) { + var err = new Error('You must provide an id when updating attributes!'); + if (cb) { + return cb(err); + } else { + throw err; + } + } + + // Do not modify the data object passed in arguments + data = Object.create(data); + + this.setIdValue(model, data, id); + + var cachedModels = this.collection(model); + var modelData = cachedModels && this.collection(model)[id]; + + if (modelData) { + this.save(model, data, options, cb); + } else { + cb(new Error('Could not update attributes. Object with id ' + id + ' does not exist!')); + } +}; + +Memory.prototype.replaceById = function(model, id, data, options, cb) { + var self = this; + if (!id) { + var err = new Error('You must provide an id when replacing!'); + return process.nextTick(function() { + cb(err); + }); + } + // Do not modify the data object passed in arguments + data = Object.create(data); + this.setIdValue(model, data, id); + var cachedModels = this.collection(model); + var modelData = cachedModels && this.collection(model)[id]; + if (!modelData) { + var msg = 'Could not replace. Object with id ' + id + ' does not exist!'; + return process.nextTick(function() { + cb(new Error(msg)); + }); + } + + var newModelData = {}; + for (var key in data) { + var val = data[key]; + if (typeof val === 'function') { + continue; // Skip methods + } + newModelData[key] = val; + } + + this.collection(model)[id] = serialize(newModelData); + this.saveToFile(newModelData, function(err) { + cb(err, self.fromDb(model, newModelData)); + }); +}; + +Memory.prototype.replaceOrCreate = function(model, data, options, callback) { + var self = this; + var idName = self.idNames(model)[0]; + var idValue = self.getIdValue(model, data); + var filter = { + where: {} + }; + filter.where[idName] = idValue; + var nodes = self._findAllSkippingIncludes(model, filter); + var found = nodes[0]; + + if (!found) { + // Calling _createSync to update the collection in a sync way and + // to guarantee to create it in the same turn of even loop + return self._createSync(model, data, function(err, id) { + if (err) return process.nextTick(function() { + cb(err); + }); + self.saveToFile(id, function(err, id) { + self.setIdValue(model, data, id); + callback(err, self.fromDb(model, data), { + isNewInstance: true + }); + }); + }); + } + var id = self.getIdValue(model, data); + self.collection(model)[id] = serialize(data); + self.saveToFile(data, function(err) { + callback(err, self.fromDb(model, data), { + isNewInstance: false + }); + }); +}; + + + +Memory.prototype.transaction = function() { + return new Memory(this); +}; + +Memory.prototype.exec = function(callback) { + this.onTransactionExec(); + setTimeout(callback, 50); +}; + +Memory.prototype.buildNearFilter = function(filter) { + // noop +}; + +Memory.prototype.automigrate = function(models, cb) { + var self = this; + + if ((!cb) && ('function' === typeof models)) { + cb = models; + models = undefined; + } + // First argument is a model name + if ('string' === typeof models) { + models = [models]; + } + + models = models || Object.keys(self._models); + if (models.length === 0) { + return process.nextTick(cb); + } + + var invalidModels = models.filter(function(m) { + return !(m in self._models); + }); + + if (invalidModels.length) { + return process.nextTick(function() { + cb(new Error('Cannot migrate models not attached to this datasource: ' + + invalidModels.join(' '))); + }); + } + + models.forEach(function(m) { + self.initCollection(m); + }); + if (cb) process.nextTick(cb); +}; + +function merge(base, update) { + if (!base) { + return update; + } + // We cannot use Object.keys(update) if the update is an instance of the model + // class as the properties are defined at the ModelClass.prototype level + for (var key in update) { + var val = update[key]; + if (typeof val === 'function') { + continue; // Skip methods + } + base[key] = val; + } + return base; +} From 3ff049c2b6cf2e49f36b56af1c7b2189f5d06817 Mon Sep 17 00:00:00 2001 From: mountain1234585 Date: Tue, 12 Jul 2016 18:35:07 +0530 Subject: [PATCH 4/6] Removed empty lines from dao.js --- lib/dao.js | 65 +++++++++--------------------------------------------- 1 file changed, 11 insertions(+), 54 deletions(-) diff --git a/lib/dao.js b/lib/dao.js index cbac864a8..b2fb2ead4 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -3059,96 +3059,53 @@ DataAccessObject.upsertWithWhere = function(where, data, options, cb) { assert(typeof cb === 'function', 'The cb argument must be a function'); var hookState = {}; var self = this; - var Model=this; - - + var Model = this; var connector = Model.getConnector(); - - var modelObject = connector._models; var modelName = Object.keys(modelObject)[0]; - - - if(connector.upsertWithWhere) { - - return connector.upsertWithWhere(modelName,where,data,cb); - - } -else { + if (connector.upsertWithWhere) { + return connector.upsertWithWhere(modelName, where, data, cb); + } else { var element = Object.keys(where)[0]; - - var filter = { "where": where }; - if (Object.keys(data).length != 0) { if (!data.hasOwnProperty(element)) { data[element] = where[element]; } - var pk = idName(Model); - - self.find(filter, function (err, instances) { - + self.find(filter, function(err, instances) { var modelsLength = instances.length; - if (modelsLength === 0 && data.hasOwnProperty(pk)) { return self.create(data, options, cb); - } - - else if (modelsLength == 0 && data.hasOwnProperty(pk) == false) { - + } else if (modelsLength == 0 && data.hasOwnProperty(pk) == false) { cb("Error message: No matching instance found. Found error while trying to create a new instance.Primary key is not provided in the payload"); - } - - else if (modelsLength === 1) { + } else if (modelsLength === 1) { var pkName = idName(Model); - var idVal = instances[0][pkName]; - self.findById(idVal, function (err, modelInst) { + self.findById(idVal, function(err, modelInst) { if (err) { cb(err); - } - else { - - modelInst.updateAttributes(data, function (err, info) { - + } else { + modelInst.updateAttributes(data, function(err, info) { if (err) { - - cb(err); } else { - cb(null, info); - } - - }); - } - }); - - } - - else { - cb("There are multiple instances found.Upsert Operation can't be performed "); } }); - - } - - - else { + } else { cb("data field can't be empty"); } } - } /** * Reload object from persistence From e2bc0908f316c9e09100ef11cdc465a13d3c6574 Mon Sep 17 00:00:00 2001 From: mountain1234585 Date: Tue, 12 Jul 2016 20:01:29 +0530 Subject: [PATCH 5/6] fixed elint errors --- lib/connectors/memory.js | 99 ---------------------------------------- 1 file changed, 99 deletions(-) diff --git a/lib/connectors/memory.js b/lib/connectors/memory.js index 2aadd1c22..29fe9255e 100644 --- a/lib/connectors/memory.js +++ b/lib/connectors/memory.js @@ -792,105 +792,6 @@ Memory.prototype.replaceOrCreate = function(model, data, options, callback) { }); }; -Memory.prototype.upsertWithWhere = function(model,data,options,callback){ - -var self = this; - try { - - var response; - - var element = Object.keys(where)[0]; - - var filter = { - "where": where - }; - - - var response = null; - if (Object.keys(data).length === 0) - response = false; - else - response = true; - - if (!data.hasOwnProperty(element)) { - data[element] = where[element]; - } - - if (response == true) { - - self.all(filter, function (err, models) { - - if (err) { - - callback(err); - } else { - - var idName = idName(Model); - - if (models.length > 1) { - - callback("Error message:" + "Multiple records exists.Upsert can't be performed."); - } else if (models.length == 0 && data.hasOwnProperty(idName)) { - - self.create(data, function (err, results) { - - if (err) - callback(err); - - else { - - callback(null, results); - - } - - - }); - } else if (models.length == 0 && data.hasOwnProperty(idName) == false) { - - callback("Error message: Primary key is not provided in the payload"); - } else if (models.length ==1){ - - - var idName = idName(Model); - - var idVal = models[0][idName]; - - self.findById(idVal, function (err, modelInst) { - if (err) { - - callback(err); - } - else { - - modelInst.updateAttributes(data, function (err, info) { - - if (err) { - - callback(err); - } else { - - callback(null, info); - - } - - - }); - } - }); - } - } - }); - } else - callback("Error Message: Data/payload can't be empty"); - } catch (ex) { - - - callback(ex); - } - - -} - Memory.prototype.transaction = function() { return new Memory(this); }; From 32b9da4d002302d2ce55462809fad188e9e9ea58 Mon Sep 17 00:00:00 2001 From: mountain1234585 Date: Tue, 12 Jul 2016 20:54:42 +0530 Subject: [PATCH 6/6] fixed the eslint errors --- lib/dao.js | 310 +++++++++++++++++------------------------------------ 1 file changed, 98 insertions(+), 212 deletions(-) diff --git a/lib/dao.js b/lib/dao.js index b2fb2ead4..c8ccceab6 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -106,14 +106,10 @@ function setIdValue(m, data, value) { function byIdQuery(m, id) { var pk = idName(m); - var query = { - where: {} - }; + var query = { where: {}}; query.where[pk] = id; return query; } - - function isWhereByGivenId(Model, where, idValue) { var keys = Object.keys(where); if (keys.length != 1) return false; @@ -254,10 +250,7 @@ DataAccessObject.create = function(data, options, cb) { async.map(data, function(item, done) { self.create(item, options, function(err, result) { // Collect all errors and results - done(null, { - err: err, - result: result || item - }); + done(null, { err: err, result: result || item }); }); }, function(err, results) { if (err) { @@ -472,9 +465,6 @@ DataAccessObject.updateOrCreate = assert(typeof cb === 'function', 'The cb argument must be a function'); var hookState = {}; - - - var context = { Model: Model, query: byIdQuery(Model, id), @@ -502,9 +492,7 @@ DataAccessObject.updateOrCreate = var update = data; var inst = data; if (!(data instanceof Model)) { - inst = new Model(data, { - applyDefaultValues: false - }); + inst = new Model(data, { applyDefaultValues: false }); } update = inst.toObject(false); @@ -578,16 +566,11 @@ DataAccessObject.updateOrCreate = var obj; if (data && !(data instanceof Model)) { - inst._initProperties(data, { - persisted: true - }); + inst._initProperties(data, { persisted: true }); obj = inst; - } else { - obj = data; - } - if (err) { - cb(err, obj); - } else { + } else { obj = data; } + if (err) cb(err, obj); + else { var context = { Model: Model, instance: obj, @@ -604,26 +587,19 @@ DataAccessObject.updateOrCreate = } }); } else { - var opts = { - notify: false - }; + var opts = { notify: false }; if (ctx.options && ctx.options.transaction) { opts.transaction = ctx.options.transaction; } - Model.findOne({ - where: ctx.query.where - }, opts, function(err, inst) { - if (err) { - return cb(err); - } + Model.findOne({ where: ctx.query.where }, opts, function(err, inst) { + if (err) { return cb(err); } if (!isOriginalQuery) { // The custom query returned from a hook may hide the fact that // there is already a model with `id` value `data[idName(Model)]` delete data[idName(Model)]; } - if (inst) { - inst.updateAttributes(data, options, cb); - } else { + if (inst) inst.updateAttributes(data, options, cb); + else { Model = self.lookupModel(data); var obj = new Model(data); obj.save(options, cb); @@ -764,16 +740,11 @@ DataAccessObject.replaceOrCreate = function replaceOrCreate(data, options, cb) { var obj; if (data && !(data instanceof Model)) { - inst._initProperties(data, { - persisted: true - }); + inst._initProperties(data, { persisted: true }); obj = inst; - } else { - obj = data; - } - if (err) { - cb(err, obj); - } else { + } else { obj = data; } + if (err) cb(err, obj); + else { var context = { Model: Model, instance: obj, @@ -791,15 +762,9 @@ DataAccessObject.replaceOrCreate = function replaceOrCreate(data, options, cb) { } }); } else { - var opts = { - notify: false - }; - if (ctx.options && ctx.options.transaction) { - opts.transaction = ctx.options.transaction; - } - Model.findOne({ - where: ctx.query.where - }, opts, function(err, found) { + var opts = { notify: false }; + if (ctx.options && ctx.options.transaction) { opts.transaction = ctx.options.transaction; } + Model.findOne({ where: ctx.query.where }, opts, function(err, found) { if (err) return cb(err); if (!isOriginalQuery) { // The custom query returned from a hook may hide the fact that @@ -844,18 +809,14 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb) // findOrCreate(data); // query will be built from data, and method will return Promise data = query; - query = { - where: data - }; + query = { where: data }; } else if (options === undefined && cb === undefined) { if (typeof data === 'function') { // findOrCreate(data, cb); // query will be built from data cb = data; data = query; - query = { - where: data - }; + query = { where: data }; } } else if (cb === undefined) { if (typeof options === 'function') { @@ -866,9 +827,7 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb) } cb = cb || utils.createPromiseCallback(); - query = query || { - where: {} - }; + query = query || { where: {}}; data = data || {}; options = options || {}; @@ -903,7 +862,7 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb) obj = new Model(data, { fields: query.fields, applySetters: false, - persisted: true + persisted: true, }); } @@ -1192,13 +1151,9 @@ DataAccessObject.findByIds = function(ids, query, options, cb) { return cb.promise; } - var filter = { - where: {} - }; + var filter = { where: {}}; var pk = idName(this); - filter.where[pk] = { - inq: [].concat(ids) - }; + filter.where[pk] = { inq: [].concat(ids) }; mergeQuery(filter, query || {}); // to know if the result need to be sorted by ids or not @@ -1713,78 +1668,77 @@ DataAccessObject.find = function find(query, options, cb) { var results = []; if (!err && Array.isArray(data)) { async.each(data, function(item, callback) { - var d = item; //data[i]; - var Model = self.lookupModel(d); - if (options.notify === false) { - buildResult(d); - } else { - withNotify(); - } - - function buildResult(data) { - d = data; + var d = item;//data[i]; + var Model = self.lookupModel(d); + if (options.notify === false) { + buildResult(d); + } else { + withNotify(); + } - var ctorOpts = { - fields: query.fields, - applySetters: false, - persisted: true, - }; - var obj = new Model(d, ctorOpts); + function buildResult(data) { + d = data; + var ctorOpts = { + fields: query.fields, + applySetters: false, + persisted: true, + }; + var obj = new Model(d, ctorOpts); - if (query && query.include) { - if (query.collect) { + if (query && query.include) { + if (query.collect) { // The collect property indicates that the query is to return the // standalone items for a related model, not as child of the parent object // For example, article.tags - obj = obj.__cachedRelations[query.collect]; - if (obj === null) { - obj = undefined; - } - } else { + obj = obj.__cachedRelations[query.collect]; + if (obj === null) { + obj = undefined; + } + } else { // This handles the case to return parent items including the related // models. For example, Article.find({include: 'tags'}, ...); // Try to normalize the include - var includes = Inclusion.normalizeInclude(query.include || []); - includes.forEach(function(inc) { - var relationName = inc; - if (utils.isPlainObject(inc)) { - relationName = Object.keys(inc)[0]; - } + var includes = Inclusion.normalizeInclude(query.include || []); + includes.forEach(function(inc) { + var relationName = inc; + if (utils.isPlainObject(inc)) { + relationName = Object.keys(inc)[0]; + } // Promote the included model as a direct property - var included = obj.__cachedRelations[relationName]; - if (Array.isArray(included)) { - included = new List(included, null, obj); - } - if (included) obj.__data[relationName] = included; - }); - delete obj.__data.__cachedRelations; - } + var included = obj.__cachedRelations[relationName]; + if (Array.isArray(included)) { + included = new List(included, null, obj); + } + if (included) obj.__data[relationName] = included; + }); + delete obj.__data.__cachedRelations; } + } - if (obj !== undefined) { - results.push(obj); - callback(); - } else { - callback(); - } + if (obj !== undefined) { + results.push(obj); + callback(); + } else { + callback(); } + } - function withNotify() { - context = { - Model: Model, - data: d, - isNewInstance: false, - hookState: hookState, - options: options, - }; + function withNotify() { + context = { + Model: Model, + data: d, + isNewInstance: false, + hookState: hookState, + options: options, + }; - Model.notifyObserversOf('loaded', context, function(err) { - if (err) return callback(err); - buildResult(context.data); - }); - } - }, + Model.notifyObserversOf('loaded', context, function(err) { + if (err) return callback(err); + buildResult(context.data); + }); + } + }, function(err) { if (err) return cb(err); @@ -1809,7 +1763,7 @@ DataAccessObject.find = function find(query, options, cb) { connector.all(self.modelName, query, allCb); } } else { - var context = { + var context = { Model: this, query: query, hookState: hookState, @@ -1826,48 +1780,6 @@ DataAccessObject.find = function find(query, options, cb) { return cb.promise; }; -/** - * Find one record, same as `find`, but limited to one result. This function returns an object, not a collection. - * - * @param {Object} query Search conditions. See [find](#dataaccessobjectfindquery-callback) for query format. - * For example: `{where: {test: 'me'}}`. - * @param {Object} [options] Options - * @param {Function} cb Callback function called with (err, instance) - */ -DataAccessObject.findOne = function findOne(query, options, cb) { - var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); - if (connectionPromise) { - return connectionPromise; - } - - if (options === undefined && cb === undefined) { - if (typeof query === 'function') { - cb = query; - query = {}; - } - } else if (cb === undefined) { - if (typeof options === 'function') { - cb = options; - options = {}; - } - } - - cb = cb || utils.createPromiseCallback(); - query = query || {}; - options = options || {}; - - assert(typeof query === 'object', 'The query argument must be an object'); - assert(typeof options === 'object', 'The options argument must be an object'); - assert(typeof cb === 'function', 'The cb argument must be a function'); - - query.limit = 1; - this.find(query, options, function(err, collection) { - if (err || !collection || !collection.length > 0) return cb(err, null); - cb(err, collection[0]); - }); - return cb.promise; -}; - /** * Destroy all matching records. * Delete all model instances from data source. Note: destroyAll method does not destroy hooks. @@ -1918,9 +1830,7 @@ DataAccessObject.remove = var hookState = {}; - var query = { - where: where - }; + var query = { where: where }; this.applyScope(query); where = query.where; @@ -1934,9 +1844,7 @@ DataAccessObject.remove = if (options.notify === false) { doDelete(where); } else { - query = { - where: whereIsEmpty(where) ? {} : where - }; + query = { where: whereIsEmpty(where) ? {} : where }; var context = { Model: Model, query: query, @@ -2119,9 +2027,7 @@ DataAccessObject.count = function(where, options, cb) { var hookState = {}; - var query = { - where: where - }; + var query = { where: where }; this.applyScope(query); where = query.where; @@ -2137,9 +2043,7 @@ DataAccessObject.count = function(where, options, cb) { var context = { Model: Model, - query: { - where: where - }, + query: { where: where }, hookState: hookState, options: options, }; @@ -2262,9 +2166,7 @@ DataAccessObject.prototype.save = function(options, cb) { Model.notifyObserversOf('loaded', context, function(err) { if (err) return cb(err); - inst._initProperties(data, { - persisted: true - }); + inst._initProperties(data, { persisted: true }); var context = { Model: Model, @@ -2372,9 +2274,7 @@ DataAccessObject.update = var hookState = {}; - var query = { - where: where - }; + var query = { where: where }; this.applyScope(query); this.applyProperties(data); @@ -2382,9 +2282,7 @@ DataAccessObject.update = var context = { Model: Model, - query: { - where: where - }, + query: { where: where }, hookState: hookState, options: options, }; @@ -2527,9 +2425,7 @@ DataAccessObject.prototype.remove = // A hook modified the query, it is no longer // a simple 'delete model with the given id'. // We must switch to full query-based delete. - Model.deleteAll(where, { - notify: false - }, function(err, info) { + Model.deleteAll(where, { notify: false }, function(err, info) { if (err) return cb(err, false); var deleted = info && info.count > 0; if (Model.settings.strictDelete && !deleted) { @@ -2687,9 +2583,7 @@ DataAccessObject.replaceById = function(id, data, options, cb) { if (!data[pkName]) data[pkName] = id; var Model = this; - var inst = new Model(data, { - persisted: true - }); + var inst = new Model(data, { persisted: true }); var enforced = {}; this.applyProperties(enforced, inst); inst.setAttributes(enforced); @@ -3026,10 +2920,7 @@ DataAccessObject.prototype.updateAttributes = . This is a PUT operation and based on * non-primary key. The filter takes one key value pair and updates single matching instance.* */ - - DataAccessObject.upsertWithWhere = function(where, data, options, cb) { - var connectionPromise = stillConnecting(this.getDataSource(), this, arguments); if (connectionPromise) { return connectionPromise; @@ -3067,9 +2958,7 @@ DataAccessObject.upsertWithWhere = function(where, data, options, cb) { return connector.upsertWithWhere(modelName, where, data, cb); } else { var element = Object.keys(where)[0]; - var filter = { - "where": where - }; + var filter = { 'where': where }; if (Object.keys(data).length != 0) { if (!data.hasOwnProperty(element)) { data[element] = where[element]; @@ -3080,7 +2969,9 @@ DataAccessObject.upsertWithWhere = function(where, data, options, cb) { if (modelsLength === 0 && data.hasOwnProperty(pk)) { return self.create(data, options, cb); } else if (modelsLength == 0 && data.hasOwnProperty(pk) == false) { - cb("Error message: No matching instance found. Found error while trying to create a new instance.Primary key is not provided in the payload"); + cb('Error message: No matching instance found.Found error while trying to create a new instance.' + + 'Primary key' + + 'is not provided in the payload'); } else if (modelsLength === 1) { var pkName = idName(Model); var idVal = instances[0][pkName]; @@ -3097,16 +2988,11 @@ DataAccessObject.upsertWithWhere = function(where, data, options, cb) { }); } }); - } - else { - cb("There are multiple instances found.Upsert Operation can't be performed "); - } + } else cb('There are multiple instances found.Upsert Operation will not be performed'); }); - } else { - cb("data field can't be empty"); - } + } else cb('data field cannot be empty'); } -} +}; /** * Reload object from persistence * Requires `id` member of `object` to be able to call `find`