Merge pull request #1395 from strongloop/fix/api-docs-mixins-validatable
Fix mixin and validatable docs
This commit is contained in:
commit
3b45c76d0f
|
@ -10,7 +10,7 @@ var utils = require('./utils');
|
|||
module.exports = ObserverMixin;
|
||||
|
||||
/**
|
||||
* ObserverMixin class. Use to add observe/notifyObserversOf APIs to other
|
||||
* ObserverMixin class. Use to add observe/notifyObserversOf APIs to other
|
||||
* classes.
|
||||
*
|
||||
* @class ObserverMixin
|
||||
|
@ -20,12 +20,30 @@ function ObserverMixin() {
|
|||
|
||||
/**
|
||||
* Register an asynchronous observer for the given operation (event).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Registers a `before save` observer for a given model.
|
||||
*
|
||||
* ```javascript
|
||||
* MyModel.observe('before save', function filterProperties(ctx, next) {
|
||||
if (ctx.options && ctx.options.skipPropertyFilter) return next();
|
||||
if (ctx.instance) {
|
||||
FILTERED_PROPERTIES.forEach(function(p) {
|
||||
ctx.instance.unsetAttribute(p);
|
||||
});
|
||||
} else {
|
||||
FILTERED_PROPERTIES.forEach(function(p) {
|
||||
delete ctx.data[p];
|
||||
});
|
||||
}
|
||||
next();
|
||||
});
|
||||
* ```
|
||||
*
|
||||
* @param {String} operation The operation name.
|
||||
* @callback {function} listener The listener function. It will be invoked with
|
||||
* `this` set to the model constructor, e.g. `User`.
|
||||
* @param {Object} context Operation-specific context.
|
||||
* @param {function(Error=)} next The callback to call when the observer
|
||||
* has finished.
|
||||
* @end
|
||||
*/
|
||||
ObserverMixin.observe = function(operation, listener) {
|
||||
|
@ -39,6 +57,16 @@ ObserverMixin.observe = function(operation, listener) {
|
|||
|
||||
/**
|
||||
* Unregister an asynchronous observer for the given operation (event).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```javascript
|
||||
* MyModel.removeObserver('before save', function removedObserver(ctx, next) {
|
||||
// some logic user want to apply to the removed observer...
|
||||
next();
|
||||
});
|
||||
* ```
|
||||
*
|
||||
* @param {String} operation The operation name.
|
||||
* @callback {function} listener The listener function.
|
||||
* @end
|
||||
|
@ -54,6 +82,15 @@ ObserverMixin.removeObserver = function(operation, listener) {
|
|||
|
||||
/**
|
||||
* Unregister all asynchronous observers for the given operation (event).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Remove all observers connected to the `before save` operation.
|
||||
*
|
||||
* ```javascript
|
||||
* MyModel.clearObservers('before save');
|
||||
* ```
|
||||
*
|
||||
* @param {String} operation The operation name.
|
||||
* @end
|
||||
*/
|
||||
|
@ -65,10 +102,29 @@ ObserverMixin.clearObservers = function(operation) {
|
|||
|
||||
/**
|
||||
* Invoke all async observers for the given operation(s).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Notify all async observers for the `before save` operation.
|
||||
*
|
||||
* ```javascript
|
||||
* var context = {
|
||||
Model: Model,
|
||||
instance: obj,
|
||||
isNewInstance: true,
|
||||
hookState: hookState,
|
||||
options: options,
|
||||
};
|
||||
* Model.notifyObserversOf('before save', context, function(err) {
|
||||
if (err) return cb(err);
|
||||
// user can specify the logic after the observers have been notified
|
||||
});
|
||||
* ```
|
||||
*
|
||||
* @param {String|String[]} operation The operation name(s).
|
||||
* @param {Object} context Operation-specific context.
|
||||
* @param {function(Error=)} callback The callback to call when all observers
|
||||
* has finished.
|
||||
* @callback {function(Error=)} callback The callback to call when all observers
|
||||
* have finished.
|
||||
*/
|
||||
ObserverMixin.notifyObserversOf = function(operation, context, callback) {
|
||||
var self = this;
|
||||
|
@ -123,19 +179,41 @@ ObserverMixin._notifyBaseObservers = function(operation, context, callback) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Run the given function with before/after observers. It's done in three serial
|
||||
* steps asynchronously:
|
||||
* Run the given function with before/after observers.
|
||||
*
|
||||
* It's done in three serial asynchronous steps:
|
||||
*
|
||||
* - Notify the registered observers under 'before ' + operation
|
||||
* - Execute the function
|
||||
* - Notify the registered observers under 'after ' + operation
|
||||
*
|
||||
* If an error happens, it fails fast and calls the callback with err.
|
||||
* If an error happens, it fails first and calls the callback with err.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```javascript
|
||||
* var context = {
|
||||
Model: Model,
|
||||
instance: obj,
|
||||
isNewInstance: true,
|
||||
hookState: hookState,
|
||||
options: options,
|
||||
};
|
||||
* function work(done) {
|
||||
process.nextTick(function() {
|
||||
done(null, 1);
|
||||
});
|
||||
}
|
||||
* Model.notifyObserversAround('execute', context, work, function(err) {
|
||||
if (err) return cb(err);
|
||||
// user can specify the logic after the observers have been notified
|
||||
});
|
||||
* ```
|
||||
*
|
||||
* @param {String} operation The operation name
|
||||
* @param {Context} context The context object
|
||||
* @param {Function} fn The task to be invoked as fn(done) or fn(context, done)
|
||||
* @param {Function} callback The callback function
|
||||
* @callback {Function} callback The callback function
|
||||
* @returns {*}
|
||||
*/
|
||||
ObserverMixin.notifyObserversAround = function(operation, context, fn, callback) {
|
||||
|
|
437
lib/relations.js
437
lib/relations.js
|
@ -13,7 +13,7 @@ var RelationDefinition = relation.RelationDefinition;
|
|||
module.exports = RelationMixin;
|
||||
|
||||
/**
|
||||
* RelationMixin class. Use to define relationships between models.
|
||||
* RelationMixin class. Use to define relationships between models.
|
||||
*
|
||||
* @class RelationMixin
|
||||
*/
|
||||
|
@ -21,7 +21,7 @@ function RelationMixin() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Define a "one to many" relationship by specifying the model name
|
||||
* Define a "one to many" relationship by specifying the model name.
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
|
@ -50,25 +50,33 @@ function RelationMixin() {
|
|||
* // you can also call the Chapter.create method with the `chapters` property which will build a chapter
|
||||
* // instance and save the it in the data source.
|
||||
* book.chapters.create({name: 'Chapter 2'}, function(err, savedChapter) {
|
||||
* // this callback is optional
|
||||
* // this callback is optional
|
||||
* });
|
||||
*
|
||||
* // Query chapters for the book
|
||||
* book.chapters(function(err, chapters) { // all chapters with bookId = book.id
|
||||
* book.chapters(function(err, chapters) {
|
||||
* // all chapters with bookId = book.id
|
||||
* console.log(chapters);
|
||||
* });
|
||||
*
|
||||
* // Query chapters for the book with a filter
|
||||
* book.chapters({where: {name: 'test'}, function(err, chapters) {
|
||||
* // All chapters with bookId = book.id and name = 'test'
|
||||
* console.log(chapters);
|
||||
* });
|
||||
* });
|
||||
*```
|
||||
* ```
|
||||
*
|
||||
* @param {Object|String} modelTo Model object (or String name of model) to which you are creating the relationship.
|
||||
* @options {Object} parameters Configuration parameters; see below.
|
||||
* @options {Object} params Configuration parameters; see below.
|
||||
* @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
|
||||
* @property {String} foreignKey Property name of foreign key field.
|
||||
* @property {Object} model Model object
|
||||
* @property {String} polymorphic Define a polymorphic relation name.
|
||||
* @property {String} through Name of the through model.
|
||||
* @property {String} keyThrough Property name of the foreign key in the through model.
|
||||
* @property {Object|Function} scope Explicitly define additional scopes.
|
||||
* @property {Boolean} invert Specify if the relation is inverted.
|
||||
* @property {Object} model The model object.
|
||||
*/
|
||||
RelationMixin.hasMany = function hasMany(modelTo, params) {
|
||||
return RelationDefinition.hasMany(this, modelTo, params);
|
||||
|
@ -123,8 +131,12 @@ RelationMixin.hasMany = function hasMany(modelTo, params) {
|
|||
* @param {Class|String} modelTo Model object (or String name of model) to which you are creating the relationship.
|
||||
* @options {Object} params Configuration parameters; see below.
|
||||
* @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
|
||||
* @property {String} primaryKey Property name of primary key field.
|
||||
* @property {String} foreignKey Name of foreign key property.
|
||||
*
|
||||
* @property {Object|Function} scope Explicitly define additional scopes.
|
||||
* @property {Object} properties Properties inherited from the parent object.
|
||||
* @property {Object} options Property level options.
|
||||
* @property {Boolean} options.invertProperties Specify if the properties should be inverted.
|
||||
*/
|
||||
RelationMixin.belongsTo = function(modelTo, params) {
|
||||
return RelationDefinition.belongsTo(this, modelTo, params);
|
||||
|
@ -132,6 +144,7 @@ RelationMixin.belongsTo = function(modelTo, params) {
|
|||
|
||||
/**
|
||||
* A hasAndBelongsToMany relation creates a direct many-to-many connection with another model, with no intervening model.
|
||||
*
|
||||
* For example, if your application includes users and groups, with each group having many users and each user appearing
|
||||
* in many groups, you could declare the models this way:
|
||||
* ```
|
||||
|
@ -155,28 +168,432 @@ RelationMixin.belongsTo = function(modelTo, params) {
|
|||
* ```
|
||||
*
|
||||
* @param {String|Object} modelTo Model object (or String name of model) to which you are creating the relationship.
|
||||
* the relation
|
||||
* @options {Object} params Configuration parameters; see below.
|
||||
* @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
|
||||
* @property {String} foreignKey Property name of foreign key field.
|
||||
* @property {Object} model Model object
|
||||
* @property {String} throughTable The table name of the through model.
|
||||
* @property {String} through Name of the through model.
|
||||
* @property {String} polymorphic Define a polymorphic relation name.
|
||||
* @property {Object|Function} scope Explicitly define additional scopes.
|
||||
* @property {Object} model The model object.
|
||||
*/
|
||||
RelationMixin.hasAndBelongsToMany = function hasAndBelongsToMany(modelTo, params) {
|
||||
return RelationDefinition.hasAndBelongsToMany(this, modelTo, params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Define a "one to one" relationship by specifying the model name.
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
* Supplier.hasOne(Account, {as: 'account', foreignKey: 'supplierId'});
|
||||
* ```
|
||||
*
|
||||
* If the target model doesn’t have a foreign key property, LoopBack will add a property with the same name.
|
||||
*
|
||||
* The type of the property will be the same as the type of the target model’s id property.
|
||||
*
|
||||
* Please note the foreign key property is defined on the target model (in this example, Account).
|
||||
*
|
||||
* If you don’t specify them, then LoopBack derives the relation name and foreign key as follows:
|
||||
* - Relation name: Camel case of the model name, for example, for the “supplier” model the relation is “supplier”.
|
||||
* - Foreign key: The relation name appended with Id, for example, for relation name “supplier” the default foreign key is “supplierId”.
|
||||
*
|
||||
* Build a new account for the supplier with the supplierId to be set to the id of the supplier.
|
||||
* ```js
|
||||
* var supplier = supplier.account.build(data);
|
||||
* ```
|
||||
*
|
||||
* Create a new account for the supplier. If there is already an account, an error will be reported.
|
||||
* ```js
|
||||
* supplier.account.create(data, function(err, account) {
|
||||
* ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Find the supplier's account model.
|
||||
* ```js
|
||||
* supplier.account(function(err, account) {
|
||||
* ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Update the associated account.
|
||||
* ```js
|
||||
* supplier.account.update({balance: 100}, function(err, account) {
|
||||
* ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Remove the account for the supplier.
|
||||
* ```js
|
||||
* supplier.account.destroy(function(err) {
|
||||
* ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param {Object|String} modelTo Model object (or String name of model) to which you are creating the relationship.
|
||||
* @options {Object} params Configuration parameters; see below.
|
||||
* @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
|
||||
* @property {String} primaryKey Property name of primary key field.
|
||||
* @property {String} foreignKey Property name of foreign key field.
|
||||
* @property {String} polymorphic Define a polymorphic relation name.
|
||||
* @property {Object|Function} scope Explicitly define additional scopes.
|
||||
* @property {Object} model The model object.
|
||||
* @property {Object} properties Properties inherited from the parent object.
|
||||
* @property {Function} methods Scoped methods for the given relation.
|
||||
*/
|
||||
RelationMixin.hasOne = function hasOne(modelTo, params) {
|
||||
return RelationDefinition.hasOne(this, modelTo, params);
|
||||
};
|
||||
|
||||
/**
|
||||
* References one or more instances of the target model.
|
||||
*
|
||||
* For example, a Customer model references one or more instances of the Account model.
|
||||
*
|
||||
* Define the relation in the model definition:
|
||||
*
|
||||
* - Definition of Customer model:
|
||||
* ```json
|
||||
* {
|
||||
"name": "Customer",
|
||||
"base": "PersistedModel",
|
||||
"idInjection": true,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"age": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"validations": [],
|
||||
"relations": {
|
||||
"accounts": {
|
||||
"type": "referencesMany",
|
||||
"model": "Account",
|
||||
"foreignKey": "accountIds",
|
||||
"options": {
|
||||
"validate": true,
|
||||
"forceId": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"acls": [],
|
||||
"methods": {}
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* - Definition of Account model:
|
||||
* ```json
|
||||
* {
|
||||
"name": "Account",
|
||||
"base": "PersistedModel",
|
||||
"idInjection": true,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"balance": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"validations": [],
|
||||
"relations": {},
|
||||
"acls": [],
|
||||
"methods": {}
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* On the bootscript, create a customer instance and for that customer instance reference many account instances.
|
||||
*
|
||||
* For example:
|
||||
* ```javascript
|
||||
* var Customer = app.models.Customer;
|
||||
var accounts = [
|
||||
{
|
||||
name: 'Checking',
|
||||
balance: 5000
|
||||
},
|
||||
{
|
||||
name: 'Saving',
|
||||
balance: 2000
|
||||
}
|
||||
];
|
||||
Customer.create({name: 'Mary Smith'}, function(err, customer) {
|
||||
console.log('Customer:', customer);
|
||||
async.each(accounts, function(account, done) {
|
||||
customer.accounts.create(account, done);
|
||||
}, function(err) {
|
||||
console.log('Customer with accounts:', customer);
|
||||
customer.accounts(console.log);
|
||||
cb(err);
|
||||
});
|
||||
});
|
||||
* ```
|
||||
*
|
||||
* Sample referencesMany model data:
|
||||
* ```javascript
|
||||
* {
|
||||
id: 1,
|
||||
name: 'John Smith',
|
||||
accounts: [
|
||||
"saving-01", "checking-01",
|
||||
]
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* Supported helper methods:
|
||||
* - customer.accounts()
|
||||
* - customer.accounts.create()
|
||||
* - customer.accounts.build()
|
||||
* - customer.accounts.findById()
|
||||
* - customer.accounts.destroy()
|
||||
* - customer.accounts.updateById()
|
||||
* - customer.accounts.exists()
|
||||
* - customer.accounts.add()
|
||||
* - customer.accounts.remove()
|
||||
* - customer.accounts.at()
|
||||
*
|
||||
* @param {Object|String} modelTo Model object (or String name of model) to which you are creating the relationship.
|
||||
* @options {Object} params Configuration parameters; see below.
|
||||
* @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
|
||||
* @property {Any} default The default value.
|
||||
* @property {Object} options Options to specify for the relationship.
|
||||
* @property {Boolean} options.forceId Force generation of id for embedded items. Default is false.
|
||||
* @property {Boolean} options.validate Denote if the embedded items should be validated. Default is true.
|
||||
* @property {Boolean} options.persistent Denote if the embedded items should be persisted. Default is false.
|
||||
* @property {Object|Function} scope Explicitly define additional scopes.
|
||||
* @property {String} foreignKey Property name of foreign key field.
|
||||
* @property {Object} properties Properties inherited from the parent object.
|
||||
* @property {Function} methods Scoped methods for the given relation.
|
||||
*/
|
||||
RelationMixin.referencesMany = function referencesMany(modelTo, params) {
|
||||
return RelationDefinition.referencesMany(this, modelTo, params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Represent a model that embeds another model.
|
||||
*
|
||||
* For example, a Customer embeds one billingAddress from the Address model.
|
||||
*
|
||||
* - Define the relation in bootscript:
|
||||
* ```js
|
||||
* Customer.embedsOne(Address, {
|
||||
* as: 'address', // default to the relation name - address
|
||||
* property: 'billingAddress' // default to addressItem
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* OR, define the relation in the model definition:
|
||||
*
|
||||
* - Definition of Customer model:
|
||||
* ```json
|
||||
* {
|
||||
"name": "Customer",
|
||||
"base": "PersistedModel",
|
||||
"idInjection": true,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"age": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"validations": [],
|
||||
"relations": {
|
||||
"address": {
|
||||
"type": "embedsOne",
|
||||
"model": "Address",
|
||||
"property": "billingAddress",
|
||||
"options": {
|
||||
"validate": true,
|
||||
"forceId": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"acls": [],
|
||||
"methods": {}
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* - Definition of Address model:
|
||||
* ```json
|
||||
* {
|
||||
"name": "Address",
|
||||
"base": "Model",
|
||||
"idInjection": true,
|
||||
"properties": {
|
||||
"street": {
|
||||
"type": "string"
|
||||
},
|
||||
"city": {
|
||||
"type": "string"
|
||||
},
|
||||
"state": {
|
||||
"type": "string"
|
||||
},
|
||||
"zipCode": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"validations": [],
|
||||
"relations": {},
|
||||
"acls": [],
|
||||
"methods": {}
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* Sample embedded model data:
|
||||
* ```javascript
|
||||
* {
|
||||
id: 1,
|
||||
name: 'John Smith',
|
||||
billingAddress: {
|
||||
street: '123 Main St',
|
||||
city: 'San Jose',
|
||||
state: 'CA',
|
||||
zipCode: '95124'
|
||||
}
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* Supported helper methods:
|
||||
* - customer.address()
|
||||
* - customer.address.build()
|
||||
* - customer.address.create()
|
||||
* - customer.address.update()
|
||||
* - customer.address.destroy()
|
||||
* - customer.address.value()
|
||||
*
|
||||
* @param {Object|String} modelTo Model object (or String name of model) to which you are creating the relationship.
|
||||
* @options {Object} params Configuration parameters; see below.
|
||||
* @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
|
||||
* @property {String} property Name of the property for the embedded item.
|
||||
* @property {Any} default The default value.
|
||||
* @property {Object} options Options to specify for the relationship.
|
||||
* @property {Boolean} options.forceId Force generation of id for embedded items. Default is false.
|
||||
* @property {Boolean} options.validate Denote if the embedded items should be validated. Default is true.
|
||||
* @property {Boolean} options.persistent Denote if the embedded items should be persisted. Default is false.
|
||||
* @property {Object|Function} scope Explicitly define additional scopes.
|
||||
* @property {Object} properties Properties inherited from the parent object.
|
||||
* @property {Function} methods Scoped methods for the given relation.
|
||||
*/
|
||||
RelationMixin.embedsOne = function embedsOne(modelTo, params) {
|
||||
return RelationDefinition.embedsOne(this, modelTo, params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Represent a model that can embed many instances of another model.
|
||||
*
|
||||
* For example, a Customer can have multiple email addresses and each email address is a complex object that contains label and address.
|
||||
*
|
||||
* Define the relation code in bootscript:
|
||||
* ```javascript
|
||||
Customer.embedsMany(EmailAddress, {
|
||||
as: 'emails', // default to the relation name - emailAddresses
|
||||
property: 'emailList' // default to emailAddressItems
|
||||
});
|
||||
* ```
|
||||
*
|
||||
* OR, define the relation in the model definition:
|
||||
*
|
||||
* - Definition of Customer model:
|
||||
* ```json
|
||||
* {
|
||||
"name": "Customer",
|
||||
"base": "PersistedModel",
|
||||
"idInjection": true,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"age": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"validations": [],
|
||||
"relations": {
|
||||
"emails": {
|
||||
"type": "embedsMany",
|
||||
"model": "EmailAddress",
|
||||
"property": "emailList",
|
||||
"options": {
|
||||
"validate": true,
|
||||
"forceId": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"acls": [],
|
||||
"methods": {}
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* - Definition of EmailAddress model:
|
||||
* ```json
|
||||
* {
|
||||
"name": "EmailAddress",
|
||||
"base": "Model",
|
||||
"idInjection": true,
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"validations": [],
|
||||
"relations": {},
|
||||
"acls": [],
|
||||
"methods": {}
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* Sample embedded model data:
|
||||
* ```javascript
|
||||
* {
|
||||
id: 1,
|
||||
name: 'John Smith',
|
||||
emails: [{
|
||||
label: 'work',
|
||||
address: 'john@xyz.com'
|
||||
}, {
|
||||
label: 'home',
|
||||
address: 'john@gmail.com'
|
||||
}]
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* Supported helper methods:
|
||||
* - customer.emails()
|
||||
* - customer.emails.create()
|
||||
* - customer.emails.build()
|
||||
* - customer.emails.findById()
|
||||
* - customer.emails.destroyById()
|
||||
* - customer.emails.updateById()
|
||||
* - customer.emails.exists()
|
||||
* - customer.emails.add()
|
||||
* - customer.emails.remove()
|
||||
* - customer.emails.at()
|
||||
* - customer.emails.value()
|
||||
*
|
||||
* @param {Object|String} modelTo Model object (or String name of model) to which you are creating the relationship.
|
||||
* @options {Object} params Configuration parameters; see below.
|
||||
* @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
|
||||
* @property {String} property Name of the property for the embedded item.
|
||||
* @property {Any} default The default value.
|
||||
* @property {Object} options Options to specify for the relationship.
|
||||
* @property {Boolean} options.forceId Force generation of id for embedded items. Default is false.
|
||||
* @property {Boolean} options.validate Denote if the embedded items should be validated. Default is true.
|
||||
* @property {Boolean} options.persistent Denote if the embedded items should be persisted. Default is false.
|
||||
* @property {String} polymorphic Define a polymorphic relation name.
|
||||
* @property {Object|Function} scope Explicitly define additional scopes.
|
||||
* @property {Object} properties Properties inherited from the parent object.
|
||||
* @property {Function} methods Scoped methods for the given relation.
|
||||
*/
|
||||
RelationMixin.embedsMany = function embedsMany(modelTo, params) {
|
||||
return RelationDefinition.embedsMany(this, modelTo, params);
|
||||
};
|
||||
|
|
|
@ -24,35 +24,9 @@ function TransactionMixin() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Begin a new transaction
|
||||
* @param {Object|String} [options] Options can be one of the forms:
|
||||
* - Object: {isolationLevel: '...', timeout: 1000}
|
||||
* - String: isolationLevel
|
||||
* Begin a new transaction.
|
||||
*
|
||||
* Valid values of `isolationLevel` are:
|
||||
*
|
||||
* - Transaction.READ_COMMITTED = 'READ COMMITTED'; // default
|
||||
* - Transaction.READ_UNCOMMITTED = 'READ UNCOMMITTED';
|
||||
* - Transaction.SERIALIZABLE = 'SERIALIZABLE';
|
||||
* - Transaction.REPEATABLE_READ = 'REPEATABLE READ';
|
||||
*
|
||||
* @param {Function} cb Callback function. It calls back with (err, transaction).
|
||||
* To pass the transaction context to one of the CRUD methods, use the `options`
|
||||
* argument with `transaction` property, for example,
|
||||
*
|
||||
* ```js
|
||||
*
|
||||
* MyModel.beginTransaction('READ COMMITTED', function(err, tx) {
|
||||
* MyModel.create({x: 1, y: 'a'}, {transaction: tx}, function(err, inst) {
|
||||
* MyModel.find({x: 1}, {transaction: tx}, function(err, results) {
|
||||
* // ...
|
||||
* tx.commit(function(err) {...});
|
||||
* });
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* The transaction can be committed or rolled back. If timeout happens, the
|
||||
* A transaction can be committed or rolled back. If timeout happens, the
|
||||
* transaction will be rolled back. Please note a transaction is typically
|
||||
* associated with a pooled connection. Committing or rolling back a transaction
|
||||
* will release the connection back to the pool.
|
||||
|
@ -65,6 +39,36 @@ function TransactionMixin() {
|
|||
* source/connector instance. CRUD methods will not join the current transaction
|
||||
* if its model is not attached the same data source.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* To pass the transaction context to one of the CRUD methods, use the `options`
|
||||
* argument with `transaction` property, for example,
|
||||
*
|
||||
* ```js
|
||||
* MyModel.beginTransaction('READ COMMITTED', function(err, tx) {
|
||||
* MyModel.create({x: 1, y: 'a'}, {transaction: tx}, function(err, inst) {
|
||||
* MyModel.find({x: 1}, {transaction: tx}, function(err, results) {
|
||||
* // ...
|
||||
* tx.commit(function(err) {...});
|
||||
* });
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param {Object|String} options Options to be passed upon transaction.
|
||||
*
|
||||
* Can be one of the forms:
|
||||
* - Object: {isolationLevel: '...', timeout: 1000}
|
||||
* - String: isolationLevel
|
||||
*
|
||||
* Valid values of `isolationLevel` are:
|
||||
*
|
||||
* - Transaction.READ_COMMITTED = 'READ COMMITTED'; // default
|
||||
* - Transaction.READ_UNCOMMITTED = 'READ UNCOMMITTED';
|
||||
* - Transaction.SERIALIZABLE = 'SERIALIZABLE';
|
||||
* - Transaction.REPEATABLE_READ = 'REPEATABLE READ';
|
||||
* @callback {Function} cb Callback function.
|
||||
* @returns {Promise|undefined} Returns a callback promise.
|
||||
*/
|
||||
TransactionMixin.beginTransaction = function(options, cb) {
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
|
@ -107,9 +111,22 @@ TransactionMixin.beginTransaction = function(options, cb) {
|
|||
if (Transaction) {
|
||||
jutil.mixin(Transaction.prototype, ObserverMixin);
|
||||
/**
|
||||
* Commit a transaction and release it back to the pool
|
||||
* @param {Function} cb Callback function
|
||||
* @returns {Promise|undefined}
|
||||
* Commit a transaction and release it back to the pool.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```js
|
||||
* MyModel.beginTransaction('READ COMMITTED', function(err, tx) {
|
||||
* // some crud operation of your choice
|
||||
* tx.commit(function(err) {
|
||||
* // release the connection pool upon committing
|
||||
* tx.close(err);
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @callback {Function} cb Callback function.
|
||||
* @returns {Promise|undefined} Returns a callback promise.
|
||||
*/
|
||||
Transaction.prototype.commit = function(cb) {
|
||||
var self = this;
|
||||
|
@ -141,9 +158,22 @@ if (Transaction) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Rollback a transaction and release it back to the pool
|
||||
* @param {Function} cb Callback function
|
||||
* @returns {Promise|undefined}
|
||||
* Rollback a transaction and release it back to the pool.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```js
|
||||
* MyModel.beginTransaction('READ COMMITTED', function(err, tx) {
|
||||
* // some crud operation of your choice
|
||||
* tx.rollback(function(err) {
|
||||
* // release the connection pool upon committing
|
||||
* tx.close(err);
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @callback {Function} cb Callback function.
|
||||
* @returns {Promise|undefined} Returns a callback promise.
|
||||
*/
|
||||
Transaction.prototype.rollback = function(cb) {
|
||||
var self = this;
|
||||
|
|
|
@ -32,6 +32,7 @@ function Validatable() {
|
|||
|
||||
/**
|
||||
* Validate presence of one or more specified properties.
|
||||
*
|
||||
* Requires a model to include a property to be considered valid; fails when validated field is blank.
|
||||
*
|
||||
* For example, validate presence of title
|
||||
|
@ -48,34 +49,43 @@ function Validatable() {
|
|||
* ```
|
||||
*
|
||||
* @param {String} propertyName One or more property names.
|
||||
* @options {Object} errMsg Optional custom error message. Default is "can't be blank"
|
||||
* @options {Object} options Configuration parameters; see below.
|
||||
* @property {String} message Error message to use instead of default.
|
||||
* @property {String} if Validate only if `if` exists.
|
||||
* @property {String} unless Validate only if `unless` exists.
|
||||
*/
|
||||
Validatable.validatesPresenceOf = getConfigurator('presence');
|
||||
|
||||
/**
|
||||
* Validate absence of one or more specified properties.
|
||||
* A model should not include a property to be considered valid; fails when validated field not blank.
|
||||
*
|
||||
* A model should not include a property to be considered valid; fails when validated field is not blank.
|
||||
*
|
||||
* For example, validate absence of reserved
|
||||
* ```
|
||||
* Post.validatesAbsenceOf('reserved', { unless: 'special' });
|
||||
* ```
|
||||
*
|
||||
* @param {String} propertyName One or more property names.
|
||||
* @options {Object} errMsg Optional custom error message. Default is "can't be set"
|
||||
* @options {Object} options Configuration parameters; see below.
|
||||
* @property {String} message Error message to use instead of default.
|
||||
* @property {String} if Validate only if `if` exists.
|
||||
* @property {String} unless Validate only if `unless` exists.
|
||||
*/
|
||||
Validatable.validatesAbsenceOf = getConfigurator('absence');
|
||||
|
||||
/**
|
||||
* Validate length. Require a property length to be within a specified range.
|
||||
* Three kinds of validations: min, max, is.
|
||||
* Validate length.
|
||||
*
|
||||
* Require a property length to be within a specified range.
|
||||
*
|
||||
* There are three kinds of validations: min, max, is.
|
||||
*
|
||||
* Default error messages:
|
||||
*
|
||||
* - min: too short
|
||||
* - max: too long
|
||||
* - is: length is wrong
|
||||
* - is: length is wrong
|
||||
*
|
||||
* Example: length validations
|
||||
* ```
|
||||
|
@ -89,36 +99,42 @@ Validatable.validatesAbsenceOf = getConfigurator('absence');
|
|||
* User.validatesLengthOf('password', {min: 7, message: {min: 'too weak'}});
|
||||
* User.validatesLengthOf('state', {is: 2, message: {is: 'is not valid state name'}});
|
||||
* ```
|
||||
*
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @options {Object} Options See below.
|
||||
* @options {Object} options Configuration parameters; see below.
|
||||
* @property {Number} is Value that property must equal to validate.
|
||||
* @property {Number} min Value that property must be less than to be valid.
|
||||
* @property {Number} max Value that property must be less than to be valid.
|
||||
* @property {Object} message Optional Object with string properties for custom error message for each validation: is, min, or max
|
||||
* @property {Object} message Optional object with string properties for custom error message for each validation: is, min, or max.
|
||||
*/
|
||||
Validatable.validatesLengthOf = getConfigurator('length');
|
||||
|
||||
/**
|
||||
* Validate numericality. Requires a value for property to be either an integer or number.
|
||||
* Validate numericality.
|
||||
*
|
||||
* Requires a value for property to be either an integer or number.
|
||||
*
|
||||
* Example
|
||||
* ```
|
||||
* User.validatesNumericalityOf('age', { message: { number: '...' }});
|
||||
* User.validatesNumericalityOf('age', {int: true, message: { int: '...' }});
|
||||
* User.validatesNumericalityOf('age', { message: { number: 'is not a number' }});
|
||||
* User.validatesNumericalityOf('age', {int: true, message: { int: 'is not an integer' }});
|
||||
* ```
|
||||
*
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @options {Object} Options See below.
|
||||
* @options {Object} options Configuration parameters; see below.
|
||||
* @property {Boolean} int If true, then property must be an integer to be valid.
|
||||
* @property {Object} message Optional object with string properties for 'int' for integer validation. Default error messages:
|
||||
*
|
||||
* @property {Boolean} allowBlank Allow property to be blank.
|
||||
* @property {Boolean} allowNull Allow property to be null.
|
||||
* @property {Object} message Optional object with string properties for 'int' for integer validation. Default error messages:
|
||||
* - number: is not a number
|
||||
* - int: is not an integer
|
||||
*/
|
||||
Validatable.validatesNumericalityOf = getConfigurator('numericality');
|
||||
|
||||
/**
|
||||
* Validate inclusion in set. Require a value for property to be in the specified array.
|
||||
* Validate inclusion in set.
|
||||
*
|
||||
* Require a value for property to be in the specified array.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
|
@ -129,8 +145,8 @@ Validatable.validatesNumericalityOf = getConfigurator('numericality');
|
|||
* ```
|
||||
*
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @options {Object} Options See below
|
||||
* @property {Array} inArray Property must match one of the values in the array to be valid.
|
||||
* @options {Object} options Configuration parameters; see below.
|
||||
* @property {Array} in Property must match one of the values in the array to be valid.
|
||||
* @property {String} message Optional error message if property is not valid.
|
||||
* Default error message: "is not included in the list".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
|
@ -138,28 +154,31 @@ Validatable.validatesNumericalityOf = getConfigurator('numericality');
|
|||
Validatable.validatesInclusionOf = getConfigurator('inclusion');
|
||||
|
||||
/**
|
||||
* Validate exclusion. Require a property value not be in the specified array.
|
||||
* Validate exclusion in a set.
|
||||
*
|
||||
* Require a property value not be in the specified array.
|
||||
*
|
||||
* Example: `Company.validatesExclusionOf('domain', {in: ['www', 'admin']});`
|
||||
*
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @options {Object} Options
|
||||
* @options {Object} options Configuration parameters; see below.
|
||||
* @property {Array} in Property must not match any of the values in the array to be valid.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: "is reserved".
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: "is reserved".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
*/
|
||||
Validatable.validatesExclusionOf = getConfigurator('exclusion');
|
||||
|
||||
/**
|
||||
* Validate format. Require a model to include a property that matches the given format.
|
||||
* Validate format.
|
||||
*
|
||||
* Require a model to include a property that matches the given format. Example:
|
||||
* `User.validatesFormatOf('name', {with: /\w+/});`
|
||||
* Require a model to include a property that matches the given format.
|
||||
*
|
||||
* Example: `User.validatesFormatOf('name', {with: /\w+/});`
|
||||
*
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @options {Object} Options
|
||||
* @options {Object} options Configuration parameters; see below.
|
||||
* @property {RegExp} with Regular expression to validate format.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
*/
|
||||
Validatable.validatesFormatOf = getConfigurator('format');
|
||||
|
@ -168,7 +187,7 @@ Validatable.validatesFormatOf = getConfigurator('format');
|
|||
* Validate using custom validation function.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
*```javascript
|
||||
* User.validate('name', customValidator, {message: 'Bad name'});
|
||||
* function customValidator(err) {
|
||||
* if (this.name === 'bad') err();
|
||||
|
@ -177,11 +196,12 @@ Validatable.validatesFormatOf = getConfigurator('format');
|
|||
* user.isValid(); // true
|
||||
* user.name = 'bad';
|
||||
* user.isValid(); // false
|
||||
* ```
|
||||
*
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @param {Function} validatorFn Custom validation function.
|
||||
* @options {Object} Options See below.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
|
||||
* @options {Object} options Configuration parameters; see below.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
*/
|
||||
Validatable.validate = getConfigurator('custom');
|
||||
|
@ -189,7 +209,6 @@ Validatable.validate = getConfigurator('custom');
|
|||
/**
|
||||
* Validate using custom asynchronous validation function.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
*```js
|
||||
* User.validateAsync('name', customValidator, {message: 'Bad name'});
|
||||
|
@ -209,17 +228,19 @@ Validatable.validate = getConfigurator('custom');
|
|||
* user.isValid(function (isValid) {
|
||||
* isValid; // false
|
||||
* })
|
||||
*```
|
||||
* ```
|
||||
*
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @param {Function} validatorFn Custom validation function.
|
||||
* @options {Object} Options See below
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
|
||||
* @options {Object} options Configuration parameters; see below.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
*/
|
||||
Validatable.validateAsync = getConfigurator('custom', {async: true});
|
||||
|
||||
/**
|
||||
* Validate uniqueness. Ensure the value for property is unique in the collection of models.
|
||||
* Validate uniqueness of the value for a property in the collection of models.
|
||||
*
|
||||
* Not available for all connectors. Currently supported with these connectors:
|
||||
* - In Memory
|
||||
* - Oracle
|
||||
|
@ -233,18 +254,33 @@ Validatable.validateAsync = getConfigurator('custom', {async: true});
|
|||
* // The login must be unique within each Site.
|
||||
* SiteUser.validateUniquenessOf('login', { scopedTo: ['siteId'] });
|
||||
* ```
|
||||
|
||||
*
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @options {Object} Options See below.
|
||||
* @options {Object} options Configuration parameters; see below.
|
||||
* @property {RegExp} with Regular expression to validate format.
|
||||
* @property {Array.<String>} scopedTo List of properties defining the scope.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: "is not unique".
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: "is not unique".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
* @property {String} ignoreCase Make the validation case insensitive
|
||||
* @property {String} ignoreCase Make the validation case insensitive.
|
||||
* @property {String} if Validate only if `if` exists.
|
||||
* @property {String} unless Validate only if `unless` exists.
|
||||
*/
|
||||
Validatable.validatesUniquenessOf = getConfigurator('uniqueness', {async: true});
|
||||
|
||||
/**
|
||||
* Validate if a value for a property is a Date.
|
||||
*
|
||||
* Example
|
||||
* ```
|
||||
* User.validatesDateOf('today', {message: 'today is not a date!'});
|
||||
* ```
|
||||
*
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @options {Object} options Configuration parameters; see below.
|
||||
* @property {String} message Error message to use instead of default.
|
||||
*/
|
||||
Validatable.validatesDateOf = getConfigurator('date');
|
||||
|
||||
// implementation of validators
|
||||
|
||||
/*!
|
||||
|
@ -438,15 +474,15 @@ function getConfigurator(name, opts) {
|
|||
* NOTE: This method can be called as synchronous only when no asynchronous validation is
|
||||
* configured. It's strongly recommended to run all validations as asyncronous.
|
||||
*
|
||||
* Example: ExpressJS controller: render user if valid, show flash otherwise
|
||||
* ```
|
||||
* Example: ExpressJS controller - render user if valid, show flash otherwise
|
||||
* ```javascript
|
||||
* user.isValid(function (valid) {
|
||||
* if (valid) res.render({user: user});
|
||||
* else res.flash('error', 'User is not valid'), console.log(user.errors), res.redirect('/users');
|
||||
* });
|
||||
* ```
|
||||
* Another example:
|
||||
* ```
|
||||
* ```javascript
|
||||
* user.isValid(function (valid) {
|
||||
* if (!valid) {
|
||||
* console.log(user.errors);
|
||||
|
@ -458,7 +494,9 @@ function getConfigurator(name, opts) {
|
|||
* }
|
||||
* });
|
||||
* ```
|
||||
* @param {Function} callback called with (valid)
|
||||
* @callback {Function} callback Called with (valid).
|
||||
* @param {Object} data Data to be validated.
|
||||
* @param {Object} options Options to be specified upon validation.
|
||||
* @returns {Boolean} True if no asynchronous validation is configured and all properties pass validation.
|
||||
*/
|
||||
Validatable.prototype.isValid = function(callback, data, options) {
|
||||
|
@ -663,6 +701,7 @@ var defaultMessages = {
|
|||
/**
|
||||
* Checks if attribute is undefined or null. Calls err function with 'blank' or 'null'.
|
||||
* See defaultMessages. You can affect this behaviour with conf.allowBlank and conf.allowNull.
|
||||
* @private
|
||||
* @param {String} attr Property name of attribute
|
||||
* @param {Object} conf conf object for validator
|
||||
* @param {Function} err
|
||||
|
@ -807,6 +846,8 @@ function ErrorCodes(messages) {
|
|||
* callback(err);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function ValidationError(obj) {
|
||||
if (!(this instanceof ValidationError)) return new ValidationError(obj);
|
||||
|
|
Loading…
Reference in New Issue