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

Commit 7b798eb0 by Mick Hansen

Merge pull request #1595 from janmeier/apidocs

Updated the in-code API docs, and added a new way to generate them
2 parents 1824379a ff755e29
......@@ -9,3 +9,5 @@ test/binary/tmp/*
test/tmp/*
test/sqlite/test.sqlite
coverage-*
docs/*.md
docs/*.html
\ No newline at end of file
YUI.add("yuidoc-meta", function(Y) {
Y.YUIDoc = { meta: {
"classes": [
"QueryInterface",
"Sequelize"
],
"modules": [
"Sequelize"
],
"allModules": [
{
"displayName": "Sequelize",
"name": "Sequelize",
"description": "The entry point."
}
]
} };
});
\ No newline at end of file
<!doctype html>
<html>
<head>
<title>Redirector</title>
<meta http-equiv="refresh" content="0;url=../">
</head>
<body>
<a href="../">Click here to redirect</a>
</body>
</html>
YUI.add('api-filter', function (Y) {
Y.APIFilter = Y.Base.create('apiFilter', Y.Base, [Y.AutoCompleteBase], {
// -- Initializer ----------------------------------------------------------
initializer: function () {
this._bindUIACBase();
this._syncUIACBase();
},
getDisplayName: function(name) {
Y.each(Y.YUIDoc.meta.allModules, function(i) {
if (i.name === name && i.displayName) {
name = i.displayName;
}
});
return name;
}
}, {
// -- Attributes -----------------------------------------------------------
ATTRS: {
resultHighlighter: {
value: 'phraseMatch'
},
// May be set to "classes" or "modules".
queryType: {
value: 'classes'
},
source: {
valueFn: function() {
var self = this;
return function(q) {
var data = Y.YUIDoc.meta[self.get('queryType')],
out = [];
Y.each(data, function(v) {
if (v.toLowerCase().indexOf(q.toLowerCase()) > -1) {
out.push(v);
}
});
return out;
};
}
}
}
});
}, '3.4.0', {requires: [
'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources'
]});
YUI.add('api-list', function (Y) {
var Lang = Y.Lang,
YArray = Y.Array,
APIList = Y.namespace('APIList'),
classesNode = Y.one('#api-classes'),
inputNode = Y.one('#api-filter'),
modulesNode = Y.one('#api-modules'),
tabviewNode = Y.one('#api-tabview'),
tabs = APIList.tabs = {},
filter = APIList.filter = new Y.APIFilter({
inputNode : inputNode,
maxResults: 1000,
on: {
results: onFilterResults
}
}),
search = APIList.search = new Y.APISearch({
inputNode : inputNode,
maxResults: 100,
on: {
clear : onSearchClear,
results: onSearchResults
}
}),
tabview = APIList.tabview = new Y.TabView({
srcNode : tabviewNode,
panelNode: '#api-tabview-panel',
render : true,
on: {
selectionChange: onTabSelectionChange
}
}),
focusManager = APIList.focusManager = tabviewNode.plug(Y.Plugin.NodeFocusManager, {
circular : true,
descendants: '#api-filter, .yui3-tab-panel-selected .api-list-item a, .yui3-tab-panel-selected .result a',
keys : {next: 'down:40', previous: 'down:38'}
}).focusManager,
LIST_ITEM_TEMPLATE =
'<li class="api-list-item {typeSingular}">' +
'<a href="{rootPath}{typePlural}/{name}.html">{displayName}</a>' +
'</li>';
// -- Init ---------------------------------------------------------------------
// Duckpunch FocusManager's key event handling to prevent it from handling key
// events when a modifier is pressed.
Y.before(function (e, activeDescendant) {
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {
return new Y.Do.Prevent();
}
}, focusManager, '_focusPrevious', focusManager);
Y.before(function (e, activeDescendant) {
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {
return new Y.Do.Prevent();
}
}, focusManager, '_focusNext', focusManager);
// Create a mapping of tabs in the tabview so we can refer to them easily later.
tabview.each(function (tab, index) {
var name = tab.get('label').toLowerCase();
tabs[name] = {
index: index,
name : name,
tab : tab
};
});
// Switch tabs on Ctrl/Cmd-Left/Right arrows.
tabviewNode.on('key', onTabSwitchKey, 'down:37,39');
// Focus the filter input when the `/` key is pressed.
Y.one(Y.config.doc).on('key', onSearchKey, 'down:83');
// Keep the Focus Manager up to date.
inputNode.on('focus', function () {
focusManager.set('activeDescendant', inputNode);
});
// Update all tabview links to resolved URLs.
tabview.get('panelNode').all('a').each(function (link) {
link.setAttribute('href', link.get('href'));
});
// -- Private Functions --------------------------------------------------------
function getFilterResultNode() {
return filter.get('queryType') === 'classes' ? classesNode : modulesNode;
}
// -- Event Handlers -----------------------------------------------------------
function onFilterResults(e) {
var frag = Y.one(Y.config.doc.createDocumentFragment()),
resultNode = getFilterResultNode(),
typePlural = filter.get('queryType'),
typeSingular = typePlural === 'classes' ? 'class' : 'module';
if (e.results.length) {
YArray.each(e.results, function (result) {
frag.append(Lang.sub(LIST_ITEM_TEMPLATE, {
rootPath : APIList.rootPath,
displayName : filter.getDisplayName(result.highlighted),
name : result.text,
typePlural : typePlural,
typeSingular: typeSingular
}));
});
} else {
frag.append(
'<li class="message">' +
'No ' + typePlural + ' found.' +
'</li>'
);
}
resultNode.empty(true);
resultNode.append(frag);
focusManager.refresh();
}
function onSearchClear(e) {
focusManager.refresh();
}
function onSearchKey(e) {
var target = e.target;
if (target.test('input,select,textarea')
|| target.get('isContentEditable')) {
return;
}
e.preventDefault();
inputNode.focus();
focusManager.refresh();
}
function onSearchResults(e) {
var frag = Y.one(Y.config.doc.createDocumentFragment());
if (e.results.length) {
YArray.each(e.results, function (result) {
frag.append(result.display);
});
} else {
frag.append(
'<li class="message">' +
'No results found. Maybe you\'ll have better luck with a ' +
'different query?' +
'</li>'
);
}
focusManager.refresh();
}
function onTabSelectionChange(e) {
var tab = e.newVal,
name = tab.get('label').toLowerCase();
tabs.selected = {
index: tab.get('index'),
name : name,
tab : tab
};
switch (name) {
case 'classes': // fallthru
case 'modules':
filter.setAttrs({
minQueryLength: 0,
queryType : name
});
search.set('minQueryLength', -1);
// Only send a request if this isn't the initially-selected tab.
if (e.prevVal) {
filter.sendRequest(filter.get('value'));
}
break;
case 'everything':
filter.set('minQueryLength', -1);
search.set('minQueryLength', 1);
if (search.get('value')) {
search.sendRequest(search.get('value'));
} else {
inputNode.focus();
}
break;
default:
// WTF? We shouldn't be here!
filter.set('minQueryLength', -1);
search.set('minQueryLength', -1);
}
if (focusManager) {
setTimeout(function () {
focusManager.refresh();
}, 1);
}
}
function onTabSwitchKey(e) {
var currentTabIndex = tabs.selected.index;
if (!(e.ctrlKey || e.metaKey)) {
return;
}
e.preventDefault();
switch (e.keyCode) {
case 37: // left arrow
if (currentTabIndex > 0) {
tabview.selectChild(currentTabIndex - 1);
inputNode.focus();
}
break;
case 39: // right arrow
if (currentTabIndex < (Y.Object.size(tabs) - 2)) {
tabview.selectChild(currentTabIndex + 1);
inputNode.focus();
}
break;
}
}
}, '3.4.0', {requires: [
'api-filter', 'api-search', 'event-key', 'node-focusmanager', 'tabview'
]});
YUI.add('api-search', function (Y) {
var Lang = Y.Lang,
Node = Y.Node,
YArray = Y.Array;
Y.APISearch = Y.Base.create('apiSearch', Y.Base, [Y.AutoCompleteBase], {
// -- Public Properties ----------------------------------------------------
RESULT_TEMPLATE:
'<li class="result {resultType}">' +
'<a href="{url}">' +
'<h3 class="title">{name}</h3>' +
'<span class="type">{resultType}</span>' +
'<div class="description">{description}</div>' +
'<span class="className">{class}</span>' +
'</a>' +
'</li>',
// -- Initializer ----------------------------------------------------------
initializer: function () {
this._bindUIACBase();
this._syncUIACBase();
},
// -- Protected Methods ----------------------------------------------------
_apiResultFilter: function (query, results) {
// Filter components out of the results.
return YArray.filter(results, function (result) {
return result.raw.resultType === 'component' ? false : result;
});
},
_apiResultFormatter: function (query, results) {
return YArray.map(results, function (result) {
var raw = Y.merge(result.raw), // create a copy
desc = raw.description || '';
// Convert description to text and truncate it if necessary.
desc = Node.create('<div>' + desc + '</div>').get('text');
if (desc.length > 65) {
desc = Y.Escape.html(desc.substr(0, 65)) + ' &hellip;';
} else {
desc = Y.Escape.html(desc);
}
raw['class'] || (raw['class'] = '');
raw.description = desc;
// Use the highlighted result name.
raw.name = result.highlighted;
return Lang.sub(this.RESULT_TEMPLATE, raw);
}, this);
},
_apiTextLocator: function (result) {
return result.displayName || result.name;
}
}, {
// -- Attributes -----------------------------------------------------------
ATTRS: {
resultFormatter: {
valueFn: function () {
return this._apiResultFormatter;
}
},
resultFilters: {
valueFn: function () {
return this._apiResultFilter;
}
},
resultHighlighter: {
value: 'phraseMatch'
},
resultListLocator: {
value: 'data.results'
},
resultTextLocator: {
valueFn: function () {
return this._apiTextLocator;
}
},
source: {
value: '/api/v1/search?q={query}&count={maxResults}'
}
}
});
}, '3.4.0', {requires: [
'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources',
'escape'
]});
YUI().use(
'yuidoc-meta',
'api-list', 'history-hash', 'node-screen', 'node-style', 'pjax',
function (Y) {
var win = Y.config.win,
localStorage = win.localStorage,
bdNode = Y.one('#bd'),
pjax,
defaultRoute,
classTabView,
selectedTab;
// Kill pjax functionality unless serving over HTTP.
if (!Y.getLocation().protocol.match(/^https?\:/)) {
Y.Router.html5 = false;
}
// Create the default route with middleware which enables syntax highlighting
// on the loaded content.
defaultRoute = Y.Pjax.defaultRoute.concat(function (req, res, next) {
prettyPrint();
bdNode.removeClass('loading');
next();
});
pjax = new Y.Pjax({
container : '#docs-main',
contentSelector: '#docs-main > .content',
linkSelector : '#bd a',
titleSelector : '#xhr-title',
navigateOnHash: true,
root : '/',
routes : [
// -- / ----------------------------------------------------------------
{
path : '/(index.html)?',
callbacks: defaultRoute
},
// -- /classes/* -------------------------------------------------------
{
path : '/classes/:class.html*',
callbacks: [defaultRoute, 'handleClasses']
},
// -- /files/* ---------------------------------------------------------
{
path : '/files/*file',
callbacks: [defaultRoute, 'handleFiles']
},
// -- /modules/* -------------------------------------------------------
{
path : '/modules/:module.html*',
callbacks: defaultRoute
}
]
});
// -- Utility Functions --------------------------------------------------------
pjax.checkVisibility = function (tab) {
tab || (tab = selectedTab);
if (!tab) { return; }
var panelNode = tab.get('panelNode'),
visibleItems;
// If no items are visible in the tab panel due to the current visibility
// settings, display a message to that effect.
visibleItems = panelNode.all('.item,.index-item').some(function (itemNode) {
if (itemNode.getComputedStyle('display') !== 'none') {
return true;
}
});
panelNode.all('.no-visible-items').remove();
if (!visibleItems) {
if (Y.one('#index .index-item')) {
panelNode.append(
'<div class="no-visible-items">' +
'<p>' +
'Some items are not shown due to the current visibility ' +
'settings. Use the checkboxes at the upper right of this ' +
'page to change the visibility settings.' +
'</p>' +
'</div>'
);
} else {
panelNode.append(
'<div class="no-visible-items">' +
'<p>' +
'This class doesn\'t provide any methods, properties, ' +
'attributes, or events.' +
'</p>' +
'</div>'
);
}
}
// Hide index sections without any visible items.
Y.all('.index-section').each(function (section) {
var items = 0,
visibleItems = 0;
section.all('.index-item').each(function (itemNode) {
items += 1;
if (itemNode.getComputedStyle('display') !== 'none') {
visibleItems += 1;
}
});
section.toggleClass('hidden', !visibleItems);
section.toggleClass('no-columns', visibleItems < 4);
});
};
pjax.initClassTabView = function () {
if (!Y.all('#classdocs .api-class-tab').size()) {
return;
}
if (classTabView) {
classTabView.destroy();
selectedTab = null;
}
classTabView = new Y.TabView({
srcNode: '#classdocs',
on: {
selectionChange: pjax.onTabSelectionChange
}
});
pjax.updateTabState();
classTabView.render();
};
pjax.initLineNumbers = function () {
var hash = win.location.hash.substring(1),
container = pjax.get('container'),
hasLines, node;
// Add ids for each line number in the file source view.
container.all('.linenums>li').each(function (lineNode, index) {
lineNode.set('id', 'l' + (index + 1));
lineNode.addClass('file-line');
hasLines = true;
});
// Scroll to the desired line.
if (hasLines && /^l\d+$/.test(hash)) {
if ((node = container.getById(hash))) {
win.scroll(0, node.getY());
}
}
};
pjax.initRoot = function () {
var terminators = /^(?:classes|files|modules)$/,
parts = pjax._getPathRoot().split('/'),
root = [],
i, len, part;
for (i = 0, len = parts.length; i < len; i += 1) {
part = parts[i];
if (part.match(terminators)) {
// Makes sure the path will end with a "/".
root.push('');
break;
}
root.push(part);
}
pjax.set('root', root.join('/'));
};
pjax.updateTabState = function (src) {
var hash = win.location.hash.substring(1),
defaultTab, node, tab, tabPanel;
function scrollToNode() {
if (node.hasClass('protected')) {
Y.one('#api-show-protected').set('checked', true);
pjax.updateVisibility();
}
if (node.hasClass('private')) {
Y.one('#api-show-private').set('checked', true);
pjax.updateVisibility();
}
setTimeout(function () {
// For some reason, unless we re-get the node instance here,
// getY() always returns 0.
var node = Y.one('#classdocs').getById(hash);
win.scrollTo(0, node.getY() - 70);
}, 1);
}
if (!classTabView) {
return;
}
if (src === 'hashchange' && !hash) {
defaultTab = 'index';
} else {
if (localStorage) {
defaultTab = localStorage.getItem('tab_' + pjax.getPath()) ||
'index';
} else {
defaultTab = 'index';
}
}
if (hash && (node = Y.one('#classdocs').getById(hash))) {
if ((tabPanel = node.ancestor('.api-class-tabpanel', true))) {
if ((tab = Y.one('#classdocs .api-class-tab.' + tabPanel.get('id')))) {
if (classTabView.get('rendered')) {
Y.Widget.getByNode(tab).set('selected', 1);
} else {
tab.addClass('yui3-tab-selected');
}
}
}
// Scroll to the desired element if this is a hash URL.
if (node) {
if (classTabView.get('rendered')) {
scrollToNode();
} else {
classTabView.once('renderedChange', scrollToNode);
}
}
} else {
tab = Y.one('#classdocs .api-class-tab.' + defaultTab);
// When the `defaultTab` node isn't found, `localStorage` is stale.
if (!tab && defaultTab !== 'index') {
tab = Y.one('#classdocs .api-class-tab.index');
}
if (classTabView.get('rendered')) {
Y.Widget.getByNode(tab).set('selected', 1);
} else {
tab.addClass('yui3-tab-selected');
}
}
};
pjax.updateVisibility = function () {
var container = pjax.get('container');
container.toggleClass('hide-inherited',
!Y.one('#api-show-inherited').get('checked'));
container.toggleClass('show-deprecated',
Y.one('#api-show-deprecated').get('checked'));
container.toggleClass('show-protected',
Y.one('#api-show-protected').get('checked'));
container.toggleClass('show-private',
Y.one('#api-show-private').get('checked'));
pjax.checkVisibility();
};
// -- Route Handlers -----------------------------------------------------------
pjax.handleClasses = function (req, res, next) {
var status = res.ioResponse.status;
// Handles success and local filesystem XHRs.
if (!status || (status >= 200 && status < 300)) {
pjax.initClassTabView();
}
next();
};
pjax.handleFiles = function (req, res, next) {
var status = res.ioResponse.status;
// Handles success and local filesystem XHRs.
if (!status || (status >= 200 && status < 300)) {
pjax.initLineNumbers();
}
next();
};
// -- Event Handlers -----------------------------------------------------------
pjax.onNavigate = function (e) {
var hash = e.hash,
originTarget = e.originEvent && e.originEvent.target,
tab;
if (hash) {
tab = originTarget && originTarget.ancestor('.yui3-tab', true);
if (hash === win.location.hash) {
pjax.updateTabState('hashchange');
} else if (!tab) {
win.location.hash = hash;
}
e.preventDefault();
return;
}
// Only scroll to the top of the page when the URL doesn't have a hash.
this.set('scrollToTop', !e.url.match(/#.+$/));
bdNode.addClass('loading');
};
pjax.onOptionClick = function (e) {
pjax.updateVisibility();
};
pjax.onTabSelectionChange = function (e) {
var tab = e.newVal,
tabId = tab.get('contentBox').getAttribute('href').substring(1);
selectedTab = tab;
// If switching from a previous tab (i.e., this is not the default tab),
// replace the history entry with a hash URL that will cause this tab to
// be selected if the user navigates away and then returns using the back
// or forward buttons.
if (e.prevVal && localStorage) {
localStorage.setItem('tab_' + pjax.getPath(), tabId);
}
pjax.checkVisibility(tab);
};
// -- Init ---------------------------------------------------------------------
pjax.on('navigate', pjax.onNavigate);
pjax.initRoot();
pjax.upgrade();
pjax.initClassTabView();
pjax.initLineNumbers();
pjax.updateVisibility();
Y.APIList.rootPath = pjax.get('root');
Y.one('#api-options').delegate('click', pjax.onOptionClick, 'input');
Y.on('hashchange', function (e) {
pjax.updateTabState('hashchange');
}, win);
});
YUI().use('node', function(Y) {
var code = Y.all('.prettyprint.linenums');
if (code.size()) {
code.each(function(c) {
var lis = c.all('ol li'),
l = 1;
lis.each(function(n) {
n.prepend('<a name="LINENUM_' + l + '"></a>');
l++;
});
});
var h = location.hash;
location.hash = '';
h = h.replace('LINE_', 'LINENUM_');
location.hash = h;
}
});
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Change Log</title>
</head>
<body bgcolor="white">
<a style="float:right" href="README.html">README</a>
<h1>Known Issues</h1>
<ul>
<li>Perl formatting is really crappy. Partly because the author is lazy and
partly because Perl is
<a href="http://www.perlmonks.org/?node_id=663393">hard</a> to parse.
<li>On some browsers, <code>&lt;code&gt;</code> elements with newlines in the text
which use CSS to specify <code>white-space:pre</code> will have the newlines
improperly stripped if the element is not attached to the document at the time
the stripping is done. Also, on IE 6, all newlines will be stripped from
<code>&lt;code&gt;</code> elements because of the way IE6 produces
<code>innerHTML</code>. Workaround: use <code>&lt;pre&gt;</code> for code with
newlines.
</ul>
<h1>Change Log</h1>
<h2>29 March 2007</h2>
<ul>
<li>Added <a href="tests/prettify_test.html#PHP">tests</a> for PHP support
to address
<a href="http://code.google.com/p/google-code-prettify/issues/detail?id=3"
>issue 3</a>.
<li>Fixed
<a href="http://code.google.com/p/google-code-prettify/issues/detail?id=6"
>bug</a>: <code>prettyPrintOne</code> was not halting. This was not
reachable through the normal entry point.
<li>Fixed
<a href="http://code.google.com/p/google-code-prettify/issues/detail?id=4"
>bug</a>: recursing into a script block or PHP tag that was not properly
closed would not silently drop the content.
(<a href="tests/prettify_test.html#issue4">test</a>)
<li>Fixed
<a href="http://code.google.com/p/google-code-prettify/issues/detail?id=8"
>bug</a>: was eating tabs
(<a href="tests/prettify_test.html#issue8">test</a>)
<li>Fixed entity handling so that the caveat
<blockquote>
<p>Caveats: please properly escape less-thans. <tt>x&amp;lt;y</tt>
instead of <tt>x&lt;y</tt>, and use <tt>&quot;</tt> instead of
<tt>&amp;quot;</tt> for string delimiters.</p>
</blockquote>
is no longer applicable.
<li>Added noisefree's C#
<a href="http://code.google.com/p/google-code-prettify/issues/detail?id=4"
>patch</a>
<li>Added a <a href="http://google-code-prettify.googlecode.com/files/prettify-small.zip">distribution</a> that has comments and
whitespace removed to reduce download size from 45.5kB to 12.8kB.
</ul>
<h2>4 Jul 2008</h2>
<ul>
<li>Added <a href="http://code.google.com/p/google-code-prettify/issues/detail?id=17">language specific formatters</a> that are triggered by the presence
of a <code>lang-&lt;language-file-extension&gt;</code></li>
<li>Fixed <a href="http://code.google.com/p/google-code-prettify/issues/detail?id=29">bug</a>: python handling of <code>'''string'''</code>
<li>Fixed bug: <code>/</code> in regex <code>[charsets] should not end regex</code>
</ul>
<h2>5 Jul 2008</h2>
<ul>
<li>Defined language extensions for Lisp and Lua</code>
</ul>
<h2>14 Jul 2008</h2>
<ul>
<li>Language handlers for F#, OCAML, SQL</code>
<li>Support for <code>nocode</code> spans to allow embedding of line
numbers and code annotations which should not be styled or otherwise
affect the tokenization of prettified code.
See the issue 22
<a href="tests/prettify_test.html#issue22">testcase</a>.</code>
</ul>
<h2>6 Jan 2009</h2>
<ul>
<li>Language handlers for Visual Basic, Haskell, CSS, and WikiText</li>
<li>Added <tt>.mxml</tt> extension to the markup style handler for
Flex <a href="http://en.wikipedia.org/wiki/MXML">MXML files</a>. See
<a
href="http://code.google.com/p/google-code-prettify/issues/detail?id=37"
>issue 37</a>.
<li>Added <tt>.m</tt> extension to the C style handler so that Objective
C source files properly highlight. See
<a
href="http://code.google.com/p/google-code-prettify/issues/detail?id=58"
>issue 58</a>.
<li>Changed HTML lexer to use the same embedded source mechanism as the
wiki language handler, and changed to use the registered
CSS handler for STYLE element content.
</ul>
<h2>21 May 2009</h2>
<ul>
<li>Rewrote to improve performance on large files.
See <a href="http://mikesamuel.blogspot.com/2009/05/efficient-parsing-in-javascript.html">benchmarks</a>.</li>
<li>Fixed bugs with highlighting of Haskell line comments, Lisp
number literals, Lua strings, C preprocessor directives,
newlines in Wiki code on Windows, and newlines in IE6.</li>
</ul>
<h2>14 August 2009</h2>
<ul>
<li>Fixed prettifying of <code>&lt;code&gt;</code> blocks with embedded newlines.
</ul>
<h2>3 October 2009</h2>
<ul>
<li>Fixed prettifying of XML/HTML tags that contain uppercase letters.
</ul>
<h2>19 July 2010</h2>
<ul>
<li>Added support for line numbers. Bug
<a href="http://code.google.com/p/google-code-prettify/issues/detail?id=22"
>22</a></li>
<li>Added YAML support. Bug
<a href="http://code.google.com/p/google-code-prettify/issues/detail?id=123"
>123</a></li>
<li>Added VHDL support courtesy Le Poussin.</li>
<li>IE performance improvements. Bug
<a href="http://code.google.com/p/google-code-prettify/issues/detail?id=102"
>102</a> courtesy jacobly.</li>
<li>A variety of markup formatting fixes courtesy smain and thezbyg.</li>
<li>Fixed copy and paste in IE[678].
<li>Changed output to use <code>&amp;#160;</code> instead of
<code>&amp;nbsp;</code> so that the output works when embedded in XML.
Bug
<a href="http://code.google.com/p/google-code-prettify/issues/detail?id=108"
>108</a>.</li>
</ul>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Javascript code prettifier</title>
<link href="src/prettify.css" type="text/css" rel="stylesheet" />
<script src="src/prettify.js" type="text/javascript"></script>
<style type="text/css">
body { margin-left: .5in }
h1, h2, h3, h4, .footer { margin-left: -.4in; }
</style>
</head>
<body onload="prettyPrint()" bgcolor="white">
<small style="float: right">Languages : <a href="README-zh-Hans.html">CH</a></small>
<h1>Javascript code prettifier</h1>
<h2>Setup</h2>
<ol>
<li><a href="http://code.google.com/p/google-code-prettify/downloads/list">Download</a> a distribution
<li>Include the script and stylesheets in your document
(you will need to make sure the css and js file are on your server, and
adjust the paths in the <tt>script</tt> and <tt>link</tt> tag)
<pre class="prettyprint">
&lt;link href="prettify.css" type="text/css" rel="stylesheet" />
&lt;script type="text/javascript" src="prettify.js">&lt;/script></pre>
<li>Add <code class="prettyprint lang-html">onload="prettyPrint()"</code> to your
document's body tag.
<li>Modify the stylesheet to get the coloring you prefer</li>
</ol>
<h2>Usage</h2>
<p>Put code snippets in
<tt>&lt;pre class="prettyprint"&gt;...&lt;/pre&gt;</tt>
or <tt>&lt;code class="prettyprint"&gt;...&lt;/code&gt;</tt>
and it will automatically be pretty printed.
<table summary="code examples">
<tr>
<th>The original
<th>Prettier
<tr>
<td><pre style="border: 1px solid #888;padding: 2px"
><a name="voila1"></a>class Voila {
public:
// Voila
static const string VOILA = "Voila";
// will not interfere with embedded <a href="#voila1">tags</a>.
}</pre>
<td><pre class="prettyprint"><a name="voila2"></a>class Voila {
public:
// Voila
static const string VOILA = "Voila";
// will not interfere with embedded <a href="#voila2">tags</a>.
}</pre>
</table>
<h2>FAQ</h2>
<h3 id="langs">Which languages does it work for?</h3>
<p>The comments in <tt>prettify.js</tt> are authoritative but the lexer
should work on a number of languages including C and friends,
Java, Python, Bash, SQL, HTML, XML, CSS, Javascript, and Makefiles.
It works passably on Ruby, PHP, VB, and Awk and a decent subset of Perl
and Ruby, but, because of commenting conventions, doesn't work on
Smalltalk, or CAML-like languages.</p>
<p>LISPy languages are supported via an extension:
<a href="http://code.google.com/p/google-code-prettify/source/browse/trunk/src/lang-lisp.js"
><code>lang-lisp.js</code></a>.</p>
<p>And similarly for
<a href="http://code.google.com/p/google-code-prettify/source/browse/trunk/src/lang-css.js"
><code>CSS</code></a>,
<a href="http://code.google.com/p/google-code-prettify/source/browse/trunk/src/lang-hs.js"
><code>Haskell</code></a>,
<a href="http://code.google.com/p/google-code-prettify/source/browse/trunk/src/lang-lua.js"
><code>Lua</code></a>,
<a href="http://code.google.com/p/google-code-prettify/source/browse/trunk/src/lang-ml.js"
><code>OCAML, SML, F#</code></a>,
<a href="http://code.google.com/p/google-code-prettify/source/browse/trunk/src/lang-vb.js"
><code>Visual Basic</code></a>,
<a href="http://code.google.com/p/google-code-prettify/source/browse/trunk/src/lang-sql.js"
><code>SQL</code></a>,
<a href="http://code.google.com/p/google-code-prettify/source/browse/trunk/src/lang-proto.js"
><code>Protocol Buffers</code></a>, and
<a href="http://code.google.com/p/google-code-prettify/source/browse/trunk/src/lang-wiki.js"
><code>WikiText</code></a>..
<p>If you'd like to add an extension for your favorite language, please
look at <tt>src/lang-lisp.js</tt> and file an
<a href="http://code.google.com/p/google-code-prettify/issues/list"
>issue</a> including your language extension, and a testcase.</p>
<h3>How do I specify which language my code is in?</h3>
<p>You don't need to specify the language since <code>prettyprint()</code>
will guess. You can specify a language by specifying the language extension
along with the <code>prettyprint</code> class like so:</p>
<pre class="prettyprint lang-html"
>&lt;pre class=&quot;prettyprint <b>lang-html</b>&quot;&gt;
The lang-* class specifies the language file extensions.
File extensions supported by default include
"bsh", "c", "cc", "cpp", "cs", "csh", "cyc", "cv", "htm", "html",
"java", "js", "m", "mxml", "perl", "pl", "pm", "py", "rb", "sh",
"xhtml", "xml", "xsl".
&lt;/pre&gt;</pre>
<h3>It doesn't work on <tt>&lt;obfuscated code sample&gt;</tt>?</h3>
<p>Yes. Prettifying obfuscated code is like putting lipstick on a pig
&mdash; i.e. outside the scope of this tool.</p>
<h3>Which browsers does it work with?</h3>
<p>It's been tested with IE 6, Firefox 1.5 &amp; 2, and Safari 2.0.4.
Look at <a href="tests/prettify_test.html">the test page</a> to see if it
works in your browser.</p>
<h3>What's changed?</h3>
<p>See the <a href="CHANGES.html">change log</a></p>
<h3>Why doesn't Prettyprinting of strings work on WordPress?</h3>
<p>Apparently wordpress does "smart quoting" which changes close quotes.
This causes end quotes to not match up with open quotes.
<p>This breaks prettifying as well as copying and pasting of code samples.
See
<a href="http://wordpress.org/support/topic/125038"
>WordPress's help center</a> for info on how to stop smart quoting of code
snippets.</p>
<h3 id="linenums">How do I put line numbers in my code?</h3>
<p>You can use the <code>linenums</code> class to turn on line
numbering. If your code doesn't start at line number 1, you can
add a colon and a line number to the end of that class as in
<code>linenums:52</code>.
<p>For example
<pre class="prettyprint">&lt;pre class="prettyprint linenums:<b>4</b>"
&gt;// This is line 4.
foo();
bar();
baz();
boo();
far();
faz();
&lt;pre&gt;</pre>
produces
<pre class="prettyprint linenums:4"
>// This is line 4.
foo();
bar();
baz();
boo();
far();
faz();
</pre>
<h3>How do I prevent a portion of markup from being marked as code?</h3>
<p>You can use the <code>nocode</code> class to identify a span of markup
that is not code.
<pre class="prettyprint">&lt;pre class=prettyprint&gt;
int x = foo(); /* This is a comment &lt;span class="nocode"&gt;This is not code&lt;/span&gt;
Continuation of comment */
int y = bar();
&lt;/pre&gt;</pre>
produces
<pre class="prettyprint">
int x = foo(); /* This is a comment <span class="nocode">This is not code</span>
Continuation of comment */
int y = bar();
</pre>
<p>For a more complete example see the issue22
<a href="tests/prettify_test.html#issue22">testcase</a>.</p>
<h3>I get an error message "a is not a function" or "opt_whenDone is not a function"</h3>
<p>If you are calling <code>prettyPrint</code> via an event handler, wrap it in a function.
Instead of doing
<blockquote>
<code class="prettyprint lang-js"
>addEventListener('load', prettyPrint, false);</code>
</blockquote>
wrap it in a closure like
<blockquote>
<code class="prettyprint lang-js"
>addEventListener('load', function (event) { prettyPrint() }, false);</code>
</blockquote>
so that the browser does not pass an event object to <code>prettyPrint</code> which
will confuse it.
<br><br><br>
<div class="footer">
<!-- Created: Tue Oct 3 17:51:56 PDT 2006 -->
<!-- hhmts start -->
Last modified: Wed Jul 19 13:56:00 PST 2010
<!-- hhmts end -->
</div>
</body>
</html>
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
\ No newline at end of file
<!doctype html>
<html>
<head>
<title>Redirector</title>
<meta http-equiv="refresh" content="0;url=../">
</head>
<body>
<a href="../">Click here to redirect</a>
</body>
</html>
<!doctype html>
<html>
<head>
<title>Redirector</title>
<meta http-equiv="refresh" content="0;url=../">
</head>
<body>
<a href="../">Click here to redirect</a>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>index.js</title>
<link rel="stylesheet" href="http:&#x2F;&#x2F;yui.yahooapis.com&#x2F;3.8.0&#x2F;build&#x2F;cssgrids&#x2F;cssgrids-min.css">
<link rel="stylesheet" href="..&#x2F;assets/vendor/prettify/prettify-min.css">
<link rel="stylesheet" href="..&#x2F;assets/css/main.css" id="site_styles">
<link rel="shortcut icon" type="image/png" href="..&#x2F;assets/favicon.png">
<script src="http:&#x2F;&#x2F;yui.yahooapis.com&#x2F;combo?3.8.0&#x2F;build&#x2F;yui&#x2F;yui-min.js"></script>
</head>
<body class="yui3-skin-sam">
<div id="doc">
<div id="hd" class="yui3-g header">
<div class="yui3-u-3-4">
<h1><img src="..&#x2F;assets/css/logo.png" title=""></h1>
</div>
<div class="yui3-u-1-4 version">
<em>API Docs for: </em>
</div>
</div>
<div id="bd" class="yui3-g">
<div class="yui3-u-1-4">
<div id="docs-sidebar" class="sidebar apidocs">
<div id="api-list">
<h2 class="off-left">APIs</h2>
<div id="api-tabview" class="tabview">
<ul class="tabs">
<li><a href="#api-classes">Classes</a></li>
<li><a href="#api-modules">Modules</a></li>
</ul>
<div id="api-tabview-filter">
<input type="search" id="api-filter" placeholder="Type to filter APIs">
</div>
<div id="api-tabview-panel">
<ul id="api-classes" class="apis classes">
<li><a href="..&#x2F;classes/QueryInterface.html">QueryInterface</a></li>
<li><a href="..&#x2F;classes/Sequelize.html">Sequelize</a></li>
</ul>
<ul id="api-modules" class="apis modules">
<li><a href="..&#x2F;modules/Sequelize.html">Sequelize</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="yui3-u-3-4">
<div id="api-options">
Show:
<label for="api-show-inherited">
<input type="checkbox" id="api-show-inherited" checked>
Inherited
</label>
<label for="api-show-protected">
<input type="checkbox" id="api-show-protected">
Protected
</label>
<label for="api-show-private">
<input type="checkbox" id="api-show-private">
Private
</label>
<label for="api-show-deprecated">
<input type="checkbox" id="api-show-deprecated">
Deprecated
</label>
</div>
<div class="apidocs">
<div id="docs-main">
<div class="content">
<h1 class="file-heading">File: index.js</h1>
<div class="file">
<pre class="code prettyprint linenums">
&#x2F;**
The entry point.
@module Sequelize
**&#x2F;
module.exports = require(&quot;.&#x2F;lib&#x2F;sequelize&quot;)
</pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="..&#x2F;assets/vendor/prettify/prettify-min.js"></script>
<script>prettyPrint();</script>
<script src="..&#x2F;assets/js/yui-prettify.js"></script>
<script src="..&#x2F;assets/../api.js"></script>
<script src="..&#x2F;assets/js/api-filter.js"></script>
<script src="..&#x2F;assets/js/api-list.js"></script>
<script src="..&#x2F;assets/js/api-search.js"></script>
<script src="..&#x2F;assets/js/apidocs.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>lib&#x2F;dialects&#x2F;sqlite&#x2F;query-interface.js</title>
<link rel="stylesheet" href="http:&#x2F;&#x2F;yui.yahooapis.com&#x2F;3.8.0&#x2F;build&#x2F;cssgrids&#x2F;cssgrids-min.css">
<link rel="stylesheet" href="..&#x2F;assets/vendor/prettify/prettify-min.css">
<link rel="stylesheet" href="..&#x2F;assets/css/main.css" id="site_styles">
<link rel="shortcut icon" type="image/png" href="..&#x2F;assets/favicon.png">
<script src="http:&#x2F;&#x2F;yui.yahooapis.com&#x2F;combo?3.8.0&#x2F;build&#x2F;yui&#x2F;yui-min.js"></script>
</head>
<body class="yui3-skin-sam">
<div id="doc">
<div id="hd" class="yui3-g header">
<div class="yui3-u-3-4">
<h1><img src="..&#x2F;assets/css/logo.png" title=""></h1>
</div>
<div class="yui3-u-1-4 version">
<em>API Docs for: </em>
</div>
</div>
<div id="bd" class="yui3-g">
<div class="yui3-u-1-4">
<div id="docs-sidebar" class="sidebar apidocs">
<div id="api-list">
<h2 class="off-left">APIs</h2>
<div id="api-tabview" class="tabview">
<ul class="tabs">
<li><a href="#api-classes">Classes</a></li>
<li><a href="#api-modules">Modules</a></li>
</ul>
<div id="api-tabview-filter">
<input type="search" id="api-filter" placeholder="Type to filter APIs">
</div>
<div id="api-tabview-panel">
<ul id="api-classes" class="apis classes">
<li><a href="..&#x2F;classes/QueryInterface.html">QueryInterface</a></li>
<li><a href="..&#x2F;classes/Sequelize.html">Sequelize</a></li>
</ul>
<ul id="api-modules" class="apis modules">
<li><a href="..&#x2F;modules/Sequelize.html">Sequelize</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="yui3-u-3-4">
<div id="api-options">
Show:
<label for="api-show-inherited">
<input type="checkbox" id="api-show-inherited" checked>
Inherited
</label>
<label for="api-show-protected">
<input type="checkbox" id="api-show-protected">
Protected
</label>
<label for="api-show-private">
<input type="checkbox" id="api-show-private">
Private
</label>
<label for="api-show-deprecated">
<input type="checkbox" id="api-show-deprecated">
Deprecated
</label>
</div>
<div class="apidocs">
<div id="docs-main">
<div class="content">
<h1 class="file-heading">File: lib&#x2F;dialects&#x2F;sqlite&#x2F;query-interface.js</h1>
<div class="file">
<pre class="code prettyprint linenums">
var Utils = require(&quot;..&#x2F;..&#x2F;utils&quot;)
&#x2F;**
Returns an object that treats SQLite&#x27;s inabilities to do certain queries.
@class QueryInterface
@static
*&#x2F;
var QueryInterface = module.exports = {
&#x2F;**
A wrapper that fixes SQLite&#x27;s inability to remove columns from existing tables.
It will create a backup of the table, drop the table afterwards and create a
new table with the same name but without the obsolete column.
@method removeColumn
@for QueryInterface
@param {String} tableName The name of the table.
@param {String} attributeName The name of the attribute that we want to remove.
@param {CustomEventEmitter} emitter The EventEmitter from outside.
@param {Function} queryAndEmit The function from outside that triggers some events to get triggered.
@since 1.6.0
*&#x2F;
removeColumn: function(tableName, attributeName, emitter, queryAndEmit) {
this.describeTable(tableName).complete(function(err, fields) {
if (err) {
emitter.emit(&#x27;error&#x27;, err)
} else {
delete fields[attributeName]
var sql = this.QueryGenerator.removeColumnQuery(tableName, fields)
, subQueries = sql.split(&#x27;;&#x27;).filter(function(q) { return q !== &#x27;&#x27; })
QueryInterface.execMultiQuery.call(this, subQueries, &#x27;removeColumn&#x27;, emitter, queryAndEmit)
}
}.bind(this))
},
&#x2F;**
A wrapper that fixes SQLite&#x27;s inability to change columns from existing tables.
It will create a backup of the table, drop the table afterwards and create a
new table with the same name but with a modified version of the respective column.
@method changeColumn
@for QueryInterface
@param {String} tableName The name of the table.
@param {Object} attributes An object with the attribute&#x27;s name as key and it&#x27;s options as value object.
@param {CustomEventEmitter} emitter The EventEmitter from outside.
@param {Function} queryAndEmit The function from outside that triggers some events to get triggered.
@since 1.6.0
*&#x2F;
changeColumn: function(tableName, attributes, emitter, queryAndEmit) {
var attributeName = Utils._.keys(attributes)[0]
this.describeTable(tableName).complete(function(err, fields) {
if (err) {
emitter.emit(&#x27;error&#x27;, err)
} else {
fields[attributeName] = attributes[attributeName]
var sql = this.QueryGenerator.removeColumnQuery(tableName, fields)
, subQueries = sql.split(&#x27;;&#x27;).filter(function(q) { return q !== &#x27;&#x27; })
QueryInterface.execMultiQuery.call(this, subQueries, &#x27;changeColumn&#x27;, emitter, queryAndEmit)
}
}.bind(this))
},
&#x2F;**
A wrapper that fixes SQLite&#x27;s inability to rename columns from existing tables.
It will create a backup of the table, drop the table afterwards and create a
new table with the same name but with a renamed version of the respective column.
@method renameColumn
@for QueryInterface
@param {String} tableName The name of the table.
@param {String} attrNameBefore The name of the attribute before it was renamed.
@param {String} attrNameAfter The name of the attribute after it was renamed.
@param {CustomEventEmitter} emitter The EventEmitter from outside.
@param {Function} queryAndEmit The function from outside that triggers some events to get triggered.
@since 1.6.0
*&#x2F;
renameColumn: function(tableName, attrNameBefore, attrNameAfter, emitter, queryAndEmit) {
this.describeTable(tableName).complete(function(err, fields) {
if (err) {
emitter.emit(&#x27;error&#x27;, err)
} else {
fields[attrNameAfter] = Utils._.clone(fields[attrNameBefore])
delete fields[attrNameBefore]
var sql = this.QueryGenerator.renameColumnQuery(tableName, attrNameBefore, attrNameAfter, fields)
, subQueries = sql.split(&#x27;;&#x27;).filter(function(q) { return q !== &#x27;&#x27; })
QueryInterface.execMultiQuery.call(this, subQueries, &#x27;renameColumn&#x27;, emitter, queryAndEmit)
}
}.bind(this))
},
execMultiQuery: function(queries, methodName, emitter, queryAndEmit) {
var chainer = new Utils.QueryChainer()
queries.splice(0, queries.length - 1).forEach(function(query) {
chainer.add(this.sequelize, &#x27;query&#x27;, [query + &quot;;&quot;, null, { raw: true }])
}.bind(this))
chainer
.runSerially()
.complete(function(err) {
if (err) {
emitter.emit(methodName, err)
emitter.emit(&#x27;error&#x27;, err)
} else {
queryAndEmit.call(this, queries.splice(queries.length - 1)[0], methodName, {}, emitter)
}
}.bind(this))
}
}
</pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="..&#x2F;assets/vendor/prettify/prettify-min.js"></script>
<script>prettyPrint();</script>
<script src="..&#x2F;assets/js/yui-prettify.js"></script>
<script src="..&#x2F;assets/../api.js"></script>
<script src="..&#x2F;assets/js/api-filter.js"></script>
<script src="..&#x2F;assets/js/api-list.js"></script>
<script src="..&#x2F;assets/js/api-search.js"></script>
<script src="..&#x2F;assets/js/apidocs.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="http:&#x2F;&#x2F;yui.yahooapis.com&#x2F;3.8.0&#x2F;build&#x2F;cssgrids&#x2F;cssgrids-min.css">
<link rel="stylesheet" href=".&#x2F;assets/vendor/prettify/prettify-min.css">
<link rel="stylesheet" href=".&#x2F;assets/css/main.css" id="site_styles">
<link rel="shortcut icon" type="image/png" href=".&#x2F;assets/favicon.png">
<script src="http:&#x2F;&#x2F;yui.yahooapis.com&#x2F;combo?3.8.0&#x2F;build&#x2F;yui&#x2F;yui-min.js"></script>
</head>
<body class="yui3-skin-sam">
<div id="doc">
<div id="hd" class="yui3-g header">
<div class="yui3-u-3-4">
<h1><img src=".&#x2F;assets/css/logo.png" title=""></h1>
</div>
<div class="yui3-u-1-4 version">
<em>API Docs for: </em>
</div>
</div>
<div id="bd" class="yui3-g">
<div class="yui3-u-1-4">
<div id="docs-sidebar" class="sidebar apidocs">
<div id="api-list">
<h2 class="off-left">APIs</h2>
<div id="api-tabview" class="tabview">
<ul class="tabs">
<li><a href="#api-classes">Classes</a></li>
<li><a href="#api-modules">Modules</a></li>
</ul>
<div id="api-tabview-filter">
<input type="search" id="api-filter" placeholder="Type to filter APIs">
</div>
<div id="api-tabview-panel">
<ul id="api-classes" class="apis classes">
<li><a href=".&#x2F;classes/QueryInterface.html">QueryInterface</a></li>
<li><a href=".&#x2F;classes/Sequelize.html">Sequelize</a></li>
</ul>
<ul id="api-modules" class="apis modules">
<li><a href=".&#x2F;modules/Sequelize.html">Sequelize</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="yui3-u-3-4">
<div id="api-options">
Show:
<label for="api-show-inherited">
<input type="checkbox" id="api-show-inherited" checked>
Inherited
</label>
<label for="api-show-protected">
<input type="checkbox" id="api-show-protected">
Protected
</label>
<label for="api-show-private">
<input type="checkbox" id="api-show-private">
Private
</label>
<label for="api-show-deprecated">
<input type="checkbox" id="api-show-deprecated">
Deprecated
</label>
</div>
<div class="apidocs">
<div id="docs-main">
<div class="content">
<div class="apidocs">
<div id="docs-main" class="content">
<p>
Browse to a module or class using the sidebar to view its API documentation.
</p>
<h2>Keyboard Shortcuts</h2>
<ul>
<li><p>Press <kbd>s</kbd> to focus the API search box.</p></li>
<li><p>Use <kbd>Up</kbd> and <kbd>Down</kbd> to select classes, modules, and search results.</p></li>
<li class="mac-only"><p>With the API search box or sidebar focused, use <kbd><span class="cmd">&#x2318;</span>-Left</kbd> or <kbd><span class="cmd">&#x2318;</span>-Right</kbd> to switch sidebar tabs.</p></li>
<li class="pc-only"><p>With the API search box or sidebar focused, use <kbd>Ctrl+Left</kbd> and <kbd>Ctrl+Right</kbd> to switch sidebar tabs.</p></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src=".&#x2F;assets/vendor/prettify/prettify-min.js"></script>
<script>prettyPrint();</script>
<script src=".&#x2F;assets/js/yui-prettify.js"></script>
<script src=".&#x2F;assets/../api.js"></script>
<script src=".&#x2F;assets/js/api-filter.js"></script>
<script src=".&#x2F;assets/js/api-list.js"></script>
<script src=".&#x2F;assets/js/api-search.js"></script>
<script src=".&#x2F;assets/js/apidocs.js"></script>
</body>
</html>
var markdox = require('markdox')
, program = require('commander')
, fs = require('fs')
, _ = require('lodash');
program
.version('0.0.1')
.option('-f, --file [file]', 'Process a single file', '')
.option('-a, --all', 'Process all files, generate index etc. (default if no options are specified')
.option('-c, --clean', 'Remove all generated markdown and HTML files')
.option('--html', 'Generate html files from the markdown ones (requires manual installation of the github-flavored-markdown package')
.parse(process.argv)
if (program.clean) {
fs.readdirSync('docs/').forEach(function (file) {
if (file.indexOf('.ejs') === -1 && file.indexOf('.js') === -1) {
fs.unlinkSync ('docs/' + file);
}
})
return
}
if (program.html) {
var ghm = require('github-flavored-markdown')
}
var getTag = function(tags, tagName) {
return _.find(tags, function (tag) {
return tag.type === tagName;
});
};
var getTags = function(tags, tagName) {
return _.where(tags, function (tag) {
return tag.type === tagName;
});
}
var options = {
formatter: function (docfile) {
docfile = markdox.defaultFormatter(docfile);
docfile.members = [];
docfile.javadoc.forEach(function(javadoc){
// 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.private = getTag(javadoc.raw.tags, 'private') !== undefined
// Only show params without a dot in them (dots means attributes of object, so no need to clutter the signature too much)
var params = []
javadoc.paramTags.forEach(function (paramTag) {
if (paramTag.name.indexOf('.') === -1) {
params.push(paramTag.name);
}
});
javadoc.paramStr = (javadoc.isMethod || javadoc.isFunction) ? '(' + params.join(', ') + ')' : '';
// Convert | to &#124; to be able to use github flavored md tables
if (javadoc.paramTags) {
javadoc.paramTags.forEach(function (paramTag) {
paramTag.joinedTypes = paramTag.joinedTypes.replace(/\|/g, '&#124;')
});
}
// Handle aliases
javadoc.aliases = getTags(javadoc.raw.tags, 'alias').map(function (a) {
return a.string
}).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) {
collection[i] = {}
if (see.local) {
collection[i].external = false
if (see.local.indexOf('{') === 0){
var _see = see.local.split('}')
_see[0] = _see[0].substring(1)
collection[i].url = 'API-Reference-' + _see[0]
collection[i].text = see.local.replace(/{|}/g, '')
} else {
collection[i].url = false
collection[i].text = see.local
}
} else {
see.external = true
see.text = see.url
collection[i] = see
}
})
// Set a name for properties
if (!javadoc.name) {
var property = getTag(javadoc.raw.tags, 'property')
if (property) {
javadoc.name = property.string
}
}
if (javadoc.isMixin) {
javadoc.name = getTag(javadoc.raw.tags, 'mixin').string;
}
javadoc.mixes = getTags(javadoc.raw.tags, 'mixes').map(function (mix) {
return {
text: mix.string,
link: (mix.string.indexOf('www') !== -1 || mix.string.indexOf('http') !== -1) ? mix.string: 'API-Reference-' + mix.string
}
})
if (!javadoc.isClass) {
if (!javadoc.isProperty) {
docfile.members.push({
text: javadoc.name + javadoc.paramStr,
link: '#' + javadoc.name
})
} else {
docfile.members.push({
text: javadoc.name,
link: '#' + javadoc.name
})
}
}
});
return docfile;
},
template: 'docs/output.md.ejs'
};
var files;
if (program.file) {
files = [{file: program.file, output: 'tmp'}]
} else {
files = [
{file:'lib/sequelize.js', output: 'API-Reference-Sequelize'},
{file:'lib/dao.js', output: 'API-Reference-DAO'},
{file:'lib/dao-factory.js', output: 'API-Reference-DAOFactory'},
{file:'lib/query-chainer.js', output: 'API-Reference-QueryChainer'},
{file:'lib/emitters/custom-event-emitter.js', output: 'API-Reference-EventEmitter'},
{file:'lib/hooks.js', output: 'API-Reference-Hooks'},
{file:'lib/associations/mixin.js', output: 'API-Reference-Associations'}
];
}
files.forEach(function (file) {
var opts = _.clone(options)
, output = 'docs/' + file.output + '.md'
opts.output = output
markdox.process(file.file, opts, function(){
if (program.html) {
var md = fs.readFileSync(output).toString();
fs.writeFileSync(output.replace('md', 'html'), ghm.parse(md))
}
});
})
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Sequelize</title>
<link rel="stylesheet" href="http:&#x2F;&#x2F;yui.yahooapis.com&#x2F;3.8.0&#x2F;build&#x2F;cssgrids&#x2F;cssgrids-min.css">
<link rel="stylesheet" href="..&#x2F;assets/vendor/prettify/prettify-min.css">
<link rel="stylesheet" href="..&#x2F;assets/css/main.css" id="site_styles">
<link rel="shortcut icon" type="image/png" href="..&#x2F;assets/favicon.png">
<script src="http:&#x2F;&#x2F;yui.yahooapis.com&#x2F;combo?3.8.0&#x2F;build&#x2F;yui&#x2F;yui-min.js"></script>
</head>
<body class="yui3-skin-sam">
<div id="doc">
<div id="hd" class="yui3-g header">
<div class="yui3-u-3-4">
<h1><img src="..&#x2F;assets/css/logo.png" title=""></h1>
</div>
<div class="yui3-u-1-4 version">
<em>API Docs for: </em>
</div>
</div>
<div id="bd" class="yui3-g">
<div class="yui3-u-1-4">
<div id="docs-sidebar" class="sidebar apidocs">
<div id="api-list">
<h2 class="off-left">APIs</h2>
<div id="api-tabview" class="tabview">
<ul class="tabs">
<li><a href="#api-classes">Classes</a></li>
<li><a href="#api-modules">Modules</a></li>
</ul>
<div id="api-tabview-filter">
<input type="search" id="api-filter" placeholder="Type to filter APIs">
</div>
<div id="api-tabview-panel">
<ul id="api-classes" class="apis classes">
<li><a href="..&#x2F;classes/QueryInterface.html">QueryInterface</a></li>
<li><a href="..&#x2F;classes/Sequelize.html">Sequelize</a></li>
</ul>
<ul id="api-modules" class="apis modules">
<li><a href="..&#x2F;modules/Sequelize.html">Sequelize</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="yui3-u-3-4">
<div id="api-options">
Show:
<label for="api-show-inherited">
<input type="checkbox" id="api-show-inherited" checked>
Inherited
</label>
<label for="api-show-protected">
<input type="checkbox" id="api-show-protected">
Protected
</label>
<label for="api-show-private">
<input type="checkbox" id="api-show-private">
Private
</label>
<label for="api-show-deprecated">
<input type="checkbox" id="api-show-deprecated">
Deprecated
</label>
</div>
<div class="apidocs">
<div id="docs-main">
<div class="content">
<h1>Sequelize Module</h1>
<div class="box clearfix meta">
<div class="foundat">
Defined in: <a href="..&#x2F;files&#x2F;lib_sequelize.js.html#l12"><code>lib&#x2F;sequelize.js:12</code></a>
</div>
</div>
<div class="box intro">
<p>The entry point.</p>
</div>
<div class="yui3-g">
<div class="yui3-u-1-2">
<p>This module provides the following classes:</p>
<ul class="module-classes">
<li class="module-class">
<a href="..&#x2F;classes/QueryInterface.html">
QueryInterface
</a>
</li>
<li class="module-class">
<a href="..&#x2F;classes/Sequelize.html">
Sequelize
</a>
</li>
</ul>
</div>
<div class="yui3-u-1-2">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="..&#x2F;assets/vendor/prettify/prettify-min.js"></script>
<script>prettyPrint();</script>
<script src="..&#x2F;assets/js/yui-prettify.js"></script>
<script src="..&#x2F;assets/../api.js"></script>
<script src="..&#x2F;assets/js/api-filter.js"></script>
<script src="..&#x2F;assets/js/api-list.js"></script>
<script src="..&#x2F;assets/js/api-search.js"></script>
<script src="..&#x2F;assets/js/apidocs.js"></script>
</body>
</html>
<!doctype html>
<html>
<head>
<title>Redirector</title>
<meta http-equiv="refresh" content="0;url=../">
</head>
<body>
<a href="../">Click here to redirect</a>
</body>
</html>
<? docfiles.forEach(function(doc) { ?>
<? doc.javadoc.forEach(function(comment) { ?>
<? if (comment.name && comment.private !== true) { -?>
<? if (!comment.ignore) { ?>
<a name="<?= comment.name ?>" />
<? if (comment.isConstructor) { ?>
### `new <?= comment.name ?><?= comment.paramStr ?>`
<? } else if (comment.isMixin) { ?>
### Mixin <?= comment.name ?>
<? } else if (comment.isClass) { ?>
### Class <?= comment.name ?>
<? } else { ?>
#### `<?= comment.name ?><?= comment.paramStr ?>` <? if (comment.returnTags.length > 0) { ?> -> `<?= comment.returnTags[0].joinedTypes ?>` <? } ?>
<? } ?>
<? } ?>
<?= comment.description ?>
<? if (comment.mixes.length) { ?>
### Mixes:
<? comment.mixes.forEach(function (mix) { -?>
* [<?=mix.text ?>](<?=mix.link ?>)
<? }) ?>
<? } ?>
<? if (comment.isClass) { ?>
### Members:
<? doc.members.forEach(function (member) { -?>
* [<?= member.text ?>](<?= member.link ?>)
<? }) -?>
<? } ?>
<? if (comment.deprecated) { ?>
**Deprecated** <?- comment.deprecated ?>
<? } ?>
<? if (comment.version) { ?>
Version: <?= comment.version ?>
<? } ?>
<? if (comment.see.length) { ?>See:<? } ?>
<? comment.see.forEach(function (see) { -?>
<? if (see.url !== false) { -?>
* [<?= see.text ?>](<?= see.url ?>)
<? } else { -?>
* <?= see.text ?>
<? } -?>
<? }) -?>
<? if (comment.paramTags.length > 0) { ?>
##### Params:
| Name | Type | Description |
| ---- | ---- | ----------- |
<? comment.paramTags.forEach(function(paramTag) { -?>
| <?= paramTag.name ?> | <?= paramTag.joinedTypes ?> | <?= paramTag.description ?> |
<? }) ?>
<? } ?>
<? if (comment.returnTags.length > 0 && comment.returnTags[0].description.length > 0) { ?>
__Returns:__ <?= comment.returnTags[0].description ?>
<? } ?>
<? if (comment.aliases) { ?>
__Aliases:__ *<?= comment.aliases ?>*
<? } ?>
======
<? } ?>
<? }) ?>
_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 <a href="irc://irc.freenode.net/#sequelizejs">IRC</a>, 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() ?>_
<? }) ?>
\ No newline at end of file
......@@ -32,7 +32,8 @@ module.exports = (function() {
self.instance[instancePrimaryKey]
),
new Utils.where(
through.rawAttributes[self.association.foreignIdentifier], {
through.rawAttributes[self.association.foreignIdentifier],
{
join: new Utils.literal([
self.QueryInterface.quoteTable(self.association.target.name),
self.QueryInterface.quoteIdentifier(foreignPrimaryKey)
......
......@@ -90,8 +90,8 @@ function extendModelValidations(modelInstance){
/**
* The Main DAO Validator.
*
* @param {sequelize.Model} modelInstance The model instance.
* @param {Object=} options A dict with options.
* @param {DAO} modelInstance The model instance.
* @param {Object} options A dict with options.
* @constructor
*/
var DaoValidator = module.exports = function(modelInstance, options) {
......@@ -106,9 +106,9 @@ var DaoValidator = module.exports = function(modelInstance, options) {
this.chainer = new Utils.QueryChainer()
/**
* Expose validator.js to allow users to extend
* Exposes a reference to validator.js. This allows you to add custom validations using `Validator.extend`
* @name Validator
*/
*/
this.Validator = Validator
/**
......@@ -131,7 +131,7 @@ DaoValidator.RAW_KEY_NAME = '__raw'
/**
* The main entry point for the Validation module, invoke to start the dance.
*
* @return {sequelize.Utils.CustomEventEmitter} That thing...
* @return {EventEmitter}
*/
DaoValidator.prototype.validate = function() {
if (this.inProgress) {
......@@ -161,7 +161,7 @@ DaoValidator.prototype.validate = function() {
* - Validation
* - After Validation Model Hooks
*
* @return {sequelize.Utils.CustomEventEmitter} An eventemitter.
* @return {EventEmitter}
*/
DaoValidator.prototype.hookValidate = function() {
var self = this
......
......@@ -12,12 +12,53 @@ var bindToProcess = function(fct) {
return fct
}
/**
* The EventEmitter is returned from all asynchronous Sequelize calls - So almost all of them.
* The emitter provides a lovely mix of native node.js `EventEmitter` and promise methods.
*
* There are several different syntaxes for attaching listeners to the emitter:
*
* ```js
* Model.find(...).on('success', function (dao) {
* // Using it as a regular node emitter
* })
*
* Model.find(...).success(function (dao) {
* // Using the shortcut methods
* })
*
* Model.find(...).done(function (err, dao) {
* // Using the done method, which is called both if the operation succeeds,
* // and if it fails. On success, the err argument will be null
* })
*
* Model.find(...).then(function (dao) {
* // Using the emitter as a promise. The first function is the success handler,
* // and the second is the error handler.
* }, function (err) {
*
* })
* ```
*
* @mixes http://nodejs.org/api/events.html#events_class_events_eventemitter
* @class EventEmitter
*/
module.exports = (function() {
/**
* Create a new emitter instance.
*
* @constructor CustomEventEmitter
* @param {function} fct A function that this emitter should run. The function is called with the emitter as first argument and as context
*/
var CustomEventEmitter = function(fct) {
this.fct = bindToProcess(fct)
}
util.inherits(CustomEventEmitter, EventEmitter)
/**
* Run the function that was passed when the emitter was instantiated.
* @return this
*/
CustomEventEmitter.prototype.run = function() {
Utils.tick(function() {
if (this.fct) {
......@@ -28,6 +69,11 @@ module.exports = (function() {
return this
}
/**
* Emit an event from the emitter
* @param {string} type The type of event
* @param {any} value(s)* All other arguments will be passed to the event listeners
*/
CustomEventEmitter.prototype.emit = function(type) {
this._events = this._events || {};
......@@ -62,14 +108,19 @@ module.exports = (function() {
};
/**
Shortcut methods (success, ok) for listening for success events.
Params:
- fct: A function that gets executed once the *success* event was triggered.
Result:
The function returns the instance of the query.
*/
* Listen for success events.
*
* ```js
* emitter.success(function (result) {
* //...
* });
* ```
*
* @param {function} onSuccess
* @method success
* @alias ok
* @return this
*/
CustomEventEmitter.prototype.success =
CustomEventEmitter.prototype.ok =
function(fct) {
......@@ -78,14 +129,20 @@ module.exports = (function() {
}
/**
Shortcut methods (failure, fail, error) for listening for error events.
Params:
- fct: A function that gets executed once the *error* event was triggered.
Result:
The function returns the instance of the query.
*/
* Listen for error events
*
* ```js
* emitter.error(function (err) {
* //...
* });
* ```
*
* @param {function} onError
* @metohd error
* @alias fail
* @alias failure
* @return this
*/
CustomEventEmitter.prototype.failure =
CustomEventEmitter.prototype.fail =
CustomEventEmitter.prototype.error =
......@@ -94,6 +151,20 @@ module.exports = (function() {
return this;
}
/**
* Listen for both success and error events.
*
* ```js
* emitter.done(function (err, result) {
* //...
* });
* ```
*
* @param {function} onDone
* @method done
* @alias complete
* @return this
*/
CustomEventEmitter.prototype.done =
CustomEventEmitter.prototype.complete =
function(fct) {
......@@ -107,16 +178,23 @@ module.exports = (function() {
return this
}
/*
* Attach a function that is called every time the function that created this emitter executes a query.
* @param {function} onSQL
* @return this
*/
CustomEventEmitter.prototype.sql = function(fct) {
this.on('sql', bindToProcess(fct))
return this;
}
/**
* Proxy every event of this custom event emitter to another one.
* Proxy every event of this event emitter to another one.
*
* @param {CustomEventEmitter} emitter The event emitter that should receive the events.
* @return {void}
* @param {EventEmitter} emitter The event emitter that should receive the events.
* @param {Object} [options]
* @param {Array} [options.events] An array of the events to proxy. Defaults to sql, error and success
* @return this
*/
CustomEventEmitter.prototype.proxy = function(emitter, options) {
options = Utils._.extend({
......@@ -136,6 +214,13 @@ module.exports = (function() {
return this
}
/**
* Attach listeners to the emitter, promise style.
*
* @param {Function} onFulfilled The function to call if the promise is fulfilled (if the emitter emits success). Note that this function will always only be called with one argument, as per the promises/A spec. For functions that emit multiple arguments (e.g. findOrCreate) see `spread`
* @param {Function} onRejected
* @return {Bluebird.Promise}
*/
CustomEventEmitter.prototype.then = function(onFulfilled, onRejected) {
var self = this
......@@ -148,6 +233,13 @@ module.exports = (function() {
}).then(onFulfilled, onRejected)
}
/**
* Attach listeners to the emitter, promise style. This listener will recieve all arguments emitted by the emitter, as opposed to `then` which will only recieve the first argument.
*
* @param {Function} onFulfilled The function to call if the promise is fulfilled (if the emitter emits success).
* @param {Function} onRejected
* @return {Bluebird.Promise}
*/
CustomEventEmitter.prototype.spread = function(onFulfilled, onRejected) {
var self = this
......@@ -162,6 +254,12 @@ module.exports = (function() {
}).spread(onFulfilled, onRejected)
}
/**
* Shorthand for `then(null, onRejected)`
*
* @param {Function} onRejected
* @return {Bluebird.Promise}
*/
CustomEventEmitter.prototype.catch = function(onRejected) {
return this.then(null, onRejected)
}
......
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 hookAliases = {
beforeDelete: "beforeDestroy",
......@@ -65,11 +97,18 @@ Hooks.runHooks = function() {
run(hooks[tick])
}
// Alias for `.addHook`
Hooks.hook = function() {
Hooks.addHook.apply(this, arguments)
}
/**
* Add a hook to the model
*
* @param {String} hooktype
* @param {String} [name] Provide a name for the hook function. This serves no purpose, other than the ability to be able to order hooks based on some sort of priority system in the future.
* @param {Function} fn The hook function
* @alias hook
*/
Hooks.addHook = function(hookType, name, fn) {
if (typeof name === "function") {
fn = name
......@@ -88,26 +127,58 @@ Hooks.addHook = function(hookType, name, fn) {
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 instance, callback(err)
*/
Hooks.beforeValidate = function(name, fn) {
Hooks.addHook.call(this, 'beforeValidate', name, fn)
}
/**
* A hook that is run after validation
* @param {String} name
* @param {Function} fn A callback function that is called with instance, callback(err)
*/
Hooks.afterValidate = function(name, fn) {
Hooks.addHook.call(this, 'afterValidate', name, fn)
}
/**
* A hook that is run before creating a single instance
* @param {String} name
* @param {Function} fn A callback function that is called with attributes, callback(err)
*/
Hooks.beforeCreate = function(name, fn) {
Hooks.addHook.call(this, 'beforeCreate', name, fn)
}
/**
* A hook that is run after creating a single instance
* @param {String} name
* @param {Function} fn A callback function that is called with attributes, callback(err)
*/
Hooks.afterCreate = function(name, fn) {
Hooks.addHook.call(this, 'afterCreate', name, fn)
}
/**
* A hook that is run before destroying a single instance
* @param {String} name
* @param {Function} fn A callback function that is called with instance, callback(err)
* alias beforeDelete
*/
Hooks.beforeDestroy = function(name, fn) {
Hooks.addHook.call(this, 'beforeDestroy', name, fn)
}
/**
* A hook that is run after destroying a single instance
* @param {String} name
* @param {Function} fn A callback function that is called with instance, callback(err)
* @alias afterDelete
*/
Hooks.afterDestroy = function(name, fn) {
Hooks.addHook.call(this, 'afterDestroy', name, fn)
}
......@@ -120,34 +191,74 @@ Hooks.afterDelete = function(name, fn) {
Hooks.addHook.call(this, 'afterDelete', name, fn)
}
/**
* A hook that is run before updating a single instance
* @param {String} name
* @param {Function} fn A callback function that is called with instance, callback(err)
*/
Hooks.beforeUpdate = function(name, fn) {
Hooks.addHook.call(this, 'beforeUpdate', name, fn)
}
/**
* A hook that is run after updating a single instance
* @param {String} name
* @param {Function} fn A callback function that is called with instance, callback(err)
*/
Hooks.afterUpdate = function(name, fn) {
Hooks.addHook.call(this, 'afterUpdate', name, fn)
}
/**
* A hook that is run before creating instances in bulk
* @param {String} name
* @param {Function} fn A callback function that is called with instances, fields, callback(err)
*/
Hooks.beforeBulkCreate = function(name, fn) {
Hooks.addHook.call(this, 'beforeBulkCreate', name, fn)
}
/**
* A hook that is run after creating instances in bulk
* @param {String} name
* @param {Function} fn A callback function that is called with instances, fields, callback(err)
*/
Hooks.afterBulkCreate = function(name, fn) {
Hooks.addHook.call(this, 'afterBulkCreate', name, fn)
}
/**
* A hook that is run before destroing instances in bulk
* @param {String} name
* @param {Function} fn A callback function that is called with where, callback(err)
*/
Hooks.beforeBulkDestroy = function(name, fn) {
Hooks.addHook.call(this, 'beforeBulkDestroy', name, fn)
}
/**
* A hook that is run after destroying instances in bulk
* @param {String} name
* @param {Function} fn A callback function that is called with where, callback(err)
*/
Hooks.afterBulkDestroy = function(name, fn) {
Hooks.addHook.call(this, 'afterBulkDestroy', name, fn)
}
/**
* A hook that is run after updating instances in bulk
* @param {String} name
* @param {Function} fn A callback function that is called with attribute, where, callback(err)
*/
Hooks.beforeBulkUpdate = function(name, fn) {
Hooks.addHook.call(this, 'beforeBulkUpdate', name, fn)
}
/**
* A hook that is run after updating instances in bulk
* @param {String} name
* @param {Function} fn A callback function that is called with attribute, where, callback(err)
*/
Hooks.afterBulkUpdate = function(name, fn) {
Hooks.addHook.call(this, 'afterBulkUpdate', name, fn)
}
var Utils = require(__dirname + "/utils")
module.exports = (function() {
/**
* The sequelize query chainer allows you to run several queries, either in parallel or serially, and attach a callback that is called when all queries are done.
* @class QueryChainer
*/
var QueryChainer = function(emitters) {
var self = this
......@@ -24,6 +28,44 @@ module.exports = (function() {
})
}
/**
* Add an query to the chainer. This can be done in two ways - either by invoking the method like you would normally, and then adding the returned emitter to the chainer, or by passing the
* class that you want to call a method on, the name of the method, and its parameters to the chainer. The second form might sound a bit cumbersome, but it is used when you want to run
* queries in serial.
*
* *Method 1:*
* ```js
* chainer.add(User.findAll({
* where: {
* admin: true
* },
* limit: 3
* }))
* chainer.add(Project.findAll())
* chainer.run().done(function (err, users, project) {
*
* })
* ```
*
* *Method 2:*
* ```js
* chainer.add(User, 'findAll', {
* where: {
* admin: true
* },
* limit: 3
* })
* chainer.add(Project, 'findAll')
* chainer.runSerially().done(function (err, users, project) {
*
* })
* ```
* @param {EventEmitter|Any} emitterOrKlass
* @param {String} [method]
* @param {Object} [params]
* @param {Object} [options]
* @return this
*/
QueryChainer.prototype.add = function(emitterOrKlass, method, params, options) {
if (!!method) {
this.serials.push({ klass: emitterOrKlass, method: method, params: params, options: options })
......@@ -35,6 +77,10 @@ module.exports = (function() {
return this
}
/**
* Run the query chainer. In reality, this means, wait for all the added emtiters to finish, since the queries began executing as soon as you invoked their methods.
* @return {EventEmitter}
*/
QueryChainer.prototype.run = function() {
var self = this
this.eventEmitter = new Utils.CustomEventEmitter(function() {
......@@ -44,6 +90,12 @@ module.exports = (function() {
return this.eventEmitter.run()
}
/**
* Run the chainer serially, so that each query waits for the previous one to finish before it starts.
* @param {Object} [options]
* @param {Object} [options.skipOnError=false] If set to true, all pending emitters will be skipped if a previous emitter failed
* @return {EventEmitter}
*/
QueryChainer.prototype.runSerially = function(options) {
var self = this
, serialCopy = Utils._.clone(this.serials)
......
......@@ -5,6 +5,10 @@ var Utils = require(__dirname + '/utils')
, QueryTypes = require('./query-types')
module.exports = (function() {
/*
* The interface that Sequelize uses to talk to all databases
* @class QueryInterface
**/
var QueryInterface = function(sequelize) {
this.sequelize = sequelize
this.QueryGenerator = require('./dialects/' + this.sequelize.options.dialect + '/query-generator')
......
var Utils = require('./utils')
, util = require('util')
/**
* The transaction object is used to identify a running transaction. It is created by calling `Sequelize.transaction()`.
*
* To run a query under a transaction, you should pass the transaction in the options object.
* @class Transaction
*/
var Transaction = module.exports = function(sequelize, options) {
this.sequelize = sequelize
this.id = Utils.generateUUID()
......@@ -12,6 +18,20 @@ var Transaction = module.exports = function(sequelize, options) {
util.inherits(Transaction, Utils.CustomEventEmitter)
/**
* The possible isolations levels to use when starting a transaction
*
* ```js
* {
* READ_UNCOMMITTED: "READ UNCOMMITTED",
* READ_COMMITTED: "READ COMMITTED",
* REPEATABLE_READ: "REPEATABLE READ",
* SERIALIZABLE: "SERIALIZABLE"
* }
* ```
*
* @property ISOLATION_LEVELS
*/
Transaction.ISOLATION_LEVELS = {
READ_UNCOMMITTED: "READ UNCOMMITTED",
READ_COMMITTED: "READ COMMITTED",
......@@ -19,6 +39,11 @@ Transaction.ISOLATION_LEVELS = {
SERIALIZABLE: "SERIALIZABLE"
}
/**
* Commit the transaction
*
* @return {this}
*/
Transaction.prototype.commit = function() {
return this
.sequelize
......@@ -29,6 +54,11 @@ Transaction.prototype.commit = function() {
}
/**
* Rollback (abort) the transaction
*
* @return {this}
*/
Transaction.prototype.rollback = function() {
return this
.sequelize
......
......@@ -70,6 +70,7 @@
"coveralls": "~2.7.1",
"async": "~0.2.10",
"coffee-script": "~1.7.1",
"markdox": "0.1.4",
"sinon-chai": "~2.5.0"
},
"keywords": [
......
......@@ -27,6 +27,7 @@ if (dialect.match(/^postgres/)) {
done()
})
it('should be able to search within an array', function(done) {
this.User.all({where: {email: ['hello', 'world']}}).on('sql', function(sql) {
expect(sql).to.equal('SELECT * FROM "Users" AS "User" WHERE "User"."email" && ARRAY[\'hello\',\'world\']::TEXT[];')
......@@ -333,7 +334,7 @@ if (dialect.match(/^postgres/)) {
.error(console.log)
})
})
describe('[POSTGRES] Unquoted identifiers', function() {
it("can insert and select", function(done) {
var self = this
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!