Skip to content

Commit 44ea464

Browse files
committed
Enabling third-party drivers
Added a method and some documentation for plugging in a third-party driver for `orm2`. Conflicts: .gitignore
1 parent b160ffe commit 44ea464

File tree

4 files changed

+198
-2
lines changed

4 files changed

+198
-2
lines changed

Drivers.md

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Creating drivers for orm2
2+
3+
To add a driver to `orm2`, call its `addDriver` method:
4+
5+
```js
6+
require('orm2').addDriver('cassandra', CassandraDriver);
7+
```
8+
9+
The first argument is the alias to register for connection URLs. For example, the above will allow you to do this:
10+
11+
```js
12+
var orm = require('orm2');
13+
orm.connect('cassandra://username:password@localhost/test', function (err, db) { });
14+
```
15+
16+
The second argument is the constructor for your driver object.
17+
18+
## Defining driver objects
19+
20+
Your driver should provide the following members.
21+
22+
### Constructor(config, connection, opts)
23+
24+
The driver object constructor should have three parameters:
25+
26+
* config - optional configuration for the database connection. It contains the following properties:
27+
* timezone - optional timezone
28+
* href - URL to use for connecting to the database if the connection argument is null
29+
* host - The hostname of `href`
30+
* pathname - The `path` of `href`
31+
* ssl - Boolean indicating whether the driver should use SSL when connecting to the database
32+
* query - Optional configuration for how the driver should perform queries
33+
* ssl - Boolean indicating whether queries should be sent using SSL
34+
* strdates - Boolean indicating whether strings should be used for dates
35+
* connection - optionally passed if reusing an existing connection
36+
* opts - optional options configuring the driver's behavior. It contains the following properties:
37+
* pool - A boolean indicating whether the driver should use connection pooling
38+
* debug - If true, whether the driver should operate in debug mode
39+
* settings - A key/value object store. Use `get(key)` and `set(key, value)` methods to manipulate the settings. The
40+
following settings are defined:
41+
* properties.primary_key - The column/field name to use for object primary keys
42+
* properties.association_key - A function taking a `name` and `field` parameter that returns the name of the
43+
column that establishes the association
44+
45+
### isSql property
46+
47+
This should be set to `true` if your database is a SQL database.
48+
49+
### customTypes property
50+
51+
Your driver should have a `customTypes` object, with the property names being the names of the custom types, and each
52+
value being the options relating to the type.
53+
54+
### connect(cb) method (required)
55+
56+
Establishes your database connection.
57+
58+
### reconnect(cb, connection) method (optional)
59+
60+
Establishes/re-establishes a connection. The optional prior connection is passed in the `connection` parameter.
61+
62+
### ping(cb) method (required)
63+
64+
Tests whether your connection is still alive.
65+
66+
### close(cb) method (required)
67+
68+
Closes your database connection.
69+
70+
### propertyToValue(value, property) method (required)
71+
72+
Maps an object property to the correlated value to use for the database.
73+
74+
### valueToProperty(value, property) method (required)
75+
76+
Maps a database value to the property value to use for the mapped object.
77+
78+
### find(fields, table, conditions, opts, cb) method (required)
79+
80+
Implement this to select and return data stored in the database.
81+
See the [documentation for Model.find](./README.md#modelfind-conditions---options---limit---order---cb-).
82+
83+
### insert(table, data, id_prop, cb) method (required)
84+
85+
Inserts an object into a database table.
86+
87+
### update(table, changes, conditions, cb) method (required)
88+
89+
Updates an object in the appropriate database row.
90+
91+
### remove(table, conditions, cb) method (required)
92+
93+
Implement this to support the removal of an object from a table.
94+
95+
### count(table, conditions, opts, cb) method (required)
96+
97+
Implement this to support [Model.count](./README.md#modelcount-conditions--cb).
98+
99+
### clear(table, cb) method (required)
100+
101+
Implement this to support `Model.clear`, which deletes all objects from a given table.
102+
103+
### eagerQuery(association, opts, ids, cb) method (required)
104+
105+
Implement this to support eager loading of associated objects.
106+
107+
### query property (optional)
108+
109+
For SQL databases, the `Query` object from the `sql-query` package used to generate ad-hoc queries.
110+
111+
### getQuery() method (optional)
112+
113+
For SQL databases, returns a `Query` object from the `sql-query` package.
114+
115+
### execQuery(query, cb) method (optional)
116+
117+
For SQL databases, this executes a `Query` object from the `sql-query` package.
118+
119+
### aggregate_functions[] property (optional)
120+
121+
If your driver supports SQL aggregate functions, this should be an array of supported function names.
122+
123+
### hasMany(Model, association) method (optional)
124+
125+
If your driver maintains associations in a unique (non-SQL-like) manner, return an object from this method to implement
126+
a one-to-many association. The return value should have the following methods:
127+
128+
* has(Instance, Associations, conditions, cb) - tests if the associations have any objects matching the conditions
129+
* get(Instance, conditions, options, createInstance, cb) - retrieves associated objects
130+
* add(Instance, Association, data, cb) - inserts an associated object
131+
* del(Instance, Associations, cb) - deletes an object from a set of associations
132+
133+
### sync(opts, cb) method (optional)
134+
135+
If your driver supports creating a table from a model, implement this method. The following options are passed:
136+
137+
* extension
138+
* id
139+
* table
140+
* properties
141+
* allProperties
142+
* indexes
143+
* customTypes
144+
* one_associations
145+
* many_associations
146+
* extend_associations
147+
148+
### drop(opts, cb) method (optional)
149+
150+
If your driver supports dropping a table, implement this method. The following options are passed to this method:
151+
152+
* table - The name of the table
153+
* properties
154+
* one_associations
155+
* many_associations
156+
157+
### on(event, cb) method (required)
158+
159+
Your driver should be an `EventEmitter`, and should emit the following types of events, when applicable:
160+
161+
* error

Readme.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,3 +840,14 @@ Person.hasMany("pets", Pet, {
840840
Person(1).getPets(...);
841841
Pet(2).getOwners(...);
842842
```
843+
844+
## Adding external drivers
845+
846+
To add an external driver to `orm2`, call the `addDriver` method, passing in the alias to use for connecting with this
847+
driver, along with the constructor for the driver object:
848+
849+
```js
850+
require('orm2').addDriver('cassandra', CassandraDriver);
851+
```
852+
853+
See [the documentation for creating drivers](./Drivers.md) for more details.

lib/Drivers/drivers.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
var aliases = require('./aliases');
2+
3+
module.exports.add = addDriver;
4+
module.exports.get = getDriver;
5+
6+
7+
var drivers = {};
8+
9+
function addDriver(name, constructor) {
10+
drivers[name] = constructor;
11+
}
12+
13+
function getDriver(name) {
14+
if (name in aliases) {
15+
return getDriver(aliases[name]);
16+
} else if (!(name in drivers)) {
17+
drivers[name] = require("./DML/" + name).Driver;
18+
}
19+
20+
return drivers[name];
21+
}

lib/ORM.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ var _ = require("lodash");
88

99
var Model = require("./Model").Model;
1010
var DriverAliases = require("./Drivers/aliases");
11+
var drivers = require("./Drivers/drivers");
1112
var Settings = require("./Settings");
1213
var Singleton = require("./Singleton");
1314
var ORMError = require("./Error");
@@ -48,7 +49,7 @@ exports.use = function (connection, proto, opts, cb) {
4849
}
4950

5051
try {
51-
var Driver = require("./Drivers/DML/" + proto).Driver;
52+
var Driver = drivers.get(proto);
5253
var settings = new Settings.Container(exports.settings.get('*'));
5354
var driver = new Driver(null, connection, {
5455
debug : (opts.query && opts.query.debug === 'true'),
@@ -109,7 +110,7 @@ exports.connect = function (opts, cb) {
109110
}
110111

111112
try {
112-
var Driver = require("./Drivers/DML/" + proto).Driver;
113+
var Driver = drivers.get(proto);
113114
var settings = new Settings.Container(exports.settings.get('*'));
114115
var debug = extractOption(opts, "debug");
115116
var pool = extractOption(opts, "pool");
@@ -142,6 +143,8 @@ exports.connect = function (opts, cb) {
142143
return db;
143144
};
144145

146+
exports.addDriver = drivers.add;
147+
145148
function ORM(driver_name, driver, settings) {
146149
this.validators = exports.validators;
147150
this.enforce = exports.enforce;

0 commit comments

Comments
 (0)