Skip to content

Commit

Permalink
Merge pull request #512 from DullReferenceException/eternal-driver-su…
Browse files Browse the repository at this point in the history
…pport

Enabling third-party drivers
  • Loading branch information
dxg committed Jun 4, 2014
2 parents b160ffe + 33a09e9 commit b31e079
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 2 deletions.
159 changes: 159 additions & 0 deletions Adapters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Creating database adapters for orm2

To add a database adapter to `orm`, call its `addAdapter` method:

```js
require('orm2').addAdapter('cassandra', CassandraAdapter);
```

The first argument is the alias to register for connection URLs. For example, the above will allow you to do this:

```js
var orm = require('orm2');
orm.connect('cassandra://username:password@localhost/test', function (err, db) { });
```

The second argument is the constructor for your adapter object.

## Defining adapters

Your adapter should provide the following members.

### Constructor(config, connection, opts)

The adapter object constructor should have three parameters:

* config - optional configuration for the database connection. It contains the following properties:
* timezone - optional timezone
* href - URL to use for connecting to the database if the connection argument is null
* host - The hostname of `href`
* pathname - The `path` of `href`
* ssl - Boolean indicating whether the adapter should use SSL when connecting to the database
* query - Optional configuration for how the adapter should perform queries
* ssl - Boolean indicating whether queries should be sent using SSL
* strdates - Boolean indicating whether strings should be used for dates
* connection - optionally passed if reusing an existing connection
* opts - optional options configuring the adapter's behavior. It contains the following properties:
* pool - A boolean indicating whether the adapter should use connection pooling
* debug - If true, whether the adapter should operate in debug mode
* settings - A key/value object store. Use `get(key)` and `set(key, value)` methods to manipulate the settings. The
following settings are defined:
* properties.primary_key - The column/field name to use for object primary keys
* properties.association_key - A function taking a `name` and `field` parameter that returns the name of the
column that establishes the association

### isSql property

This should be set to `true` if your database is a SQL database.

### customTypes property

Your adapter should have a `customTypes` object, with the property names being the names of the custom types, and each
value being the options relating to the type.

### connect(cb) method (required)

Establishes your database connection.

### reconnect(cb, connection) method (optional)

Establishes/re-establishes a connection. The optional prior connection is passed in the `connection` parameter.

### ping(cb) method (required)

Tests whether your connection is still alive.

### close(cb) method (required)

Closes your database connection.

### propertyToValue(value, property) method (required)

Maps an object property to the correlated value to use for the database.

### valueToProperty(value, property) method (required)

Maps a database value to the property value to use for the mapped object.

### find(fields, table, conditions, opts, cb) method (required)

Implement this to select and return data stored in the database.
See the [documentation for Model.find](./README.md#modelfind-conditions---options---limit---order---cb-).

### insert(table, data, id_prop, cb) method (required)

Inserts an object into a database table.

### update(table, changes, conditions, cb) method (required)

Updates an object in the appropriate database row.

### remove(table, conditions, cb) method (required)

Implement this to support the removal of an object from a table.

### count(table, conditions, opts, cb) method (required)

Implement this to support [Model.count](./README.md#modelcount-conditions--cb).

### clear(table, cb) method (required)

Implement this to support `Model.clear`, which deletes all objects from a given table.

### eagerQuery(association, opts, ids, cb) method (required)

Implement this to support eager loading of associated objects.

### query property (optional)

For SQL databases, the `Query` object from the `sql-query` package used to generate ad-hoc queries.

### getQuery() method (optional)

For SQL databases, returns a `Query` object from the `sql-query` package.

### execQuery(query, cb) method (optional)

For SQL databases, this executes a `Query` object from the `sql-query` package.

### aggregate_functions[] property (optional)

If your adapter supports SQL aggregate functions, this should be an array of supported function names.

### hasMany(Model, association) method (optional)

If your adapter maintains associations in a unique (non-SQL-like) manner, return an object from this method to implement
a one-to-many association. The return value should have the following methods:

* has(Instance, Associations, conditions, cb) - tests if the associations have any objects matching the conditions
* get(Instance, conditions, options, createInstance, cb) - retrieves associated objects
* add(Instance, Association, data, cb) - inserts an associated object
* del(Instance, Associations, cb) - deletes an object from a set of associations

### sync(opts, cb) method (optional)

If your adapter supports creating a table from a model, implement this method. The following options are passed:

* extension
* id
* table
* properties
* allProperties
* indexes
* customTypes
* one_associations
* many_associations
* extend_associations

### drop(opts, cb) method (optional)

If your adapter supports dropping a table, implement this method. The following options are passed to this method:

* table - The name of the table
* properties
* one_associations
* many_associations

### on(event, cb) method (required)

Your adapter should be an `EventEmitter`, and should emit the `error` event when applicable.
11 changes: 11 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -840,3 +840,14 @@ Person.hasMany("pets", Pet, {
Person(1).getPets(...);
Pet(2).getOwners(...);
```

## Adding external database adapters

To add an external database adapter to `orm`, call the `addAdapter` method, passing in the alias to use for connecting
with this adapter, along with the constructor for the adapter:

```js
require('orm').addAdapter('cassandra', CassandraAdapter);
```

See [the documentation for creating adapters](./Adapters.md) for more details.
21 changes: 21 additions & 0 deletions lib/Adapters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
var aliases = require('./Drivers/aliases');

module.exports.add = addAdapter;
module.exports.get = getAdapter;


var adapters = {};

function addAdapter(name, constructor) {
adapters[name] = constructor;
}

function getAdapter(name) {
if (name in aliases) {
return getAdapter(aliases[name]);
} else if (!(name in adapters)) {
adapters[name] = require("./Drivers/DML/" + name).Driver;
}

return adapters[name];
}
7 changes: 5 additions & 2 deletions lib/ORM.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var _ = require("lodash");

var Model = require("./Model").Model;
var DriverAliases = require("./Drivers/aliases");
var adapters = require("./Adapters");
var Settings = require("./Settings");
var Singleton = require("./Singleton");
var ORMError = require("./Error");
Expand Down Expand Up @@ -48,7 +49,7 @@ exports.use = function (connection, proto, opts, cb) {
}

try {
var Driver = require("./Drivers/DML/" + proto).Driver;
var Driver = adapters.get(proto);
var settings = new Settings.Container(exports.settings.get('*'));
var driver = new Driver(null, connection, {
debug : (opts.query && opts.query.debug === 'true'),
Expand Down Expand Up @@ -109,7 +110,7 @@ exports.connect = function (opts, cb) {
}

try {
var Driver = require("./Drivers/DML/" + proto).Driver;
var Driver = adapters.get(proto);
var settings = new Settings.Container(exports.settings.get('*'));
var debug = extractOption(opts, "debug");
var pool = extractOption(opts, "pool");
Expand Down Expand Up @@ -142,6 +143,8 @@ exports.connect = function (opts, cb) {
return db;
};

exports.addAdapter = adapters.add;

function ORM(driver_name, driver, settings) {
this.validators = exports.validators;
this.enforce = exports.enforce;
Expand Down

0 comments on commit b31e079

Please sign in to comment.