README.md
1MySQL-JS
2========
3
4Introduction
5------------
6This package provides a fast, easy, and safe framework for building
7database applications in Node.js. It is organized around the concept
8of a database *session*, which allows standard JavaScript objects to be
9read from and written to a database.
10
11This example uses a session to store a single object into a MySQL table:
12```
13var nosql = require("mysql-js");
14
15var connectionProperties = {
16 "implementation" : "mysql",
17 "database" : "test",
18 "mysql_host" : "localhost",
19 "mysql_port" : 3306,
20 "mysql_user" : "test",
21 "mysql_password" : "",
22};
23
24nosql.openSession(connectionProperties).then(
25 function(session) {
26 var user = { id: 1, name: "Database Jones"};
27 return session.persist("user", user);
28 }
29).then(
30 function() {
31 console.log("Complete");
32 nosql.closeAllOpenSessionFactories();
33 }
34);
35```
36
37
38Quick Install
39-------------
40```
41npm install https://github.com/mysql/mysql-js/archive/2014-10-06.tar.gz
42```
43
44
45Supported Databases and Connection Properties
46---------------------------------------------
47MySQL-JS provides a common data management API over a variety of back-end
48database connections. Two database adapters are currently supported.
49The *mysql* adapter provides generic support for any MySQL database,
50based on all-JavaScript mysql connector node-mysql.
51The *ndb* adapter provides optimized high-performance access to MySQL Cluster
52using the NDB API.
53
54Each backend adapter supports its own set of connection properties.
55+ [MySQL Connection Properties](Backend-documentation/mysql_properties.js)
56+ [NDB Connection Properties](Backend-documentation/ndb_properties.js)
57
58
59Session
60-------
61The central concept of mysql-js is the **Session**. A session provides
62a context for database operations and transactions. Each independent user
63context should have a distinct session. For instance, in a web application,
64handling each HTTP request involves opening a session, using the session to
65access the database, and then closing the session.
66
67
68### Session methods
69
70Most methods on session() are available on several varieties: they may take
71either a mapped object or a literal table name; they may take a callback, or
72rely on the returned promise for continuation; and they may take any number
73of extra arguments after a callback.
74
75Each of the following methods is *asynchronous* and *returns a promise*:
76+ **find()** Find an instance in the database using a primary or unique key.
77 + find(Constructor, keys, [callback], [...])
78 + find(Projection, keys, [callback], [...])
79 + find(tableName, keys, [callback], [...])
80+ **load(instance, [callback], [...])** Loads a specific instance from the database
81based on the primary or unique key present in the object.
82+ **persist()** Insert an instance into the database.
83 + persist(instance, [callback], [...])
84 + persist(Constructor, values, [callback], [...])
85 + persist(tableName, values, [callback], [...])
86+ **remove()** Delete an instance by primary or unique key.
87 + remove(instance, [callback], [...])
88 + remove(Constructor, keys, [callback], [...])
89 + remove(tableName, keys, [callback], [...])
90+ **update()** Update an instance by primary or unique key without necessarily retrieving it.
91 + update(instance, [callback], [...])
92 + update(Constructor, keys, values, [callback], [...])
93 + update(tableName, keys, values, [callback], [...])
94+ **save()** Write an object to the database without checking for existence; could result in either an update or an insert.
95 + save(instance, [callback], [...])
96 + save(Constructor, values, [callback], [...])
97 + save(tableName, values, [callback], [...])
98+ **createQuery()** Create an object that can be used to query the database
99 + createQuery(instance, [callback], [...])
100 + createQuery(Constructor, [callback], [...])
101 + createQuery(tableName, [callback], [...])
102+ **getMapping()** Resolve and fetch mappings for a table or class
103 + getMapping(object, [callback], [...])
104 + getMapping(Constructor, [callback], [...])
105 + getMapping(tableName, [callback], [...])
106+ **close([callback], [...])** Close the current session
107
108The following methods are *immediate*:
109+ createBatch(). Returns a batch.
110+ listBatches(). Returns an array of batches.
111+ isClosed(). Returns boolean.
112+ isBatch(). Returns boolean.
113+ currentTransaction(). Returns a Transaction.
114
115See the [Complete documentation for Session](API-documentation/Session)
116
117
118SessionFactory
119--------------
120A [SessionFactory](API-documentaiton/SessionFactory) is a heavyweight master
121connection to a database, *i.e.* for a whole process or application.
122
123A SessionFactory generally makes use of network resources such as TCP connections.
124A node.js process will often not exit until all SessionFactories have been
125closed.
126
127
128
129Promises and Callbacks
130----------------------
131The majority of the asynchronous API methods in mysql-js return a
132[Promises/A+ compatible promise](http://promisesaplus.com).
133
134These promises are objects that implement the method **then(onFulfilled, onRejected)**:
135If the asynchronous call completes succesfully, *onFulfilled* will be called with
136one parameter holding the value produced by the async call; if it fails, *onRejected*
137will be called with one parameter holding the error condition. The *then()* method
138also returns a promise, which allows promise calls to be chained.
139
140Async calls also support standard node.js callbacks. If a callback is provided,
141it will be called with parameters *(error, value)* on the completion of the call.
142
143
144The top level mysql-js API
145--------------------------
146Idiomatically the top-level API is often referred to as *nosql*:
147```
148var nosql = require("mysql-js");
149var properties = new nosql.ConnectionProperties("mysql");
150properties.mysql_host = "productiondb";
151var mapping = new nosql.TableMapping("webapp.users");
152nosql.connect(properties, mapping, onConnectedCallback);
153```
154
155+ *ConnectionProperties(adapterName)*: *Constructor*. Creates a ConnectionProperties
156 object containing default values for all properties.
157+ *TableMapping(tableName)*: *Constructor*. Creates a new TableMapping.
158+ *Projection(mappedConstructor)*: *Constructor*. Creates a new Projection.
159+ *connect(properties, [mappings], [callback], [...]): *ASYNC*. The callback
160or promise receives a SessionFactory.
161+ *openSession(properties, [mappings], [callback], [...]): *ASYNC*. An implicit
162SessionFactory is opened if needed; the callback or promise receives a Session.
163+ *getOpenSessionFactories()* Returns an array
164+ *closeAllOpenSessionFactories()* Returns undefined
165
166See the [complete documentation for the top-level API](API-documentation/Mynode)
167
168
169Mapped Objects
170-------------------------
171A **TableMapping** is an _entirely optional_ part of the API that allows you
172to fine-tune the relations between JavaScript objects and database records.
173All of the data management calls available on *session* can take either a table
174name (so that they work without any mapping), or a *mapped object*. When a
175table name is used with find(), for instance, the returned object contains
176one property for every database column, with each property name the same as the
177corresponding column name, and the property value of a default JavaScript type
178based on the column type. When find() is used with a TableMapping, it can
179return an object with some subset of the fields from the mapped table (along
180perhaps with some *non-persistent* fields), using cusom type conversions,
181created from a particular constructor, and connected to a class prototype.
182
183
184```
185 function User() { // Constructor for application object
186 }
187
188 var userTable = new nosql.TableMapping("webapp.user"); // map a table
189 userTable.mapField("firstName","first_name"); // customize the mapping
190 userTable.applyToClass(User); // apply the mapping to the constructor
191```
192See the [complete documentation for TableMapping](API-documentation/TableMapping).
193
194Converters
195----------
196The data types stored in a particular database do not always correspond to
197native JavaScript types. For instance, most databases support 64-bit
198signed and unsigned integers, while JavaScript does not. MySQL-JS allows
199users to customize data conversion in these cases using
200[Converter classess](API-documentation/Converter). A Converter class marshalls
201data between an *intermediate format* and a desired JavaScript format by means of
202two methods, toDB() and fromDB().
203
204The intermediate format for each column type is defined by the backend database
205driver; e.g. the mysql and ndb drivers use *string* as the intermediate type for
206BIGINT columns.
207
208To declare a converter universally for a particular column type, use
209**sessionFactory.registerTypeConverter()**. To declare a specific converter
210for a particular TableMapping, assign it to the converter property of a mapped
211field.
212
213
214Batches
215-------
216MySQL-JS allows flexible batching of operations. Many of the *Session* operations
217are also supported by [Batch](API-documentation/Batch). A variety of operations
218can be defined in a batch, and will all be executed together at once. Callbacks
219are available for each completed operation and for the batch as a whole.
220
221```
222 var batch = session.createBatch();
223 for(i = 0; i < itemDetails.length ; i++) {
224 batch.persist(itemDetails[i]);
225 }
226 batch.update(userHistory);
227 batch.update(userStatistics, onStatsUpdatedCallback);
228 batch.remove(unsavedCart);
229 batch.execute(batchCallback);
230```
231
232
233Transactions
234------------
235Each Session includes a single current [Transaction](API-documentation/Transaction),
236which is obtained using the *session.currentTransaction()* call.
237
238```
239 var transaction = session.currentTransaction();
240 transaction.begin();
241 session.update(user);
242 session.update(cart);
243 transaction.commit(onCommitCallback);
244```
245
246By default, operations happen in **auto-commit mode**, with each operation
247enclosed in a transaction of its own.
248
249
250
251Queries
252-------
253While *session.find()* can be used to fetch a single database record using
254primary or unique index access, more complex queries are provided through
255the [Query class](API-documentation/Query)
256
257Queries are defined by a filter that specifies which database rows should be
258returned. The filter is declared fluently, combining queryable columns with
259comparators and parameters.
260
261```
262session.createQuery('employee').then(function(query) {
263 query.where(
264 query.salary.gt(query.param('low_salary')
265 .and(query.salary.lt(query.param('high_salary')))));
266});
267```
268
269Query execution is governed by a parameter object that can include values
270for named parameters for the query as well as options to sort or paginate the
271result. Query execution returns a promise but can also use the standard callback
272mechanism.
273
274This query will return at most 20 objects that satisfy the filter, in
275ascending order. The same query object can be reused with different parameters
276and options.
277
278```
279query.execute({low_salary: 10000, high_salary:20000, limit: 20, order: 'asc"})
280 .then(function(result) {console.log(result));
281```
282
283Standardized Errors
284-------------------
285MySQL-JS provides a common representation of database errors, independent
286of backend adapters. This representation is based on SQLState, as used in
287the SQL 1999 standard. The DatabaseError object and supported SQLState codes
288are described in the [Error documentation](API-documentation/Error).
289
290
291