forked from coresmart/persistencejs
-
Notifications
You must be signed in to change notification settings - Fork 2
/
compositor.json
143 lines (143 loc) · 40.2 KB
/
compositor.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
{
"name": "rsaccon/persistencejs",
"version": "0.1.4",
"libraries": {
"xv": "^1.1.25"
},
"title": "",
"branch": "",
"style": {
"name": "Default",
"componentSet": {
"nav": "nav/BasicNav",
"header": "header/BannerHeader",
"article": "article/BasicArticle",
"footer": "footer/BasicFooter"
},
"fontFamily": "-apple-system, BlinkMacSystemFont, sans-serif",
"fontWeight": 400,
"bold": 600,
"lineHeight": 1.5,
"typeScale": [
72,
48,
24,
20,
16,
14,
12
],
"monospace": "Menlo, monospace",
"heading": {
"fontFamily": null,
"fontStyle": null,
"fontWeight": 600,
"lineHeight": 1.25,
"textTransform": null,
"letterSpacing": null
},
"h0": {},
"h1": {},
"h2": {},
"h3": {},
"h4": {},
"h5": {},
"h6": {},
"alternativeText": {},
"space": [
0,
8,
16,
32,
48,
64,
96
],
"layout": {
"maxWidth": 1024,
"centered": false
},
"colors": {
"text": "#111",
"background": "#fff",
"primary": "#08e",
"secondary": "#059",
"highlight": "#e08",
"border": "#ddd",
"muted": "#eee"
},
"border": {
"width": 1,
"radius": 2
},
"link": {},
"button": {
"hover": {
"boxShadow": "inset 0 0 0 999px rgba(0, 0, 0, .125)"
}
},
"input": {},
"body": {
"margin": 0
},
"breakpoints": {
"xs": "@media screen and (max-width:40em)",
"sm": "@media screen and (min-width:40em)",
"md": "@media screen and (min-width:52em)",
"lg": "@media screen and (min-width:64em)"
}
},
"content": [
{
"component": "nav",
"links": [
{
"href": "https://github.com/rsaccon/persistencejs",
"text": "GitHub"
},
{
"href": "https://npmjs.com/package/persistencejs",
"text": "npm"
}
]
},
{
"component": "header",
"heading": "persistencejs",
"subhead": "persistence.js is a simple asynchronous Javascript object-relational mapper library. In the browser it works with HTML5 SQLite databases as well as Google Gears' local data store. On the server-side we are working on different back-ends. Currently there is a MySQL back-end.",
"children": [
{
"component": "ui/TweetButton",
"text": "persistencejs: persistence.js is a simple asynchronous Javascript object-relational mapper library. In the browser it works with HTML5 SQLite databases as well as Google Gears' local data store. On the server-side we are working on different back-ends. Currently there is a MySQL back-end.",
"url": ""
},
{
"component": "ui/GithubButton",
"user": "rsaccon",
"repo": "persistencejs"
}
],
"text": "v0.2.2"
},
{
"component": "article",
"metadata": {
"source": "github.readme"
},
"html": "\n<p><code>persistence.js</code> is a asynchronous Javascript object-relational\nmapper library. It can be used both in the web browser and on\nthe server using <a href=\"http://nodejs.org\">node.js</a>. It currently\nsupports 4 types of data stores:</p>\n<ul>\n<li><a href=\"http://dev.w3.org/html5/webdatabase/\">HTML5 WebSQL database</a>, a\nsomewhat controversial part of HTML5 that is supported in Webkit\nbrowsers, specifically on mobile devices, including iPhone, Android\nand Palm's WebOS. </li>\n<li><a href=\"http://gears.google.com\">Google Gears</a>, a browser plug-in that adds\na number of feature to the browser, including a in-browser database.</li>\n<li><a href=\"http://www.mysql.com\">MySQL</a>, using the\n<a href=\"http://github.com/felixge/node-mysql\">node-mysql</a>, node.js module\non the server.</li>\n<li>In-memory, as a fallback. Keeps the database in memory and is cleaned\nupon a page refresh (or server restart).</li>\n</ul>\n<p>There is also an experimental support for <a href=\"http://doc.trolltech.org/4.7-snapshot/declarativeui.html\">Qt 4.7 Declarative UI\nframework\n(QML)</a> which\nis an extension to JavaScript.</p>\n<p>For browser use, <code>persistence.js</code> has no dependencies on any other\nframeworks, other than the Google Gears <a href=\"http://code.google.com/apis/gears/gears_init.js\">initialization\nscript</a>, in case you\nwant to enable Gears support.</p>\n<h2>Plug-ins</h2>\n<p>There are a few <code>persistence.js</code> plug-ins available that add functionality:</p>\n<ul>\n<li><code>persistence.search.js</code>, adds simple full-text search capabilities,\nsee <code>docs/search.md</code> for more information.</li>\n<li><code>persistence.migrations.js</code>, supports data migrations (changes to\nthe database schema), see <code>docs/migrations.md</code> for more information.</li>\n<li><code>persistence.sync.js</code>, supports database synchronization with a\nremote server, see <code>docs/sync.md</code> for more information.</li>\n<li><code>jquery.persistence.js</code>, adds jQuery integration, including \njQuery-mobile ajax request interception and re-routing to persistencejs,\nsee <code>docs/jquery.md</code> for more information and <code>demo/jquerymobile</code> for a \nsimple demo.</li>\n</ul>\n<h2>A Brief Intro to Async Programming</h2>\n<p>In browsers, Javascript and the web page's rendering engine share\na single thread. The result of this is that only one thing can happen\nat a time. If a database query would be performed <em>synchronously</em>,\nlike in many other programming environments like Java and PHP the\nbrowser would freeze from the moment the query was issued until the\nresults came back. Therefore, many APIs in Javascript are defined as\n<em>asynchronous</em> APIs, which mean that they do not block when an\n"expensive" computation is performed, but instead provide the call\nwith a function that will be invoked once the result is known. In the\nmeantime, the browser can perform other duties.</p>\n<p>For instance, a synchronous database call call would look as follows:</p>\n<pre><span class=\"hljs-keyword\">var</span> results = <span class=\"hljs-keyword\">db</span>.<span class=\"hljs-keyword\">query</span>(<span class=\"hljs-string\">"SELECT * FROM Table"</span>);\n<span class=\"hljs-keyword\">for</span>(...) { ... }</pre><p>The execution of the first statement could take half a second, during\nwhich the browser doesn't do anything else. By contrast, the\nasynchronous version looks as follows:</p>\n<pre>db.query(<span class=\"hljs-string\">"SELECT * FROM Table"</span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span><span class=\"hljs-params\">(results)</span> </span>{\n <span class=\"hljs-keyword\">for</span>(...) { ... }\n});</pre><p>Note that there will be a delay between the <code>db.query</code> call and the\nresult being available and that while the database is processing the\nquery, the execution of the Javascript continues. To make this clear,\nconsider the following program:</p>\n<pre>db.query(<span class=\"hljs-string\">"SELECT * FROM Table"</span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span>(<span class=\"hljs-params\">results</span>) </span>{\n <span class=\"hljs-built_in\">console</span>.log(<span class=\"hljs-string\">"hello"</span>);\n});\n<span class=\"hljs-built_in\">console</span>.log(<span class=\"hljs-string\">"world"</span>);</pre><p>Although one could assume this would print "hello", followed by\n"world", the result will likely be that "world" is printed before\n"hello", because "hello" is only printed when the results from the\nquery are available. This is a tricky thing about asynchronous\nprogramming that a Javascript developer will have to get used to.</p>\n<h1>Using persistence.js in the browser</h1>\n<h2>Browser support</h2>\n<ul>\n<li>Modern webkit browsers (Google Chrome and Safari)</li>\n<li>Firefox (through Google Gears)</li>\n<li>Android browser (tested on 1.6 and 2.x)</li>\n<li>iPhone browser (iPhone OS 3+)</li>\n<li>Palm WebOS (tested on 1.4.0)</li>\n</ul>\n<p>(The following is being worked on:)\nInternet Explorer is likely not supported (untested) because it\nlacks <code>__defineGetter__</code> and <code>__defineSetter__</code> support, which\n<code>persistence.js</code> uses heavily. This may change in IE 8.</p>\n<h2>Setting up</h2>\n<p>To use <code>persistence.js</code> you need to clone the git repository:</p>\n<pre>git <span class=\"hljs-keyword\">clone</span> <span class=\"hljs-title\">git</span>://github.com/zefhemel/persistencejs.git</pre><p>To use it you need to copy <code>lib/persistence.js</code> to your web directory,\nas well as any data stores you want to use. Note that the <code>mysql</code> and\n<code>websql</code> stores both depend on the <code>sql</code> store. A typical setup\nrequires you to copy at least <code>lib/persistence.js</code>,\n<code>lib/persistence.store.sql.js</code> and <code>lib/persistence.store.websql.js</code> to your\nweb directory. You can then load them as follows:</p>\n<pre><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span> <span class=\"hljs-attr\">src</span>=<span class=\"hljs-string\">"persistence.js"</span> <span class=\"hljs-attr\">type</span>=<span class=\"hljs-string\">"application/javascript"</span>></span><span class=\"undefined\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span>\n<span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span> <span class=\"hljs-attr\">src</span>=<span class=\"hljs-string\">"persistence.store.sql.js"</span> <span class=\"hljs-attr\">type</span>=<span class=\"hljs-string\">"application/javascript"</span>></span><span class=\"undefined\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span>\n<span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span> <span class=\"hljs-attr\">src</span>=<span class=\"hljs-string\">"persistence.store.websql.js"</span> <span class=\"hljs-attr\">type</span>=<span class=\"hljs-string\">"application/javascript"</span>></span><span class=\"undefined\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span></pre><h2>Setup your database</h2>\n<p>You need to explicitly configure the data store you want to use,\nconfiguration of the data store is store-specific. The WebSQL store\n(which includes Google Gears support) is configured as follows:</p>\n<pre>persistence.store.websql.<span class=\"hljs-built_in\">config</span>(persistence, <span class=\"hljs-string\">'yourdbname'</span>, <span class=\"hljs-string\">'A database description'</span>, <span class=\"hljs-number\">5</span> * <span class=\"hljs-number\">1024</span> * <span class=\"hljs-number\">1024</span>);</pre><p>The first argument is always supposed to be <code>persistence</code>. The second\nin your database name (it will create it if it does not already exist,\nthe third is a description for you database, the last argument is the\nmaximum size of your database in bytes (5MB in this example).</p>\n<p>If you're using the in-memory store, you can configure it as follows:</p>\n<pre><span class=\"hljs-selector-tag\">persistence</span><span class=\"hljs-selector-class\">.store</span><span class=\"hljs-selector-class\">.memory</span><span class=\"hljs-selector-class\">.config</span>(<span class=\"hljs-selector-tag\">persistence</span>);</pre><h2>Schema definition</h2>\n<p>A data model is declared using <code>persistence.define</code>. The following two\ndefinitions define a <code>Task</code> and <code>Category</code> entity with a few simple\nproperties. The property types are based on <a href=\"http://www.sqlite.org/datatype3.html\">SQLite\ntypes</a>, specifically supported\ntypes are (but any SQLite type is supported):</p>\n<ul>\n<li><code>TEXT</code>: for textual data </li>\n<li><code>INT</code>: for numeric values</li>\n<li><code>BOOL</code>: for boolean values (<code>true</code> or <code>false</code>)</li>\n<li><code>DATE</code>: for date/time value (with precision of 1 second)</li>\n<li><code>JSON</code>: a special type that can be used to store arbitrary\n<a href=\"http://www.json.org\">JSON</a> data. Note that this data can not be used\nto filter or sort in any sensible way. If internal changes are made to a <code>JSON</code>\nproperty, <code>persistence.js</code> may not register them. Therefore, a manual\ncall to <code>anObj.markDirty('jsonPropertyName')</code> is required before calling\n<code>persistence.flush</code>.</li>\n</ul>\n<p>Example use:</p>\n<pre><span class=\"hljs-built_in\">var</span> Task = persistence.<span class=\"hljs-class\"><span class=\"hljs-keyword\">define</span></span>(<span class=\"hljs-string\">'Task'</span>, {\n name: <span class=\"hljs-string\">"TEXT"</span>,\n description: <span class=\"hljs-string\">"TEXT"</span>,\n done: <span class=\"hljs-string\">"BOOL"</span>\n});\n\n<span class=\"hljs-built_in\">var</span> Category = persistence.<span class=\"hljs-class\"><span class=\"hljs-keyword\">define</span></span>(<span class=\"hljs-string\">'Category'</span>, {\n name: <span class=\"hljs-string\">"TEXT"</span>,\n metaData: <span class=\"hljs-string\">"JSON"</span>\n});\n\n<span class=\"hljs-built_in\">var</span> <span class=\"hljs-built_in\">Tag</span> = persistence.<span class=\"hljs-class\"><span class=\"hljs-keyword\">define</span></span>(<span class=\"hljs-string\">'Task'</span>, {\n name: <span class=\"hljs-string\">"TEXT"</span>\n});</pre><p>The returned values are constructor functions and can be used to\ncreate new instances of these entities later:</p>\n<p>Relationships between entities are defined using the constructor\nfunction's <code>hasMany</code> call:</p>\n<pre><span class=\"hljs-comment\">// This defines a one-to-many relationship:</span>\nCategory.hasMany(<span class=\"hljs-string\">'tasks'</span>, <span class=\"hljs-built_in\">Task</span>, <span class=\"hljs-string\">'category'</span>);\n<span class=\"hljs-comment\">// These two definitions define a many-to-many relationship</span>\n<span class=\"hljs-built_in\">Task</span>.hasMany(<span class=\"hljs-string\">'tags'</span>, Tag, <span class=\"hljs-string\">'tasks'</span>);\nTag.hasMany(<span class=\"hljs-string\">'tasks'</span>, <span class=\"hljs-built_in\">Task</span>, <span class=\"hljs-string\">'tags'</span>);</pre><p>The first statement defines a <code>tasks</code> relationship on category objects\ncontaining a <code>QueryCollection</code> (see the section on query collections\nlater) of <code>Task</code>s, it also defines an inverse relationship on <code>Task</code>\nobjects with the name <code>category</code>. The last two statements define a\nmany-to-many relationships between <code>Task</code> and <code>Tag</code>. <code>Task</code> gets a\n<code>tags</code> property (a <code>QueryCollection</code>) containing all its tags and vice\nversa, <code>Tag</code> gets a <code>tasks</code> property containing all of its tasks.</p>\n<p>The defined entity definitions are synchronized (activated) with the\ndatabase using a <code>persistence.schemaSync</code> call, which takes a callback\nfunction (with a newly created transaction as an argument), that is called\nwhen the schema synchronization has completed, the callback is\noptional.</p>\n<pre>persistence.schemaSync();\n<span class=\"hljs-comment\">// or</span>\npersistence.schemaSync(<span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span><span class=\"hljs-params\">(tx)</span> </span>{ \n <span class=\"hljs-comment\">// tx is the transaction object of the transaction that was</span>\n <span class=\"hljs-comment\">// automatically started</span>\n});</pre><p>There is also a migrations plugin you can check out, documentation can be found\nin <a href=\"migrations/persistence.migrations.docs.md\">persistence.migrations.docs.md</a> file.</p>\n<h2>Mix-ins</h2>\n<p>You can also define mix-ins and apply them to entities of the model. </p>\n<p>A mix-in definition is similar to an entity definition, except using\n<code>defineMixin</code> rather than just <code>define</code>. For example:</p>\n<pre><span class=\"hljs-attribute\">var Annotatable</span> = persistence.defineMixin(<span class=\"hljs-string\">'Annotatable'</span>, {\n lastAnnotated: <span class=\"hljs-string\">"DATE"</span>\n});</pre><p>You can define relationships between mix-in and entities. For example:</p>\n<pre><span class=\"hljs-comment\">// A normal entity</span>\n<span class=\"hljs-built_in\">var</span> Note = persistence.<span class=\"hljs-class\"><span class=\"hljs-keyword\">define</span></span>(<span class=\"hljs-string\">'Note'</span>, {\n text: <span class=\"hljs-string\">"TEXT"</span>\n});\n\n<span class=\"hljs-comment\">// relationship between a mix-in and a normal entity</span>\nAnnotatable.hasMany(<span class=\"hljs-string\">'notes'</span>, Note, <span class=\"hljs-string\">'annotated'</span>);</pre><p>Once you have defined a mix-in, you can apply it to any entity of your model, \nwith the <code>Entity.is(mixin)</code> method. For example:</p>\n<pre>Project.<span class=\"hljs-keyword\">is</span>(Annotatable);\n<span class=\"hljs-keyword\">Task</span>.<span class=\"hljs-keyword\">is</span>(Annotatable);</pre><p>Now, your <code>Project</code> and <code>Task</code> entities have an additional <code>lastAnnotated</code> property.\nThey also have a one to many relationship called <code>notes</code> to the <code>Note</code> entity. \nAnd you can also traverse the reverse relationship from a <code>Note</code> to its <code>annotated</code> object.</p>\n<p>Note that <code>annotated</code> is a polymorphic relationship as it may yield either a <code>Project</code> \nor a <code>Task</code> (or any other entity which is `Annotatable').</p>\n<p>Note: Prefetch is not allowed (yet) on a relationship that targets a mixin. In the example above\nyou cannot prefetch the <code>annotated</code> relationship when querying the <code>Note</code> entity.</p>\n<p>Notes: this feature is very experimental at this stage. It needs more testing.\n Support for "is a" relationships (classical inheritance) is also in the works.</p>\n<h2>Creating and manipulating objects</h2>\n<p>New objects can be instantiated with the constructor functions.\nOptionally, an object with initial property values can be passed as\nwell, or the properties may be set later:</p>\n<pre><span class=\"hljs-built_in\">var</span> task = <span class=\"hljs-literal\">new</span> Task();\n<span class=\"hljs-built_in\">var</span> category = <span class=\"hljs-literal\">new</span> Category({name: <span class=\"hljs-string\">"My category"</span>});\ncategory.metaData = {rating: <span class=\"hljs-number\">5</span>};\n<span class=\"hljs-built_in\">var</span> <span class=\"hljs-built_in\">tag</span> = <span class=\"hljs-literal\">new</span> <span class=\"hljs-built_in\">Tag</span>();\n<span class=\"hljs-built_in\">tag</span>.name = <span class=\"hljs-string\">"work"</span>;</pre><p>Many-to-one relationships are accessed using their specified name, e.g.:\n task.category = category;</p>\n<p>One-to-many and many-to-many relationships are access and manipulated\nthrough the <code>QueryCollection</code> API that will be discussed later:</p>\n<pre>task.tags.add(<span class=\"hljs-keyword\">tag</span>);\ntasks.tags.remove(<span class=\"hljs-keyword\">tag</span>)l\ntasks.tags.list(tx, function(<span class=\"hljs-literal\">all</span>Tags) { console.<span class=\"hljs-keyword\">log</span>(<span class=\"hljs-literal\">all</span>Tags); });</pre><h2>Persisting/removing objects</h2>\n<p>Similar to <a href=\"http://www.hibernate.org\">hibernate</a>, <code>persistence.js</code>\nuses a tracking mechanism to determine which objects' changes have to\nbe persisted to the datase. All objects retrieved from the database\nare automatically tracked for changes. New entities can be tracked to\nbe persisted using the <code>persistence.add</code> function:</p>\n<pre><span class=\"hljs-keyword\">var</span> c = <span class=\"hljs-keyword\">new</span> Category({name: <span class=\"hljs-string\">"Main category"</span>});\npersistence.<span class=\"hljs-keyword\">add</span>(c);\n<span class=\"hljs-keyword\">for</span> ( <span class=\"hljs-keyword\">var</span> i = <span class=\"hljs-number\">0</span>; i < <span class=\"hljs-number\">5</span>; i++) {\n <span class=\"hljs-keyword\">var</span> t = <span class=\"hljs-keyword\">new</span> Task();\n t.name = <span class=\"hljs-string\">'Task '</span> + i;\n t.done = i % <span class=\"hljs-number\">2</span> == <span class=\"hljs-number\">0</span>;\n t.category = c;\n persistence.<span class=\"hljs-keyword\">add</span>(t);\n}</pre><p>Objects can also be removed from the database:</p>\n<pre>persistence.remove(c)<span class=\"hljs-comment\">;</span></pre><p>All changes made to tracked objects can be flushed to the database by\nusing <code>persistence.flush</code>, which takes a transaction object and\ncallback function as arguments. A new transaction can be started using\n<code>persistence.transaction</code>:</p>\n<pre>persistence.transaction(<span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span><span class=\"hljs-params\">(tx)</span></span> {\n persistence.<span class=\"hljs-built_in\">flush</span>(tx, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span><span class=\"hljs-params\">()</span></span> {\n alert(<span class=\"hljs-string\">'Done flushing!'</span>);\n });\n});</pre><p>For convenience, it is also possible to not specify a transaction or\ncallback, in that case a new transaction will be started\nautomatically. For instance:</p>\n<pre>persistence.<span class=\"hljs-built_in\">flush</span>();\n// <span class=\"hljs-keyword\">or</span>, with callback\npersistence.<span class=\"hljs-built_in\">flush</span>(<span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span><span class=\"hljs-params\">()</span></span> {\n alert(<span class=\"hljs-string\">'Done flushing'</span>);\n});</pre><p>Note that when no callback is defined, the flushing still happens\nasynchronously.</p>\n<p><strong>Important</strong>: Changes and new objects will not be persisted until you\nexplicitly call <code>persistence.flush()</code>. The exception to this rule is\nusing the <code>list(...)</code> method on a database <code>QueryCollection</code>, which also\nflushes first, although this behavior may change in the future. </p>\n<h2>Dumping and restoring data</h2>\n<p>The library supports two kinds of dumping and restoring data.</p>\n<p><code>persistence.dump</code> can be used to create an object containing a full\ndump of a database. Naturally, it is adviced to only do this with\nsmaller databases. Example:</p>\n<pre>persistence.dump(tx, [Task, Category], <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span><span class=\"hljs-params\">(dump)</span></span> {\n console.<span class=\"hljs-built_in\">log</span>(dump);\n});</pre><p>The <code>tx</code> is left out, a new transaction will be started for the\noperation. If the second argument is left out, <code>dump</code> defaults\nto dumping <em>all</em> defined entities.</p>\n<p>The dump format is:</p>\n<pre>{<span class=\"hljs-string\">"entity-name"</span>: [<span class=\"hljs-built_in\">list</span> <span class=\"hljs-keyword\">of</span> instances],\n ...}</pre><p><code>persistence.load</code> is used to restore the dump produced by\n<code>persistence.dump</code>. Usage:</p>\n<pre>persistence.<span class=\"hljs-built_in\">load</span>(tx, dumpObj, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span><span class=\"hljs-params\">()</span></span> {\n alert(<span class=\"hljs-string\">'Dump restored!'</span>);\n});</pre><p>The <code>tx</code> argument can be left out to automatically start a new\ntransaction. Note that <code>persistence.load</code> does not empty the database\nfirst, it simply attempts to add all objects to the database. If\nobjects with, e.g. the same ID already exist, this will fail.</p>\n<p>Similarly, <code>persistence.loadFromJson</code> and <code>persistence.dumpToJson</code>\nrespectively load and dump all the database's data as JSON strings.</p>\n<h2>Entity constructor functions</h2>\n<p>The constructor function returned by a <code>persistence.define</code> call\ncannot only be used to instantiate new objects, it also has some\nuseful methods of its own:</p>\n<ul>\n<li><code>EntityName.all([session])</code> returns a query collection containing\nall\npersisted instances of that object. The <code>session</code> argument is\noptional and only required when <code>persistence.js</code> is used in\nmulti-session mode.</li>\n<li><code>EntityName.load([session], [tx], id, callback)</code> loads an particular\nobject from the database by id or returns <code>null</code> if it has not been\nfound.</li>\n<li><code>EntityName.findBy([session], [tx], property, value, callback)</code> searches\nfor a particular object based on a property value (this is assumed to\nbe unique), the callback function is called with the found object or\n<code>null</code> if it has not been found.</li>\n</ul>\n<p>And of course the methods to define relationships to other entities:</p>\n<ul>\n<li><code>EntityName.hasMany(property, Entity, inverseProperty)</code> defines a\n1:N or N:M relationship (depending on the inverse property)</li>\n<li><code>EntityName.hasOne(property, Entity)</code> defines a 1:1 or N:1\nrelationship</li>\n</ul>\n<h2>Entity objects</h2>\n<p>Entity instances also have a few predefined properties and methods you\nshould be aware of:</p>\n<ul>\n<li><code>obj.id</code>, contains the identifier of your entity, this is a\nautomatically generated (approximation of a) UUID. You should\nnever write to this property.</li>\n<li><code>obj.fetch(prop, callback)</code>, if an object has a <code>hasOne</code>\n relationship to another which has not yet been fetched from the\n database (e.g. when <code>prefetch</code> wasn't used), you can fetch in manually\n using <code>fetch</code>. When the property object is retrieved the callback function\n is invoked with the result, the result is also cached in the entity\n object itself.</li>\n<li><code>obj.selectJSON([tx], propertySpec, callback)</code>, sometime you need to extract\na subset of data from an entity. You for instance need to post a\nJSON representation of your entity, but do not want to include all\nproperties. <code>selectJSON</code> allows you to do that. The <code>propertySpec</code>\narguments expects an array with property names. Some examples:<ul>\n<li><code>['id', 'name']</code>, will return an object with the id and name property of this entity</li>\n<li><code>['*']</code>, will return an object with all the properties of this entity, not recursive</li>\n<li><code>['project.name']</code>, will return an object with a project property which has a name \nproperty containing the project name (hasOne relationship)</li>\n<li><code>['project.[id, name]']</code>, will return an object with a project property which has an\nid and name property containing the project name (hasOne relationship)</li>\n<li><code>['tags.name']</code>, will return an object with an array <code>tags</code> property containing \nobjects each with a single property: name</li>\n</ul>\n</li>\n</ul>\n<h2>Query collections</h2>\n<p>A core concept of <code>persistence.js</code> is the <code>QueryCollection</code>. A\n<code>QueryCollection</code> represents a (sometimes) virtual collection that can\nbe filtered, ordered or paginated. <code>QueryCollection</code>s are somewhate\ninspired by <a href=\"http://code.google.com/appengine/docs/python/datastore/queryclass.html\">Google AppEngine's Query\nclass</a>.\nA <code>QueryCollection</code> has the following methods:</p>\n<ul>\n<li><code>filter(property, operator, value)</code><br>Returns a new <code>QueryCollection</code> that adds a filter, filtering a\ncertain property based on an operator and value. Supported operators\nare '=', '!=', '<', '<=', '>', '>=', 'in' and 'not in'. Example:\n<code>.filter('done', '=', true)</code></li>\n<li><code>or(filter)</code><br>Returns a new <code>QueryCollection</code> that contains items either matching\nthe filters specified before calling <code>or</code>, or the filter represented\nin the argument. The <code>filter</code> argument is of a <code>Filter</code> type, there\nare three types of filters:<ul>\n<li><code>persistence.PropertyFilter</code>, which filters on properties (internally called when <code>filter(...)</code> is used.<br>Example: <code>new persistence.PropertyFilter('done', '=', true)</code></li>\n<li><code>persistence.AndFilter</code>, which is passed two filter objects as arguments, both of which should be true.\nExample: <code>new persistence.AndFilter(new persistence.PropertyFilter('done', '=', true), new persistence.PropertyFilter('archived', '=', true))</code></li>\n<li><code>persistence.OrFilter</code>, which is passed two filter objects as arguments, one of which should be true.\nExample: <code>new persistence.OrFilter(new persistence.PropertyFilter('done', '=', true), new persistence.PropertyFilter('archived', '=', true))</code></li>\n</ul>\n</li>\n<li><code>and(filter)</code><br>same as <code>or(filter)</code> except that both conditions should hold for items to be in the collection. </li>\n<li><code>order(property, ascending)</code><br>Returns a new <code>QueryCollection</code> that will order its results by the\nproperty specified in either an ascending (ascending === true) or\ndescending (ascending === false) order.</li>\n<li><code>limit(n)</code><br>Returns a new <code>QueryCollection</code> that limits the size of the result\nset to <code>n</code> items. Useful for pagination.</li>\n<li><code>skip(n)</code><br>Returns a new <code>QueryCollection</code> that skips the first <code>n</code> results.\nUseful for pagination.</li>\n<li><code>prefetch(rel)</code><br>Returns a new <code>QueryCollection</code> that prefetches entities linked\nthrough relationship <code>rel</code>, note that this only works for one-to-one\nand many-to-one relationships.</li>\n<li><code>add(obj)</code><br>Adds object <code>obj</code> to the collection.</li>\n<li><code>remove(obj)</code><br>Removes object <code>obj</code> from the collection.</li>\n<li><code>list([tx], callback)</code><br>Asynchronously fetches the results matching the formulated query.\nOnce retrieved, the callback function is invoked with an array of\nentity objects as argument.</li>\n<li><code>each([tx], eachCallback)</code><br>Asynchronously fetches the results matching the formulated query.\nOnce retrieved, the <code>eachCallback</code> function is invoked on each\nelement of the result objects.</li>\n<li><code>forEach([tx], eachCallback)</code><br>Alias for <code>each</code></li>\n<li><code>one([tx], callback)</code>\nAsynchronously fetches the first element of the collection, or <code>null</code> if none.</li>\n<li><code>destroyAll([tx], callback)</code>\nAsynchronously removes all the items in the collection. <strong>Important</strong>: this does\nnot only remove the items from the collection, but removes the items themselves!</li>\n<li><code>count([tx], callback)</code>\nAsynchronously counts the number of items in the collection. The arguments passed\nto the <code>callback</code> function is the number of items.</li>\n</ul>\n<p>Query collections are returned by:</p>\n<ul>\n<li><code>EntityName.all()</code>, e.g. <code>Task.all()</code></li>\n<li>one-to-many and many-to-many relationships, e.g. <code>task.tags</code></li>\n</ul>\n<p>Example:</p>\n<pre><span class=\"hljs-keyword\">var</span> allTasks = Task.all().filter(<span class=\"hljs-string\">"done"</span>, <span class=\"hljs-string\">'='</span>, <span class=\"hljs-literal\">true</span>).prefetch(<span class=\"hljs-string\">"category"</span>).order(<span class=\"hljs-string\">"name"</span>, <span class=\"hljs-literal\">false</span>).limit(<span class=\"hljs-number\">10</span>);\n\nallTasks.list(<span class=\"hljs-literal\">null</span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span> (<span class=\"hljs-params\">results</span>) </span>{\n results.forEach(<span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span> (<span class=\"hljs-params\">r</span>) </span>{\n <span class=\"hljs-built_in\">console</span>.log(r.name)\n <span class=\"hljs-built_in\">window</span>.task = r;\n });\n});</pre><h1>Using persistence.js on the server</h1>\n<p>Installing <code>persistence.js</code> on node is easy using <a href=\"http://npmjs.org\">npm</a>:</p>\n<pre>npm <span class=\"hljs-keyword\">install</span> persistencejs</pre><p>Sadly the node.js server environment requires slight changes to\n<code>persistence.js</code> to make it work with multiple database connections:</p>\n<ul>\n<li>A <code>Session</code> object needs to be passed as an extra argument to\ncertain method calls, typically as a first argument.</li>\n<li>Methods previously called on the <code>persistence</code> object itself are now\ncalled on the <code>Session</code> object.</li>\n</ul>\n<p>An example <code>node.js</code> application is included in <code>test/node-blog.js</code>. </p>\n<h2>Setup</h2>\n<p>You need to <code>require</code> two modules, the <code>persistence.js</code> library itself\nand the MySQL backend module.</p>\n<pre><span class=\"hljs-attribute\">var persistence</span> = require(<span class=\"hljs-string\">'persistencejs/persistence'</span>).persistence;\n<span class=\"hljs-attribute\">var persistenceStore</span> = require(<span class=\"hljs-string\">'persistencejs/persistence.store.mysql'</span>);</pre><p>Then, you configure the database settings to use:</p>\n<pre>persistenceStore.<span class=\"hljs-built_in\">config</span>(persistence, <span class=\"hljs-string\">'localhost'</span>, <span class=\"hljs-number\">3306</span>, <span class=\"hljs-string\">'dbname'</span>, <span class=\"hljs-string\">'username'</span>, <span class=\"hljs-string\">'password'</span>);</pre><p>Subsequently, for every connection you handle (assuming you're\nbuilding a sever), you call the <code>persistenceStore.getSession()</code>\nmethod:</p>\n<pre><span class=\"hljs-attribute\">var session</span> = persistenceBackend.getSession();</pre><p>This session is what you pass around, typically together with a\ntransaction object. Note that currently you can only have one\ntransaction open per session and transactions cannot be nested.</p>\n<pre>session.transaction(<span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span><span class=\"hljs-params\">(tx)</span> </span>{\n ...\n});</pre><h2>Commit and Rollback</h2>\n<p><code>persistence.js</code> works in autocommit mode by default. </p>\n<p>You can override this behavior and enable explicit commit and rollback \nby passing true as first argument to <code>persistence.transaction</code>. \nYou can then use the following two methods to control the transaction:</p>\n<ul>\n<li><code>transaction.commit(session, callback)</code> commits the changes.</li>\n<li><code>transaction.rollback(session, callback)</code> rollbacks the changes.</li>\n</ul>\n<p>Typical code will look like:</p>\n<pre>session.transaction(<span class=\"hljs-literal\">true</span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span>(<span class=\"hljs-params\">tx</span>) </span>{\n <span class=\"hljs-comment\">// create/update/delete objects</span>\n modifyThings(session, tx, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span>(<span class=\"hljs-params\">err, result</span>) </span>{\n <span class=\"hljs-keyword\">if</span> (err) {\n <span class=\"hljs-comment\">// something went wrong</span>\n tx.rollback(session, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span>(<span class=\"hljs-params\"></span>) </span>{\n <span class=\"hljs-built_in\">console</span>.log(<span class=\"hljs-string\">'changes have been rolled back: '</span> + ex.message);\n });\n }\n <span class=\"hljs-keyword\">else</span> {\n <span class=\"hljs-comment\">// success</span>\n tx.commit(session, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span>(<span class=\"hljs-params\"></span>) </span>{\n <span class=\"hljs-built_in\">console</span>.log(<span class=\"hljs-string\">'changes have been committed: '</span> result);\n });\n });\n});</pre><p>Explicit commit and rollback is only supported on MySQL (server side) \nfor now.</p>\n<h2>Defining your data model</h2>\n<p>Defining your data model is done in exactly the same way as regular <code>persistence.js</code>:</p>\n<pre><span class=\"hljs-built_in\">var</span> Task = persistence.<span class=\"hljs-class\"><span class=\"hljs-keyword\">define</span></span>(<span class=\"hljs-string\">'Task'</span>, {\n name: <span class=\"hljs-string\">"TEXT"</span>,\n description: <span class=\"hljs-string\">"TEXT"</span>,\n done: <span class=\"hljs-string\">"BOOL"</span>\n});</pre><p>A <code>schemaSync</code> is typically performed as follows:</p>\n<pre>session.schemaSync(tx, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span><span class=\"hljs-params\">()</span> </span>{\n ...\n});</pre><h2>Creating and manipulating objects</h2>\n<p>Creating and manipulating objects is done much the same way as with\nregular <code>persistence.js</code>, except that in the entity's constructor you\nneed to reference the <code>Session</code> again:</p>\n<pre><span class=\"hljs-keyword\">var</span> t = <span class=\"hljs-keyword\">new</span> Task(session);\n...\nsession.add(t);\n\nsession.flush(tx, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span><span class=\"hljs-params\">()</span> </span>{\n ...\n});</pre><h2>Query collections</h2>\n<p>Query collections work the same way as in regular <code>persistence.js</code>\nwith the exception of the <code>Entity.all()</code> method that now also requires\na <code>Session</code> to be passed to it:</p>\n<pre>Task.all(session).filter(<span class=\"hljs-string\">'done'</span>, <span class=\"hljs-string\">'='</span>, <span class=\"hljs-keyword\">true</span>).<span class=\"hljs-keyword\">list</span>(tx, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span><span class=\"hljs-params\">(tasks)</span> </span>{\n ...\n});</pre><h2>Closing the session</h2>\n<p>After usage, you need to close your session:</p>\n<pre>session.close()<span class=\"hljs-comment\">;</span></pre><h1>Bugs and Contributions</h1>\n<p>If you find a bug, please <a href=\"http://yellowgrass.org/project/persistence.js\">report it</a>.\nor fork the project, fix the problem and send me a pull request. For\na list of planned features and open issues, have a look at the <a href=\"http://yellowgrass.org/project/persistence.js\">issue\ntracker</a>.</p>\n<p>For support and discussion, please join the <a href=\"http://groups.google.com/group/persistencejs\">persistence.js Google\nGroup</a>.</p>\n<p>Thanks goes to the people listed in <code>AUTHORS</code> for their contributions.</p>\n<p>If you use <a href=\"http://code.google.com/webtoolkit/\">GWT</a> (the Google Web\nToolkit), be sure to have a look at <a href=\"http://github.com/dennisjzh/gwt-persistence\">Dennis Z. Jiang's GWT persistence.js\nwrapper</a>.</p>\n<h1>License</h1>\n<p>This work is licensed under the <a href=\"http://en.wikipedia.org/wiki/MIT_License\">MIT license</a>.</p>\n<h2>Support this work</h2>\n<p>You can support this project by flattering it:</p>\n<p><a href=\"http://flattr.com/thing/2510/persistence-js\" target=\"_blank\">\n<img src=\"http://api.flattr.com/button/button-static-50x60.png\"></a></p>\n"
},
{
"component": "footer",
"links": [
{
"href": "https://github.com/rsaccon/persistencejs",
"text": "GitHub"
},
{
"href": "https://github.com/rsaccon",
"text": "rsaccon"
}
]
}
]
}