不要怂,就是干,撸起袖子干!

Commit 16dac585 by Jan Aagaard Meier

More work on DAO factory api docs

1 parent 3097bfeb
......@@ -192,6 +192,7 @@ module.exports = (function() {
var newAttributes = {}
newAttributes[this.identifier] = { type: this.options.keyType || DataTypes.INTEGER }
Helpers.addForeignKeyConstraints(newAttributes[this.identifier], this.source, this.target, this.options)
Utils._.defaults(this.target.rawAttributes, newAttributes)
}
......
......@@ -69,20 +69,38 @@ module.exports = (function() {
this.scopeObj = {}
}
/**
* Return a hash of the attributes of the table. Keys are attributes, are values are the SQL representation of their type
* @property attributes
*/
Object.defineProperty(DAOFactory.prototype, 'attributes', {
get: function() {
return this.QueryGenerator.attributesToSQL(this.rawAttributes)
}
})
/**
* A reference to the sequelize instance
* @property sequelize
*/
Object.defineProperty(DAOFactory.prototype, 'sequelize', {
get: function() { return this.daoFactoryManager.sequelize }
})
/**
* A reference to the query interface
* @property QueryInterface
* @see {QueryInterface}
*/
Object.defineProperty(DAOFactory.prototype, 'QueryInterface', {
get: function() { return this.daoFactoryManager.sequelize.getQueryInterface() }
})
/**
* A reference to the query generator
* @property QueryGenerator
* @see {QueryGenerator}
*/
Object.defineProperty(DAOFactory.prototype, 'QueryGenerator', {
get: function() { return this.QueryInterface.QueryGenerator }
})
......@@ -307,7 +325,7 @@ module.exports = (function() {
}
/**
* Sync this DAO to the DB.
* Sync this DAOFactory to the DB, that is create the table.
* @see {Sequelize#sync} for options
* @return {EventEmitter}
*/
......@@ -336,6 +354,11 @@ module.exports = (function() {
}).run()
}
/**
* Drop the table represented by this Model
* @param {Object} [options]
* @param {Boolean} [options.cascade=false] Also drop all objects depending on this table, such as views. Only works in postgres
*/
DAOFactory.prototype.drop = function(options) {
// Only Postgres' QueryGenerator.dropTableQuery() will add schema manually
var isPostgres = this.options.dialect === "postgres" || (!!this.daoFactoryManager && this.daoFactoryManager.sequelize.options.dialect === "postgres")
......@@ -368,6 +391,47 @@ module.exports = (function() {
return this.QueryGenerator.addSchema(this)
}
/**
* Apply a scope created in `define` to the model. First let's look at how to create scopes:
* ```js
* var Model = sequelize.define('model', {
* attributes
* }, {
* defaultScope: {
* where: {
* username: 'dan'
* },
* limit: 12
* },
* scopes: {
* isALie: {
* where: {
* stuff: 'cake'
* }
* },
* complexFunction: function(email, accessLevel) {
* return {
* where: ['email like ? AND access_level >= ?', email + '%', accessLevel]
* }
* },
* }
* })
* ```
* Now, since you defined a default scope, every time you do Model.find, the default scope is appended to your query. Here's a couple of examples:
* ```js
* Model.findAll() // WHERE username = 'dan'
* Model.findAll({ where: { age: { gt: 12 } } }) // WHERE age > 12 AND username = 'dan'
* ```
*
* To invoke scope functions you can do:
* ```js
* Model.scope({ method: ['complexFunction' 'dan@sequelize.com', 42]})
* // WHERE email like 'dan@sequelize.com%' AND access_level >= 42
* ```
*
* @param {Array|Object|String|null} option* The scope(s) to apply. Scopes can either be passed as consecutive arguments, or as an array of arguments. To apply simple scopes, pass them as strings. For scope function, pass an object, with a `method` property. The value can either be a string, if the method does not take any arguments, or an array, where the first element is the name of the method, and consecutive elements are arguments to that method. Pass null to remove all scopes, including the default.
* @return {DAOFactory} A reference to the model, with the scope(s) applied. Calling scope again on the returned model will clear the previous scope.
*/
DAOFactory.prototype.scope = function(option) {
var self = Object.create(this)
, type
......@@ -450,11 +514,86 @@ module.exports = (function() {
return self
}
// alias for findAll
/**
* Alias for `findAll`
*
* @see {DAOFactory#findAll}
*/
DAOFactory.prototype.all = function(options, queryOptions) {
return this.findAll(options, queryOptions)
}
/**
* Search for multiple instances
*
* __Simple search using AND and =__
* ```js
* Model.find({
* where: {
* attr1: 42,
* attr2: 'cake'
* }
* })
* ```
* ```sql
* WHERE attr1 = 42 AND attr2 = 'cake'
*```
*
* __Using greater than, less than etc.___
* ```js
*
* Model.find({
* where: {
* attr1: {
* gt: 50
* },
* attr2: {
* lte: 45
* },
* attr3: {
* in: [1,2,3]
* },
* attr4: {
* ne: 5
* }
* }
* })
* ```
* ```sql
* WHERE attr1 > 50 AND attr2 <= 45 AND attr3 IN (1,2,3) AND attr4 != 5
* ```
* Possible options are: `gt, gte, lt, lte, ne, between/.., nbetween/notbetween/!.., in, not, like, nlike/notlike`
*
* __Queries using OR__
* ```js
* Model.find({
* where: Sequelize.and(
* { name: 'a project' },
* Sequelize.or(
* { id: [1,2,3] },
* { id: { gt: 10 } }
* )
* )
* })
* ```
* ```sql
* WHERE name = 'a project' AND (id` IN (1,2,3) OR id > 10)
* ```
*
* @param {Object} [options] A hash of options to describe the scope of the search
* @param {Object} [options.where] A hash of attributes to describe your search. See above for examples.
* @param {Array<String>} [options.attributes] A list of the attributes that you want to select
* @param {Array<Object|DAOFactory>} [options.include] A list of associations to eagerly load. Supported is either { include: [ DaoFactory1, DaoFactory2, ...] } or { include: [ { model: DaoFactory1, as: 'Alias' } ] }. When using the object form, you can also specify `attributes`, `where` to limit the relations and their columns, and `include` to load further nested relations
* @param {String|Array|Sequelize.fn} [options.order] Specifies an ordering. If a string is provided, it will be esacped. Using an array, you can provide several columns / functions to order by. Each element can be further wrapped in a two-element array. The first element is the column / function to order by, the second is the direction. For example: `order: [['name', 'DESC']]`. In this way the column will be escaped, but the direction will not.
* @param {Number} [options.limit]
* @param {Number} [options.offset]
* @param {Object} [queryOptions] set the query options, e.g. raw, specifying that you want raw data instead of built DAOs. See sequelize.query for options
* @param {Transaction} [queryOptions.transaction]
* @param {Boolean} [queryOptions.raw] Returns the results as raw JS objects instead of DAO instances
*
* @see {Sequelize#query}
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, an array of DAOs will be returned to the success listener
*/
DAOFactory.prototype.findAll = function(options, queryOptions) {
var hasJoin = false
, tableNames = { }
......@@ -498,17 +637,11 @@ module.exports = (function() {
/**
* Search for an instance.
*
* @param {Object|Number} options A hush of options to describe the scope of the search, or a number to search by id.
* @param {Object} [options.where]
* @param {Array<String>} [options.attributes] A list of the attributes that you want to select
* @param {Array<Object|DAOFactory>} [options.include] A list of associations which shall get eagerly loaded. Supported is either { include: [ DaoFactory1, DaoFactory2, ...] } or { include: [ { daoFactory: DaoFactory1, as: 'Alias' } ] }.
* @param {String|Array} [options.order]
* @param {Number} [options.limit]
* @param {Number} [options.offset]
* @param {Object} queryOptions set the query options, e.g. raw, specifying that you want raw data instead of built DAOs. See sequelize.query for options
* @param {Transaction} queryOptions.transaction
* @param {Object|Number} [options] A hash of options to describe the scope of the search, or a number to search by id.
* @param {Object} [queryOptions]
*
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, a DAO will be return to the sucess listener
* @see {DAOFactory#findAll} for an explanation of options and queryOptions
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, a DAO will be returned to the success listener
*/
DAOFactory.prototype.find = function(options, queryOptions) {
var hasJoin = false
......@@ -593,6 +726,16 @@ module.exports = (function() {
}, queryOptions, { transaction: (options || {}).transaction }))
}
/**
* Run an aggregation method on the specified field
*
* @param {String} field The field to aggregate over. Can be a field name or *
* @param {String} aggregateFunction The function to use for aggregation, e.g. sum, max etc.
* @param {Object} [options] Query options. See sequelize.query for full options
* @param {DataType|String} [options.dataType] The type of the result. If field is a field in the DAO, the default will be the type of that field, otherwise defaults to float.
*
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, the result of the aggregation function will be returned to the success listener
*/
DAOFactory.prototype.aggregate = function(field, aggregateFunction, options) {
var tableField;
......@@ -641,6 +784,24 @@ module.exports = (function() {
}.bind(this)).run()
}
/**
* Find all the rows matching your query, within a specified offset / limit, and get the total number of rows matching your query. This is very usefull for paging
*
* ```js
* Model.findAndCountAll({
* where: ...,
* limit: 12,
* offset: 12
* }).success(function (result) {
// result.rows will contain rows 13 through 24, while result.count will return the total number of rows that matched your query
* })
* ```
* @param {Object} [findOptions]
* @param {Object} [queryOptions]
*
* @see {DAOFactory#findAll} for a specification of find and query options
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, an object containing rows and count will be returned
*/
DAOFactory.prototype.findAndCountAll = function(findOptions, queryOptions) {
var self = this
// no limit, offset, order, attributes for the options given to count()
......@@ -673,14 +834,41 @@ module.exports = (function() {
}).run()
}
/**
* Find the maximum value of field
*
* @param {String} field
* @param {Object} options
* @see {DAOFactory#aggregate} for options
*
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, the maximum value of field will be returned to the listener.
*/
DAOFactory.prototype.max = function(field, options) {
return this.aggregate(field, 'max', options)
}
/**
* Find the minimum value of field
*
* @param {String} field
* @param {Object} options
* @see {DAOFactory#aggregate} for options
*
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, the minimum value of field will be returned to the listener.
*/
DAOFactory.prototype.min = function(field, options) {
return this.aggregate(field, 'min', options)
}
/**
* Find the sun of field
*
* @param {String} field
* @param {Object} options
* @see {DAOFactory#aggregate} for options
*
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, the value of the summation over field will be returned to the listener.
*/
DAOFactory.prototype.sum = function(field, options) {
return this.aggregate(field, 'sum', options)
}
......@@ -740,6 +928,23 @@ module.exports = (function() {
return this.build(values).save(fieldsOrOptions)
}
/*
* Alias of `findOrInitialize`
*
* @see {DAOFactory#findOrInitialize}
* @name findOrBuild
*/
/**
* Find a row that matches the query, or build (but don't save) the row if none is found.
*
* @param {Object} where A hash of search attributes. Note that this method differs from finders, in that the syntax is { attr1: 42 } and NOT { where: { attr1: 42}}. This is subject to change in 2.0
* @param {Object} [defaults] Default values to use if building a new instance
* @param {Object} [options] Options passed to the find call
* @deprecated The syntax is due for change, in order to make `where` more consistent with the rest of the API
*
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, the DAO will be return to the success listener
*/
DAOFactory.prototype.findOrInitialize = DAOFactory.prototype.findOrBuild = function (params, defaults, options) {
defaults = defaults || {}
options = options || {}
......@@ -781,6 +986,16 @@ module.exports = (function() {
}).run()
}
/**
* Find a row that matches the query, or build and save the row if none is found
*
* @param {Object} where A hash of search attributes. Note that this method differs from finders, in that the syntax is { attr1: 42 } and NOT { where: { attr1: 42}}. This is subject to change in 2.0
* @param {Object} [defaults] Default values to use if creating a new instance
* @param {Object} [options] Options passed to the find and create calls
* @deprecated The syntax is due for change, in order to make `where` more consistent with the rest of the API
*
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, the DAO will be return to the success listener
*/
DAOFactory.prototype.findOrCreate = function (where, defaults, options) {
var self = this
, values = {}
......@@ -835,7 +1050,6 @@ module.exports = (function() {
*
* @return {EventEmitter} Fires `success`, `error` and `sql`. The success` handler is not passed any arguments. To obtain DAOs for the newly created values, you will need to query for them again. This is because MySQL and SQLite do not make it easy to obtain back automatically generated IDs and other default values in a way that can be mapped to multiple records
*/
DAOFactory.prototype.bulkCreate = function(records, fieldsOrOptions, options) {
Utils.validateParameter(fieldsOrOptions, Object, { deprecated: Array, optional: true, index: 2, method: 'DAOFactory#bulkCreate' })
Utils.validateParameter(options, 'undefined', { deprecated: Object, optional: true, index: 3, method: 'DAOFactory#bulkCreate' })
......@@ -1010,13 +1224,13 @@ module.exports = (function() {
/**
* Delete multiple instances
*
* @param {Object} where Options to describe the scope of the search.
* @param {Object} options:
* @param {Boolean} options.hooks If set to true, destroy will find all records within the where parameter and will execute before/afterDestroy hooks on each row
* @param {Number} options.limit How many rows to delete
* @param {Boolean} options.truncate If set to true, dialects that support it will use TRUNCATE instead of DELETE FROM. If a table is truncated the where and limit options are ignored
* @param {Object} [where] Options to describe the scope of the search.
* @param {Object} [options]
* @param {Boolean} [options.hooks] If set to true, destroy will find all records within the where parameter and will execute before/afterDestroy hooks on each row
* @param {Number} [options.limit] How many rows to delete
* @param {Boolean} [options.truncate] If set to true, dialects that support it will use TRUNCATE instead of DELETE FROM. If a table is truncated the where and limit options are ignored
*
* @return {EventEmitter} Fires `success`, `error` and `sql`.
* @return {EventEmitter} Fires `success`, `error` and `sql`.
*/
DAOFactory.prototype.destroy = function(where, options) {
options = options || {}
......@@ -1271,10 +1485,21 @@ module.exports = (function() {
}).run()
}
/**
* Run a describe query on the table
*
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, a hash of attributes and their types will be returned
*/
DAOFactory.prototype.describe = function(schema) {
return this.QueryInterface.describeTable(this.tableName, schema || this.options.schema || undefined)
}
/**
* A proxy to the node-sql query builder, which allows you to build your query through a chain of method calls. The returned instance already has all the fields defined on the model. If you have a user model with a column
*
* @see https://github.com/brianc/node-sql
* @return {Object} A node-sql instance
*/
DAOFactory.prototype.dataset = function() {
if (!this.__sql) {
this.__setSqlDialect()
......
......@@ -7,7 +7,7 @@ var Utils = require("./utils")
module.exports = (function() {
/**
* This class represents an single instance, a database column. You might see it referred to as both DAO and instance.
* This class represents an single instance, a database row. You might see it referred to as both DAO and instance.
*
* DAO instances operate with the concept of a `dataValues` property, which stores the actual values represented by this DAO. By default, the values from dataValues can also be accessed directly from the DAO, that is:
* ```js
......@@ -18,7 +18,7 @@ module.exports = (function() {
* instance.getDataValue('field')
* ```
* However, if getters and/or setters are defined for `field` they will be invoked, instead of returning the value from `dataValues`.
*
* @see {Sequelize#define} Sequelize#define for more information about getters and setters
* @class DAO
*/
......@@ -210,7 +210,7 @@ module.exports = (function() {
, originalValue
if (typeof key === "object") {
values = keys
values = key
options = value
options || (options = {})
......@@ -683,16 +683,16 @@ module.exports = (function() {
/**
* Increment the value of one or more columns. This is done in the database, which means it does not use the values currently stored on the DAO. The increment is done using a
```sql
SET column = column + X
```
query. To get the correct value after an increment into the DAO you should do a reload.
```js
instance.increment('number') increment number by 1
instance.increment(['number', 'count'], { by: 2 }) increment number and count by 2
instance.increment({ answer: 42, tries: 1}, { by: 1 }) increment answer by 42, and tries by 1. `by` is ignore, since each column has its own value
```
* ```sql
* SET column = column + X
* ```
* query. To get the correct value after an increment into the DAO you should do a reload.
*
*```js
* instance.increment('number') increment number by 1
* instance.increment(['number', 'count'], { by: 2 }) increment number and count by 2
* instance.increment({ answer: 42, tries: 1}, { by: 1 }) increment answer by 42, and tries by 1. `by` is ignore, since each column has its own value
* ```
*
* @see {DAO#reload}
* @param {String|Array|Object} fields If a string is provided, that column is incremented by the value of `by` given in options. If an array is provided, the same is true for each column. If and object is provided, each column is incremented by the value given
......@@ -742,17 +742,17 @@ instance.increment({ answer: 42, tries: 1}, { by: 1 }) increment answer by 42, a
}
/**
* Increment the value of one or more columns. This is done in the database, which means it does not use the values currently stored on the DAO. The decrement is done using a
```sql
SET column = column - X
```
query. To get the correct value after an decrement into the DAO you should do a reload.
```js
instance.decrement('number') decrement number by 1
instance.decrement(['number', 'count'], { by: 2 }) decrement number and count by 2
instance.decrement({ answer: 42, tries: 1}, { by: 1 }) decrement answer by 42, and tries by 1. `by` is ignore, since each column has its own value
```
* Decrement the value of one or more columns. This is done in the database, which means it does not use the values currently stored on the DAO. The decrement is done using a
* ```sql
* SET column = column - X
* ```
* query. To get the correct value after an decrement into the DAO you should do a reload.
*
* ```js
* instance.decrement('number') decrement number by 1
* instance.decrement(['number', 'count'], { by: 2 }) decrement number and count by 2
* instance.decrement({ answer: 42, tries: 1}, { by: 1 }) decrement answer by 42, and tries by 1. `by` is ignore, since each column has its own value
* ```
*
* @see {DAO#reload}
* @param {String|Array|Object} fields If a string is provided, that column is decremented by the value of `by` given in options. If an array is provided, the same is true for each column. If and object is provided, each column is decremented by the value given
......@@ -790,6 +790,12 @@ instance.decrement({ answer: 42, tries: 1}, { by: 1 }) decrement answer by 42, a
return this.increment(fields, countOrOptions)
}
/**
* Check whether all values of this and `other` DAO are the same
*
* @param {DAO} other
* @return {Boolean} true if the two DAOs have the same values
*/
DAO.prototype.equals = function(other) {
var result = true
......@@ -804,19 +810,30 @@ instance.decrement({ answer: 42, tries: 1}, { by: 1 }) decrement answer by 42, a
return result
}
/**
* Check if this is eqaul to one of `others` by calling equals
*
* @param {Array} others
* @return {Boolean} true if at least one of the DAOs in others has the same values as this
*/
DAO.prototype.equalsOneOf = function(others) {
var result = false
, self = this
var self = this
others.forEach(function(other) { result = result || self.equals(other) })
return result
return _.any(others, function (other) {
return self.equals(other)
})
}
DAO.prototype.setValidators = function(attribute, validators) {
this.validators[attribute] = validators
}
/**
* Convert the DAO to a JSON representation. Proxies to `get`
*
* @see {DAO#get}
* @return {Object} The properties of the DAO
*/
DAO.prototype.toJSON = function() {
return this.get();
}
......
......@@ -154,12 +154,15 @@ module.exports = (function() {
/**
* A reference to Utils
* @property Utils
* @see {Utils}
*/
Sequelize.Utils = Utils
/**
* An object of different query types. This is used when doing raw queries (sequlize.query). If no type is provided to .query, sequelize will try to guess the correct type based on your SQL. This might not always work if you query is formatted in a special way
* @property QueryTypes
* @see {Sequelize#query}
* @see {QueryTypes}
*/
......@@ -285,6 +288,8 @@ module.exports = (function() {
* @param {Function} [attributes.column.set] Provide a custom setter for this column. Use this.getDataValue(String) and this.setDataValue(String, Value) to manipulate the underlying values.
* @param {Object} [options] These options are merged with the options provided to the Sequelize constructor
* @param {Object} [options.defaultScope] Define the default search scope to use for this model. Scopes have the same form as the options passed to find / findAll
* @param {Object} [options.scopes] More scopes, defined in the same way as defaultScope above. See `DAOFactory.scope` for more information about how scopes are defined, and what you can do with them
* @param {Boolean} [options.omitNull] Don't persits null values. This means that all columns with null values will not be saved
* @param {Boolean} [options.timestamps=true] Handle createdAt and updatedAt timestamps
* @param {Boolean} [options.paranoid=false] Calling destroy will not delete the model, but instead set a deletedAt timestamp if this is true. Needs timestamps=true to work
......
......@@ -26,6 +26,7 @@ var options = {
// Find constructor tags
javadoc.isConstructor = getTag(javadoc.raw.tags, 'constructor') !== undefined;
javadoc.isMixin = getTag(javadoc.raw.tags, 'mixin') !== undefined;
javadoc.isProperty = getTag(javadoc.raw.tags, 'property') !== undefined
javadoc.mixes = getTags(javadoc.raw.tags, 'mixes');
// Only show params without a dot in them (dots means attributes of object, so no need to clutter the co)
......@@ -37,6 +38,12 @@ var options = {
});
javadoc.paramStr = params.join(', ');
// Handle deprecation text
if (javadoc.deprecated) {
var deprecation = getTag(javadoc.raw.tags, 'deprecated')
javadoc.deprecated = deprecation.string
}
// Handle linking in comments
javadoc.see = getTags(javadoc.raw.tags, 'see');
javadoc.see.forEach(function (see, i, collection) {
......@@ -50,7 +57,7 @@ var options = {
_see[0] = _see[0].substring(1)
collection[i].url = _see[0]
collection[i].text = see.local
collection[i].text = see.local.replace(/{|}/g, '')
} else {
collection[i].url = false
collection[i].text = see.local
......@@ -70,7 +77,11 @@ var options = {
}
if (!javadoc.isClass) {
docfile.members.push(javadoc.name + '(' + javadoc.paramStr + ')')
if (!javadoc.isProperty) {
docfile.members.push(javadoc.name + '(' + javadoc.paramStr + ')')
} else {
docfile.members.push(javadoc.name)
}
}
});
......
......@@ -28,12 +28,13 @@
<? if (comment.isClass) { ?>
### Members:
<? doc.members.forEach(function (member) { -?>
* <a href="#<?= member ?>"><?= member ?></a>
<? var link = member.replace(/\(.*?\)/, '') -?>
* <a href="#<?= link ?>"><?= member ?></a>
<? }) -?>
<? } ?>
<? if (comment.deprecated) { ?>
**Deprecated**
**Deprecated** <? if (typeof comment.deprecated === "string") { ?><?- comment.deprecated ?><? } ?>
<? } ?>
<? if (comment.author) { ?>
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!