loopback-connector
Advanced tools
Comparing version 2.0.1 to 2.1.0
@@ -0,1 +1,11 @@ | ||
2015-05-18, Version 2.1.0 | ||
========================= | ||
* Update sql-connector.md (Rand McKinney) | ||
* Add tests for propagating a transaction over relations (Raymond Feng) | ||
* Add transaction support (Raymond Feng) | ||
2015-05-18, Version 2.0.1 | ||
@@ -2,0 +12,0 @@ ========================= |
@@ -1,3 +0,1 @@ | ||
# Using loopback-connector | ||
Use the loopback-connector module to build a LoopBack connector to back-end data sources | ||
@@ -8,3 +6,3 @@ such as databases or web services. There are many existing connectors for the most popular data sources; see: | ||
To build a new data source connector that doesn't yet exist, please see [Building a connector for a relational database] (http://docs.strongloop.com/display/LB/Building+a+connector+for+a+relational+database). | ||
To build a new data source connector that doesn't yet exist, please see [Building a connector for a relational database](http://docs.strongloop.com/display/LB/Building+a+connector+for+a+relational+database). | ||
@@ -5,1 +5,3 @@ exports.Connector = require('./lib/connector'); | ||
exports.ParameterizedSQL = exports.SQLConnector.ParameterizedSQL; | ||
exports.Transaction = require('./lib/transaction'); | ||
@@ -178,5 +178,5 @@ var debug = require('debug')('loopback:connector'); | ||
Connector.prototype.defineProperty = function(model, propertyName, propertyDefinition) { | ||
var modelDef = this.getModelDefinition(model); | ||
modelDef.properties[propertyName] = propertyDefinition; | ||
}; | ||
var modelDef = this.getModelDefinition(model); | ||
modelDef.properties[propertyName] = propertyDefinition; | ||
}; | ||
@@ -183,0 +183,0 @@ /** |
@@ -101,1 +101,2 @@ var assert = require('assert'); | ||
ParameterizedSQL.PLACEHOLDER = PLACEHOLDER; | ||
@@ -7,2 +7,3 @@ var util = require('util'); | ||
var ParameterizedSQL = require('./parameterized-sql'); | ||
var Transaction = require('./transaction'); | ||
@@ -29,2 +30,4 @@ module.exports = SQLConnector; | ||
SQLConnector.Transaction = Transaction; | ||
/** | ||
@@ -60,3 +63,2 @@ * Set the relational property to indicate the backend is a relational DB | ||
SQLConnector.prototype.getDefaultIdType = function(prop) { | ||
/*jshint unused:false */ | ||
return Number; | ||
@@ -473,3 +475,2 @@ }; | ||
selectStmt.merge(this.buildWhere(model, where)); | ||
selectStmt = this.applyPagination(model, selectStmt, { | ||
@@ -513,2 +514,3 @@ limit: 1, | ||
}; | ||
// Alias to `destroy`. Juggler checks `destroy` only. | ||
@@ -550,2 +552,3 @@ Connector.defineAliases(SQLConnector.prototype, 'destroy', | ||
}; | ||
// Alias to `destroyAll`. Juggler checks `destroyAll` only. | ||
@@ -615,2 +618,3 @@ Connector.defineAliases(SQLConnector.prototype, 'destroyAll', ['deleteAll']); | ||
}; | ||
// Alias to `update`. Juggler checks `update` only. | ||
@@ -1045,3 +1049,4 @@ Connector.defineAliases(SQLConnector.prototype, 'update', ['updateAll']); | ||
if (filter && filter.include) { | ||
self.getModelDefinition(model).model.include(objs, filter.include, cb); | ||
self.getModelDefinition(model).model.include( | ||
objs, filter.include, options, cb); | ||
} else { | ||
@@ -1052,2 +1057,3 @@ cb(null, objs); | ||
}; | ||
// Alias to `all`. Juggler checks `all` only. | ||
@@ -1054,0 +1060,0 @@ Connector.defineAliases(SQLConnector.prototype, 'all', ['findAll']); |
{ | ||
"name": "loopback-connector", | ||
"version": "2.0.1", | ||
"version": "2.1.0", | ||
"description": "Building blocks for LoopBack connectors", | ||
@@ -30,5 +30,5 @@ "keywords": [ | ||
"jshint": "^2.7.0", | ||
"loopback-datasource-juggler": "^2.27.0", | ||
"loopback-datasource-juggler": "^2.28.0", | ||
"mocha": "^2.2.4" | ||
} | ||
} |
@@ -48,2 +48,1 @@ var expect = require('chai').expect; | ||
}); | ||
@@ -6,3 +6,30 @@ /* | ||
var SQLConnector = require('../../lib/sql'); | ||
var debug = require('debug')('loopback:connector:test-sql'); | ||
var transactionId = 0; | ||
function MockTransaction(connector, name) { | ||
this.connector = connector; | ||
this.name = name; | ||
this.data = {}; | ||
} | ||
MockTransaction.prototype.commit = function(cb) { | ||
var self = this; | ||
// Merge data from this TX to the global data var | ||
for (var m in this.data) { | ||
self.connector.data[m] = self.connector.data[m] || []; | ||
for (var i = 0, n = this.data[m].length; i < n; i++) { | ||
self.connector.data[m].push(this.data[m]); | ||
} | ||
} | ||
this.data = {}; | ||
cb(); | ||
}; | ||
MockTransaction.prototype.rollback = function(cb) { | ||
this.data = {}; | ||
cb(); | ||
}; | ||
exports.initialize = function initializeDataSource(dataSource, callback) { | ||
@@ -22,2 +49,3 @@ process.nextTick(function() { | ||
this._tables = {}; | ||
this.data = {}; | ||
} | ||
@@ -80,2 +108,55 @@ | ||
TestConnector.prototype.escapeName = function(name) { | ||
return '`' + name + '`'; | ||
}; | ||
TestConnector.prototype.dbName = function(name) { | ||
return name.toUpperCase(); | ||
}; | ||
TestConnector.prototype.getPlaceholderForValue = function(key) { | ||
return '$' + key; | ||
}; | ||
TestConnector.prototype.escapeValue = function(value) { | ||
if (typeof value === 'number' || typeof value === 'boolean') { | ||
return value; | ||
} | ||
if (typeof value === 'string') { | ||
return "'" + value + "'"; | ||
} | ||
if (value == null) { | ||
return 'NULL'; | ||
} | ||
if (typeof value === 'object') { | ||
return String(value); | ||
} | ||
return value; | ||
}; | ||
TestConnector.prototype.toColumnValue = function(prop, val, escaping) { | ||
return escaping ? this.escapeValue(val) : val; | ||
}; | ||
TestConnector.prototype._buildLimit = function(model, limit, offset) { | ||
if (isNaN(limit)) { | ||
limit = 0; | ||
} | ||
if (isNaN(offset)) { | ||
offset = 0; | ||
} | ||
if (!limit && !offset) { | ||
return ''; | ||
} | ||
return 'LIMIT ' + (offset ? (offset + ',' + limit) : limit); | ||
}; | ||
TestConnector.prototype.applyPagination = | ||
function(model, stmt, filter) { | ||
/*jshint unused:false */ | ||
var limitClause = this._buildLimit(model, filter.limit, | ||
filter.offset || filter.skip); | ||
return stmt.merge(limitClause); | ||
}; | ||
TestConnector.prototype.dropTable = function(model, cb) { | ||
@@ -107,4 +188,51 @@ var err; | ||
TestConnector.prototype.getInsertedId = function(model, info) { | ||
return info; | ||
}; | ||
TestConnector.prototype.fromColumnValue = function(propertyDef, value) { | ||
return value; | ||
}; | ||
TestConnector.prototype.beginTransaction = function(isolationLevel, cb) { | ||
var name = 'tx_' + transactionId++; | ||
cb(null, new MockTransaction(this, name)); | ||
}; | ||
TestConnector.prototype.commit = function(tx, cb) { | ||
tx.commit(cb); | ||
}; | ||
TestConnector.prototype.rollback = function(tx, cb) { | ||
tx.rollback(cb); | ||
}; | ||
TestConnector.prototype.executeSQL = function(sql, params, options, callback) { | ||
callback(null, []); | ||
var transaction = options.transaction; | ||
var model = options.model; | ||
if (transaction && transaction.connector === this && transaction.connection) { | ||
if (sql.indexOf('INSERT') === 0) { | ||
transaction.connection.data[model] = | ||
transaction.connection.data[model] || []; | ||
transaction.connection.data[model].push({sql: sql, params: params}); | ||
debug('INSERT', transaction.connection.data, sql, | ||
transaction.connection.name); | ||
callback(null, 1); | ||
} | ||
else { | ||
debug('SELECT', transaction.connection.data, sql, | ||
transaction.connection.name); | ||
callback(null, transaction.connection.data[model] || []); | ||
} | ||
} else { | ||
if (sql.indexOf('INSERT') === 0) { | ||
this.data[model] = this.data[model] || []; | ||
this.data[model].push({sql: sql, params: params}); | ||
debug('INSERT', this.data, sql); | ||
callback(null, 1); | ||
} else { | ||
debug('SELECT', this.data, sql); | ||
callback(null, this.data[model] || []); | ||
} | ||
} | ||
}; |
@@ -310,2 +310,1 @@ var expect = require('chai').expect; | ||
}); | ||
332757
22
2395