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

Commit ebab9d9e by Jan Aagaard Meier

Some api doc work on DAOfactory and hooks

1 parent c0b82bd5
...@@ -8,6 +8,14 @@ var Utils = require("./utils") ...@@ -8,6 +8,14 @@ var Utils = require("./utils")
, QueryTypes = require('./query-types') , QueryTypes = require('./query-types')
module.exports = (function() { module.exports = (function() {
/**
* A DAOFactory represents a table in the database. Sometimes you might also see it refererred to as model, or simply as factory. This class should _not_ be instantiated directly, It is created using `sequelize.define`, and already created models can be loaded using `sequelize.import`
*
* @class DAOFactory
* @mixes {Hooks}
* @mixes {Assocations}
* @mixes http://nodejs.org/api/events.html#events_class_events_eventemitter
*/
var DAOFactory = function(name, attributes, options) { var DAOFactory = function(name, attributes, options) {
this.options = Utils._.extend({ this.options = Utils._.extend({
timestamps: true, timestamps: true,
...@@ -484,10 +492,17 @@ module.exports = (function() { ...@@ -484,10 +492,17 @@ module.exports = (function() {
/** /**
* Search for an instance. * Search for an instance.
* *
* @param {Object} options Options to describe the scope of the search. * @param {Object|Number} options A hush of options to describe the scope of the search, or a number to search by id.
* @param {Array} include A list of associations which shall get eagerly loaded. Supported is either { include: [ DaoFactory1, DaoFactory2, ...] } or { include: [ { daoFactory: DaoFactory1, as: 'Alias' } ] }. * @param {Object} [options.where]
* @param {Object} set the query options, e.g. raw, specifying that you want raw data instead of built DAOs * @param {Array<String>} [options.attributes] A list of the attributes that you want to select
* @return {Object} A promise which fires `success`, `error`, `complete` and `sql`. * @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
*
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, a DAO will be return to the sucess listener
*/ */
DAOFactory.prototype.find = function(options, queryOptions) { DAOFactory.prototype.find = function(options, queryOptions) {
var hasJoin = false var hasJoin = false
...@@ -657,6 +672,18 @@ module.exports = (function() { ...@@ -657,6 +672,18 @@ module.exports = (function() {
return this.aggregate(field, 'sum', options) return this.aggregate(field, 'sum', options)
} }
/**
* Builds a new model instance. Values is an object of key value pairs, must be defined but can be empty.
* @param {Object} values
* @param {Object} [options]
* @param {Boolean} [options.raw=false] If set to true, values will ignore field and virtual setters.
* @param {Boolean} [options.isNewRecord=true]
* @param {Boolean} [options.isDirty=true]
* @param {Array} [options.include] an array of include options - Used to build prefetched/included model instances
*
* @return {DAO}
*/
DAOFactory.prototype.build = function(values, options) { DAOFactory.prototype.build = function(values, options) {
options = options || { isNewRecord: true, isDirty: true } options = options || { isNewRecord: true, isDirty: true }
...@@ -667,6 +694,24 @@ module.exports = (function() { ...@@ -667,6 +694,24 @@ module.exports = (function() {
return new this.DAO(values, options) return new this.DAO(values, options)
} }
/**
* Builds a new model instance and calls save on it.
* @see {DAO#build}
* @see {DAO#save}
*
* @param {Object} values
* @param {Object} [options]
* @param {Boolean} [options.raw=false] If set to true, values will ignore field and virtual setters.
* @param {Boolean} [options.isNewRecord=true]
* @param {Boolean} [options.isDirty=true]
* @param {Array} [options.fields] If set, only columns matching those in fields will be saved
* @param {Array} [options.include] an array of include options - Used to build prefetched/included model instances
* @param {Transaction} [options.transaction]
*
* @return {EventEmitter} Fires `success`, `error` and `sql`. Upon success, the DAO will be return to the success listener
*/
DAOFactory.prototype.create = function(values, fieldsOrOptions) { DAOFactory.prototype.create = function(values, fieldsOrOptions) {
Utils.validateParameter(values, Object, { optional: true }) Utils.validateParameter(values, Object, { optional: true })
Utils.validateParameter(fieldsOrOptions, Object, { deprecated: Array, optional: true, index: 2, method: 'DAOFactory#create' }) Utils.validateParameter(fieldsOrOptions, Object, { deprecated: Array, optional: true, index: 2, method: 'DAOFactory#create' })
...@@ -766,17 +811,16 @@ module.exports = (function() { ...@@ -766,17 +811,16 @@ module.exports = (function() {
} }
/** /**
* Create and insert multiple instances * Create and insert multiple instances in bulk
* *
* @param {Array} records List of objects (key/value pairs) to create instances from * @param {Array} records List of objects (key/value pairs) to create instances from
* @param {Array} fields Fields to insert (defaults to all fields) * @param {Object} [options]
* @return {Object} A promise which fires `success`, `error`, `complete` and `sql`. * @param {Array} [options.fields] Fields to insert (defaults to all fields)
* * @param {Boolean} [options.validate=false] Should each row be subject to validation before it is inserted. The whole insert will fail if one row fails validation
* Note: the `success` handler is not passed any arguments. To obtain DAOs for * @param {Boolean} [options.hooks=false] Run before / after bulkCreate hooks?
* the newly created values, you will need to query for them again. This is * @param {Boolean} [options.ignoreDuplicates=false] Ignore duplicate values for primary keys? (not supported by postgres)
* 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 * @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
* multiple records
*/ */
DAOFactory.prototype.bulkCreate = function(records, fieldsOrOptions, options) { DAOFactory.prototype.bulkCreate = function(records, fieldsOrOptions, options) {
Utils.validateParameter(fieldsOrOptions, Object, { deprecated: Array, optional: true, index: 2, method: 'DAOFactory#bulkCreate' }) Utils.validateParameter(fieldsOrOptions, Object, { deprecated: Array, optional: true, index: 2, method: 'DAOFactory#bulkCreate' })
...@@ -949,12 +993,13 @@ module.exports = (function() { ...@@ -949,12 +993,13 @@ module.exports = (function() {
/** /**
* Delete multiple instances * Delete multiple instances
* *
* @param {Object} where Options to describe the scope of the search. * @param {Object} where Options to describe the scope of the search.
* @param {Object} options Possible options are: * @param {Object} 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 {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
- limit: How many rows to delete * @param {Number} options.limit How many rows to delete
- 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 {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 {Object} A promise which fires `success`, `error`, `complete` and `sql`. *
* @return {EventEmitter} Fires `success`, `error` and `sql`.
*/ */
DAOFactory.prototype.destroy = function(where, options) { DAOFactory.prototype.destroy = function(where, options) {
options = options || {} options = options || {}
...@@ -1070,9 +1115,13 @@ module.exports = (function() { ...@@ -1070,9 +1115,13 @@ module.exports = (function() {
/** /**
* Update multiple instances * Update multiple instances
* *
* @param {Object} attrValueHash A hash of fields to change and their new values * @param {Object} attrValueHash A hash of fields to change and their new values
* @param {Object} where Options to describe the scope of the search. * @param {Object where Options to describe the scope of the search. Note that these options are not wrapped in a { where: ... } is in find / findAll calls etc. This is probably due to change in 2.0
* @return {Object} A promise which fires `success`, `error`, `complete` and `sql`. * @param {Object} options
* @param {Boolean} [options.validate=true] Should each row be subject to validation before it is inserted. The whole insert will fail if one row fails validation
* @param {Boolean} [options.hooks=false] Run before / after bulkUpdate hooks?
*
* @return {EventEmitter} A promise which fires `success`, `error` and `sql`.
*/ */
DAOFactory.prototype.update = function(attrValueHash, where, options) { DAOFactory.prototype.update = function(attrValueHash, where, options) {
var self = this var self = this
......
...@@ -10,13 +10,13 @@ module.exports = (function() { ...@@ -10,13 +10,13 @@ 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 column. 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: * 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 * ```js
instance.field * instance.field
// is the same as * // is the same as
instance.get('field') * instance.get('field')
// is the same as * // is the same as
instance.getDataValue('field') * instance.getDataValue('field')
``` * ```
* However, if getters and/or setters are defined for `field` they will be invoked, instead of returning the value from `dataValues`. * 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 * @see {Sequelize#define} Sequelize#define for more information about getters and setters
......
var Utils = require("./utils") var Utils = require("./utils")
/**
* Hooks are function that are called before and after (bulk-) creation/updating/deletion and validation. Hooks can be added to you models in three ways:
* 1. By specifying them as options in sequelize.define
* 2. By calling `hook()` with a string and your hook handler function
* 3. By calling the function with the same name as the hook you want
* ```js
* // Method 1
* sequelize.define(name, { attributes }, {
* hooks: {
* beforeBulkCreate: function () {
* // can be a single function
* },
* beforeValidate: [
* function () {},
* function() {} // Or an array of several
* ]
* }
* })
*
* // Method 2
* Model.hook('afterDestroy', function () {})
*
* // Method 3
* Model.afterBulkUpdate(function () {})
* ```
*
* @see {Sequelize#define}
* @mixin Hooks
*/
var Hooks = module.exports = function(){} var Hooks = module.exports = function(){}
var hookAliases = { var hookAliases = {
beforeDelete: "beforeDestroy", beforeDelete: "beforeDestroy",
...@@ -65,11 +96,21 @@ Hooks.runHooks = function() { ...@@ -65,11 +96,21 @@ Hooks.runHooks = function() {
run(hooks[tick]) run(hooks[tick])
} }
// Alias for `.addHook` /**
* Alias of addHook
* @see {Hooks#addHook}
*/
Hooks.hook = function() { Hooks.hook = function() {
Hooks.addHook.apply(this, arguments) Hooks.addHook.apply(this, arguments)
} }
/**
* Add a hook to the model
*
* @param {String} hooktype
* @param {String} [name] Provide a name for the hooks function. This serves no purpose other than the ability/capability for the future to order hooks based on either a priority system or by before/after a specific hook.
* @param {Function} fn The hook function
*/
Hooks.addHook = function(hookType, name, fn) { Hooks.addHook = function(hookType, name, fn) {
if (typeof name === "function") { if (typeof name === "function") {
fn = name fn = name
...@@ -88,6 +129,11 @@ Hooks.addHook = function(hookType, name, fn) { ...@@ -88,6 +129,11 @@ Hooks.addHook = function(hookType, name, fn) {
this.options.hooks[hookType][this.options.hooks[hookType].length] = !!name ? {name: name, fn: method} : method this.options.hooks[hookType][this.options.hooks[hookType].length] = !!name ? {name: name, fn: method} : method
} }
/**
* A hook that is run before validation
* @param {String} name
* @param {Function} fn A callback function that is called with model, callback(err)
*/
Hooks.beforeValidate = function(name, fn) { Hooks.beforeValidate = function(name, fn) {
Hooks.addHook.call(this, 'beforeValidate', name, fn) Hooks.addHook.call(this, 'beforeValidate', name, fn)
} }
......
...@@ -158,7 +158,7 @@ module.exports = (function() { ...@@ -158,7 +158,7 @@ module.exports = (function() {
/** /**
* 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 * 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
* @see sequelize#query * @see {Sequelize#query}
* @see {QueryTypes} * @see {QueryTypes}
*/ */
Sequelize.QueryTypes = QueryTypes Sequelize.QueryTypes = QueryTypes
...@@ -252,6 +252,7 @@ module.exports = (function() { ...@@ -252,6 +252,7 @@ module.exports = (function() {
* For more about instance and class methods see http://sequelizejs.com/docs/latest/models#expansion-of-models * For more about instance and class methods see http://sequelizejs.com/docs/latest/models#expansion-of-models
* *
* @see {DataTypes} * @see {DataTypes}
* @see {Hooks}
* @param {String} daoName * @param {String} daoName
* @param {Object} attributes An object, where each attribute is a column of the table. Each column can be either a DataType, a string or a type-description object, with the properties described below: * @param {Object} attributes An object, where each attribute is a column of the table. Each column can be either a DataType, a string or a type-description object, with the properties described below:
* @param {String|DataType|Object} attributes.column The description of a database column * @param {String|DataType|Object} attributes.column The description of a database column
...@@ -288,6 +289,7 @@ module.exports = (function() { ...@@ -288,6 +289,7 @@ module.exports = (function() {
* @param {Strng} [options.charset] * @param {Strng} [options.charset]
* @param {String} [options.comment] * @param {String} [options.comment]
* @param {String} [options.collate] * @param {String} [options.collate]
* @param {Object} [options.hooks] An object of hook function that are called before and after certain lifecycle events. The possible hooks are: beforeValidate, afterValidate, beforeBulkCreate, beforeBulkDestroy, beforeBulkUpdate, beforeCreate, beforeDestroy, beforeUpdate, afterCreate, afterDestroy, afterUpdate, afterBulkCreate, afterBulkDestory and afterBulkUpdate. See Hooks for more information about hook functions and their signatures. Each property can either be a function, or an array of function.
* *
* @return {DaoFactory} * @return {DaoFactory}
* TODO validation * TODO validation
...@@ -621,7 +623,7 @@ module.exports = (function() { ...@@ -621,7 +623,7 @@ module.exports = (function() {
/** /**
* Creates a object representing a column in the DB. This is usefull in sequelize.fn, since raw string arguments to that will be escaped. * Creates a object representing a column in the DB. This is usefull in sequelize.fn, since raw string arguments to that will be escaped.
* @see Sequelize#fn * @see {Sequelize#fn}
* *
* @method col * @method col
* @param {String} col The name of the column * @param {String} col The name of the column
......
...@@ -5,10 +5,16 @@ var markdox = require('markdox') ...@@ -5,10 +5,16 @@ var markdox = require('markdox')
var getTag = function(tags, tagName) { var getTag = function(tags, tagName) {
return _.find(tags, function (tag) { return _.find(tags, function (tag) {
return tag.type === tagName return tag.type === tagName;
}); });
}; };
var getTags = function(tags, tagName) {
return _.where(tags, function (tag) {
return tag.type === tagName;
});
}
// TODO multiple @see tags // TODO multiple @see tags
var options = { var options = {
output: 'output.md', output: 'output.md',
...@@ -18,7 +24,9 @@ var options = { ...@@ -18,7 +24,9 @@ var options = {
docfile.members = []; docfile.members = [];
docfile.javadoc.forEach(function(javadoc, index){ docfile.javadoc.forEach(function(javadoc, index){
// Find constructor tags // Find constructor tags
docfile.javadoc[index].isConstructor = getTag(javadoc.raw.tags, 'constructor') !== undefined; javadoc.isConstructor = getTag(javadoc.raw.tags, 'constructor') !== undefined;
javadoc.isMixin = getTag(javadoc.raw.tags, 'mixin') !== 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) // Only show params without a dot in them (dots means attributes of object, so no need to clutter the co)
var params = [] var params = []
...@@ -30,26 +38,28 @@ var options = { ...@@ -30,26 +38,28 @@ var options = {
javadoc.paramStr = params.join(', '); javadoc.paramStr = params.join(', ');
// Handle linking in comments // Handle linking in comments
if (javadoc.see) { javadoc.see = getTags(javadoc.raw.tags, 'see');
if (javadoc.see.indexOf('{') === 0){ javadoc.see.forEach(function (see, i, collection) {
var see = javadoc.see.split('}') collection[i] = {}
see[0] = see[0].substring(1)
if (javadoc.see.indexOf('www') !== -1) {
javadoc.seeExternal = true
} else {
javadoc.seeExternal = false
}
javadoc.seeURL = see[0]
if (see[1] !== "") { if (see.local) {
javadoc.seeText = see[1] collection[i].external = false
if (see.local.indexOf('{') === 0){
var _see = see.local.split('}')
_see[0] = _see[0].substring(1)
collection[i].url = _see[0]
collection[i].text = see.local
} else { } else {
javadoc.seeText = see[0] collection[i].url = false
collection[i].text = see.local
} }
} else { } else {
javadoc.seeURL = false collection[i].external = true
} }
} })
// Set a name for properties // Set a name for properties
if (!javadoc.name) { if (!javadoc.name) {
...@@ -60,7 +70,7 @@ var options = { ...@@ -60,7 +70,7 @@ var options = {
} }
if (!javadoc.isClass) { if (!javadoc.isClass) {
docfile.members.push(javadoc.name) docfile.members.push(javadoc.name + '(' + javadoc.paramStr + ')')
} }
}); });
...@@ -69,7 +79,7 @@ var options = { ...@@ -69,7 +79,7 @@ var options = {
template: 'output.md.ejs' template: 'output.md.ejs'
}; };
markdox.process('./lib/sequelize.js', options, function(){ markdox.process(process.argv[2] || './lib/hooks.js', options, function(){
md = fs.readFileSync('output.md').toString(); md = fs.readFileSync('output.md').toString();
fs.writeFileSync('out.html', ghm.parse(md)); fs.writeFileSync('out.html', ghm.parse(md));
......
...@@ -14,10 +14,22 @@ ...@@ -14,10 +14,22 @@
<?= comment.description ?> <?= comment.description ?>
<? if (comment.mixes.length) { ?>
### Mixes:
<? comment.mixes.forEach(function (mix) { mix = mix.string ?>
<? if (mix.indexOf('www') !== -1 || mix.indexOf('http') !== -1) { -?>
* <a href="<?= mix ?>"><?= mix ?></a>
<? } else { -?>
* <a href="https://github.com/sequelize/sequelize/wiki/API-Reference-<?= mix ?>"><?= mix.substring(1, mix.length -1) ?></a>
<? } ?>
<? }) ?>
<? } ?>
<? if (comment.isClass) { ?> <? if (comment.isClass) { ?>
### Members: ### Members:
<? doc.members.forEach(function (member) { ?> <? doc.members.forEach(function (member) { -?>
* <a href="#<?= member ?>"><?= member ?></a><? }) ?> * <a href="#<?= member ?>"><?= member ?></a>
<? }) -?>
<? } ?> <? } ?>
<? if (comment.deprecated) { ?> <? if (comment.deprecated) { ?>
...@@ -32,17 +44,18 @@ ...@@ -32,17 +44,18 @@
Version: <?= comment.version ?> Version: <?= comment.version ?>
<? } ?> <? } ?>
<? if (comment.see) { ?> <? if (comment.see.length) { ?>See:<? } ?>
<? if (comment.seeURL !== false) { ?> <? comment.see.forEach(function (see) { -?>
<? if (comment.seeExternal) { ?> <? if (see.url !== false) { -?>
See: <a href="<?= comment.seeURL ?>"><?= comment.seeText ?></a> <? if (see.external) { -?>
<? } else { ?> * <a href="<?= see.url ?>"><?= see.text ?></a>
See: <a href="https://github.com/sequelize/sequelize/wiki/API-Reference-<?= comment.seeURL ?>"><?= comment.seeText ?></a> <? } else { -?>
<? } ?> * <a href="https://github.com/sequelize/sequelize/wiki/API-Reference-<?= see.url ?>"><?= see.text ?></a>
<? } else { ?> <? } -?>
See: <?= comment.see ?> <? } else { -?>
<? } ?> * <?= see.text ?>
<? } ?> <? } -?>
<? }) -?>
<? if (comment.paramTags.length > 0) { ?> <? if (comment.paramTags.length > 0) { ?>
#### Params: #### Params:
...@@ -70,7 +83,7 @@ ...@@ -70,7 +83,7 @@
------ ------
<? }) ?> <? }) ?>
_This document is automatically generated based on source code comments. Please do not edit it directly, as your changes will be ignored. Please write on [IRC](irc://irc.freenode.net/#sequelizejs), open an issue or a create a pull request if you feel something can be improved. For help on how to write source code documentation see [JSDoc](http://usejsdoc.org), [dox](https://github.com/visionmedia/dox) and [markdox](https://github.com/cbou/markdox)_ _This document is automatically generated based on source code comments. Please do not edit it directly, as your changes will be ignored. Please write on [IRC](irc://irc.freenode.net/#sequelizejs), open an issue or a create a pull request if you feel something can be improved. For help on how to write source code documentation see [JSDoc](http://usejsdoc.org) and [markdox](https://github.com/cbou/markdox)_
_This documentation was automagically created on <?= new Date().toString() ?>_ _This documentation was automagically created on <?= new Date().toString() ?>_
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!