From c3d7fd0f1c2ea1724e4399f7d101d3c64f7a1802 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Thu, 24 Oct 2013 20:37:43 -0700 Subject: [PATCH 1/3] Create remote functions for predefined scopes/relations --- lib/scope.js | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/scope.js b/lib/scope.js index 50d4b481..e65f748a 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -20,6 +20,7 @@ function defineScope(cls, targetClass, name, params, methods) { } } + // Define a property for the scope Object.defineProperty(cls, name, { enumerable: false, configurable: true, @@ -80,6 +81,44 @@ function defineScope(cls, targetClass, name, params, methods) { } }); + // Wrap the property into a function for remoting + var fn = function() { + var f = this[name]; + f.apply(this, arguments); + }; + + fn.shared = true; + fn.http = {verb: 'get', path: '/' + name}; + fn.accepts = {arg: 'where', type: 'object'}; + fn.description = 'Fetches ' + name; + fn.returns = {arg: name, type: 'array', root: true}; + + cls['__get__' + name] = fn; + + var fn_create = function() { + var f = this[name].create; + f.apply(this, arguments); + }; + + fn_create.shared = true; + fn_create.http = {verb: 'post', path: '/' + name}; + fn_create.accepts = {arg: 'data', type: 'object', source: 'body'}; + fn_create.description = 'Creates ' + name; + fn_create.returns = {arg: 'data', type: 'object', root: true}; + + cls['__create__' + name] = fn_create; + + var fn_delete = function() { + var f = this[name].destroyAll; + f.apply(this, arguments); + }; + fn_delete.shared = true; + fn_delete.http = {verb: 'delete', path: '/' + name}; + fn_delete.description = 'Deletes ' + name; + fn_delete.returns = {arg: 'data', type: 'object', root: true}; + + cls['__delete__' + name] = fn_delete; + // and it should have create/build methods with binded thisModelNameId param function build(data) { return new targetClass(mergeParams(this._scope, {where:data || {}}).where); From 2ae0fd880421ea442eee820fc865f04ec317804e Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Fri, 25 Oct 2013 16:25:05 -0700 Subject: [PATCH 2/3] Honor the model plural name --- lib/relations.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/relations.js b/lib/relations.js index bb2f520e..2f13cb99 100644 --- a/lib/relations.js +++ b/lib/relations.js @@ -41,8 +41,7 @@ Relation.hasMany = function hasMany(anotherClass, params) { } } } - var methodName = params.as || - i8n.camelize(i8n.pluralize(anotherClass.modelName), true); + var methodName = params.as || i8n.camelize(anotherClass.pluralModelName, true); var fk = params.foreignKey || i8n.camelize(thisClassName + '_id', true); this.relations[methodName] = { From 8ad0194a51f6689c6a8fcb038e8061899fde90f3 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Sun, 27 Oct 2013 12:55:01 -0700 Subject: [PATCH 3/3] Add a relation example following Ruby on Rails active records --- examples/relations.js | 90 +++++++++++++++++++++++++++++++++++++++++++ lib/relations.js | 8 ++-- 2 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 examples/relations.js diff --git a/examples/relations.js b/examples/relations.js new file mode 100644 index 00000000..8501f4ea --- /dev/null +++ b/examples/relations.js @@ -0,0 +1,90 @@ +var DataSource = require('../index').DataSource; +var ds = new DataSource('memory'); + +var Order = ds.createModel('Order', { + customerId: Number, + orderDate: Date +}); + +var Customer = ds.createModel('Customer', { + name: String +}); + +Order.belongsTo(Customer); + +Customer.create({name: 'John'}, function (err, customer) { + Order.create({customerId: customer.id, orderDate: new Date()}, function (err, order) { + order.customer(console.log); + order.customer(true, console.log); + + Customer.create({name: 'Mary'}, function (err, customer2) { + order.customer(customer2); + order.customer(console.log); + }); + }); +}); + + +Customer.hasMany(Order, {as: 'orders', foreignKey: 'customerId'}); + +Customer.create({name: 'Ray'}, function (err, customer) { + Order.create({customerId: customer.id, orderDate: new Date()}, function (err, order) { + customer.orders(console.log); + customer.orders.create({orderDate: new Date()}, console.log); + customer.orders.findById('2', console.log); + customer.orders.destroy('2', console.log); + }); +}); + + +var Physician = ds.createModel('Physician', { + name: String +}); + +var Patient = ds.createModel('Patient', { + name: String +}); + +var Appointment = ds.createModel('Appointment', { + physicianId: Number, + patientId: Number, + appointmentDate: Date +}); + +Appointment.belongsTo(Patient); +Appointment.belongsTo(Physician); + +Physician.hasMany(Patient, {through: Appointment}); +Patient.hasMany(Physician, {through: Appointment}); + +Physician.create({name: 'Smith'}, function (err, physician) { + Patient.create({name: 'Mary'}, function (err, patient) { + Appointment.create({appointmentDate: new Date(), physicianId: physician.id, patientId: patient.id}, + function (err, appt) { + physician.patients(console.log); + patient.physicians(console.log); + }); + }); +}); + + +var Assembly = ds.createModel('Assembly', { + name: String +}); + +var Part = ds.createModel('Part', { + partNumber: String +}); + +Assembly.hasAndBelongsToMany(Part); +Part.hasAndBelongsToMany(Assembly); + +Assembly.create({name: 'car'}, function (err, assembly) { + Part.create({partNumber: 'engine'}, function (err, part) { + assembly.parts.add(part, function(err) { + assembly.parts(console.log); + }); + + }); +}); + diff --git a/lib/relations.js b/lib/relations.js index 2f13cb99..97e46a4d 100644 --- a/lib/relations.js +++ b/lib/relations.js @@ -140,12 +140,14 @@ Relation.hasMany = function hasMany(anotherClass, params) { } function destroy(id, cb) { - this.findById(id, function (err, inst) { + var self = this; + anotherClass.findById(id, function (err, inst) { if (err) return cb(err); - if (inst) { + if (!inst) return cb(new Error('Not found')); + if (inst[fk] && inst[fk].toString() == self.id.toString()) { inst.destroy(cb); } else { - cb(new Error('Not found')); + cb(new Error('Permission denied')); } }); }