diff --git a/lib/dao.js b/lib/dao.js index aad2cc6c..99c2fc4a 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -22,12 +22,10 @@ var removeUndefined = utils.removeUndefined; /** * Base class for all persistent objects. * Provides a common API to access any database connector. - * This class describes only abstract behavior. Refer to the specific connector (`lib/connectors/*.js`) for details. + * This class describes only abstract behavior. Refer to the specific connector for additional details. * * `DataAccessObject` mixes `Inclusion` classes methods. - * * @class DataAccessObject - * @param {Object} data Initial object data */ function DataAccessObject() { if (DataAccessObject._mixins) { @@ -39,6 +37,8 @@ function DataAccessObject() { } } + + function idName(m) { return m.getDataSource().idName ? m.getDataSource().idName(m.modelName) : 'id'; @@ -71,15 +71,20 @@ DataAccessObject._forDB = function (data) { }; /** - * Create new instance of Model class, saved in database. - * The callback function is called with arguments: + * Create an instance of Model with given data and save to the attached data source. Callback is optional. + * Example: + *```js + * User.create({first: 'Joe', last: 'Bob'}, function(err, user) { + * console.log(user instanceof User); // true + * }); + * ``` + * Note: You must include a callback and use the created model provided in the callback if your code depends on your model being + * saved or having an ID. * + * @param {Object} data Optional data object + * @param {Function} callback Callback function called with these arguments: * - err (null or Error) * - instance (null or Model) - * - * @param data {Object} Optional data object - * @param callback {Function} Callback function - */ DataAccessObject.create = function (data, callback) { if (stillConnecting(this.getDataSource(), this, arguments)) return; @@ -210,7 +215,10 @@ function stillConnecting(dataSource, obj, args) { } /** - * Update or insert a model instance. + * Update or insert a model instance: update exiting record if one is found, such that parameter `data.id` matches `id` of model instance; + * otherwise, insert a new record. + * + * NOTE: No setters, validations, or hooks are applied when using upsert. * `updateOrCreate` is an alias * @param {Object} data The model instance data * @param {Function} callback The callback function (optional). @@ -269,10 +277,12 @@ setRemoting(DataAccessObject.upsert, { }); /** - * Find one record, same as `all`, limited by 1 and return object, not collection, - * if not found, create using data provided as second argument + * Find one record that matches specified query criteria. Same as `find`, but limited to one record, and this function returns an + * object, not a collection. + * If the specified instance is not found, then create it using data provided as second argument. * - * @param {Object} query Search conditions: {where: {test: 'me'}}. + * @param {Object} query Search conditions. See [find](#dataaccessobjectfindquery-callback) for query format. + * For example: `{where: {test: 'me'}}`. * @param {Object} data Object to create. * @param {Function} cb Callback called with (err, instance) */ @@ -323,7 +333,14 @@ setRemoting(DataAccessObject.exists, { }); /** - * Find object by id + * Find model instance by ID. + * + * Example: + * ```js + * User.findById(23, function(err, user) { + * console.info(user.id); // 23 + * }); + * ``` * * @param {*} id Primary key value * @param {Function} cb Callback called with (err, instance) @@ -477,18 +494,59 @@ DataAccessObject._coerce = function (where) { }; /** - * Find all instances of Model, matched by query - * make sure you have marked as `index: true` fields for filter or sort - * - * @param {Object} [query] the query object - * - * - where: Object `{ key: val, key2: {gt: 'val2'}}` - * - include: String, Object or Array. See `DataAccessObject.include()`. - * - order: String - * - limit: Number - * - skip: Number + * Find all instances of Model that match the specified query. + * Fields used for filter and sort should be declared with `{index: true}` in model definition. + * See [Querying models](http://docs.strongloop.com/display/DOC/Querying+models) for more information. * - * @param {Function} callback (required) called with two arguments: err (null or Error), array of instances + * For example, find the second page of ten users over age 21 in descending order exluding the password property. + * + * ```js + * User.find({ + * where: { + * age: {gt: 21}}, + * order: 'age DESC', + * limit: 10, + * skip: 10, + * fields: {password: false} + * }, + * console.log + * ); + * ``` + * + * @options {Object} [query] Optional JSON object that specifies query criteria and parameters. + * @property {Object} where Search criteria in JSON format `{ key: val, key2: {gt: 'val2'}}`. + * Operations: + * - gt: > + * - gte: >= + * - lt: < + * - lte: <= + * - between + * - inq: IN + * - nin: NOT IN + * - neq: != + * - like: LIKE + * - nlike: NOT LIKE + * + * You can also use `and` and `or` operations. See [Querying models](http://docs.strongloop.com/display/DOC/Querying+models) for more information. + * @property {String|Object|Array} include Allows you to load relations of several objects and optimize numbers of requests. + * Format examples; + * - `'posts'`: Load posts + * - `['posts', 'passports']`: Load posts and passports + * - `{'owner': 'posts'}`: Load owner and owner's posts + * - `{'owner': ['posts', 'passports']}`: Load owner, owner's posts, and owner's passports + * - `{'owner': [{posts: 'images'}, 'passports']}`: Load owner, owner's posts, owner's posts' images, and owner's passports + * See `DataAccessObject.include()`. + * @property {String} order Sort order. Format: `'key1 ASC, key2 DESC'` + * @property {Number} limit Maximum number of instances to return. + * @property {Number} skip Number of instances to skip. + * @property {Number} offset Alias for `skip`. + * @property {Object|Array|String} fields Included/excluded fields. + * - `['foo']` or `'foo'` - include only the foo property + * - `['foo', 'bar']` - include the foo and bar properties. Format: + * - `{foo: true}` - include only foo + * - `{bat: false}` - include all properties, exclude bat + * + * @param {Function} callback Required callback function. Call this function with two arguments: `err` (null or Error) and an array of instances. */ DataAccessObject.find = function find(query, cb) { @@ -613,10 +671,11 @@ setRemoting(DataAccessObject.find, { }); /** - * Find one record, same as `all`, limited by 1 and return object, not collection + * Find one record, same as `find`, but limited to one result. This function returns an object, not a collection. * - * @param {Object} query - search conditions: {where: {test: 'me'}} - * @param {Function} cb - callback called with (err, instance) + * @param {Object} query Sarch conditions. See [find](#dataaccessobjectfindquery-callback) for query format. + * For example: `{where: {test: 'me'}}`. + * @param {Function} cb Callback function called with (err, instance) */ DataAccessObject.findOne = function findOne(query, cb) { if (stillConnecting(this.getDataSource(), this, arguments)) return; @@ -641,8 +700,16 @@ setRemoting(DataAccessObject.findOne, { }); /** - * Destroy all matching records - * @param {Object} [where] An object that defines the criteria + * Destroy all matching records. + * Delete all model instances from data source. Note: destroyAll method does not destroy hooks. + * Example: + *````js + * Product.destroyAll({price: {gt: 99}}, function(err) { + // removed matching products + * }); + * ```` + * + * @param {Object} [where] Optional object that defines the criteria. This is a "where" object. Do NOT pass a filter object. * @param {Function} [cb] Callback called with (err) */ DataAccessObject.remove = DataAccessObject.deleteAll = DataAccessObject.destroyAll = function destroyAll(where, cb) { @@ -697,9 +764,16 @@ setRemoting(DataAccessObject.deleteById, { }); /** - * Return count of matched records + * Return count of matched records. Optional query parameter allows you to count filtered set of model instances. + * Example: + * + *```js + * User.count({approved: true}, function(err, count) { + * console.log(count); // 2081 + * }); + * ``` * - * @param {Object} where Search conditions (optional) + * @param {Object} [where] Search conditions (optional) * @param {Function} cb Callback, called with (err, count) */ DataAccessObject.count = function (where, cb) { diff --git a/lib/relations.js b/lib/relations.js index a18da4e9..81495170 100644 --- a/lib/relations.js +++ b/lib/relations.js @@ -61,8 +61,37 @@ function lookupModel(models, modelName) { * ``` * Book.hasMany('chapters', {model: Chapter}); * ``` - * @param {Relation} anotherClass Class to has many - * @options {Object} parameters Configuration parameters + * + * Query and create related models: + * + * ```js + * Book.create(function(err, book) { + * + * // Create a chapter instance ready to be saved in the data source. + * var chapter = book.chapters.build({name: 'Chapter 1'}); + * + * // Save the new chapter + * chapter.save(); + * + * // 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 + * }); + * + * // Query chapters for the book + * book.chapters(function(err, chapters) { // all chapters with bookId = book.id + * console.log(chapters); + * }); + * + * book.chapters({where: {name: 'test'}, function(err, chapters) { + * // All chapters with bookId = book.id and name = 'test' + * console.log(chapters); + * }); + * }); + *``` + * @param {Object|String} anotherClass Model object (or String name of model) to which you are creating the relationship. + * @options {Object} parameters Configuration parameters; see below. * @property {String} as * @property {String} foreignKey Property name of foreign key field. * @property {Object} model Model object @@ -275,8 +304,8 @@ Relation.hasMany = function hasMany(anotherClass, params) { * ``` * This optional parameter default value is false, so the related object will be loaded from cache if available. * - * @param {Class} anotherClass Class to belong - * @param {Object} Parameters Configuration parameters + * @param {Class|String} anotherClass Model object (or String name of model) to which you are creating the relationship. + * @options {Object} params Configuration parameters; see below. * @property {String} as Can be 'propertyName' * @property {String} foreignKey Name of foreign key property. * @@ -446,11 +475,12 @@ Relation.belongsTo = function (anotherClass, params) { * user.groups.remove(group, callback); * ``` * - * @param {String|Function} anotherClass - target class to hasAndBelongsToMany or name of + * @param {String|Object} anotherClass Model object (or String name of model) to which you are creating the relationship. * the relation - * @options {Object} params - configuration {as: String, foreignKey: *, model: ModelClass} - * @property {Object} model Model name + * @options {Object} params Configuration parameters; see below. + * @property {String} as * @property {String} foreignKey Property name of foreign key field. + * @property {Object} model Model object */ Relation.hasAndBelongsToMany = function hasAndBelongsToMany(anotherClass, params) { params = params || {};