db = function (config) { var db = { log: config && config.log, config: config, model: function(modelConfig) { var proto = _.omit(modelConfig, isModelMeta); proto._meta = _.extend({ id: 'id' }, _.pick(modelConfig, isModelMeta)); proto._meta.db = this; var id = proto._meta.id; proto._meta.compoundKey = id == false || id instanceof Array; var modelPrototype = _.extend(Object.create(rowBase), proto); function model(obj, options) { var saved = typeof options == 'object' && options.hasOwnProperty('saved')? options.saved: false; var modified = typeof options == 'object' && options.hasOwnProperty('modified')? options.modified: false; var row = _.extend(Object.create(modelPrototype), obj); if (saved) { row.setSaved(); if (!modified) { row.setNotChanged(); } } return row; } model.query = function() { var self = this; return db.query.apply(db, arguments).then(function (entities) { return entities.map(function (e) { return self(e, {saved: true}); }); }); }; return model; }, query: function(_query, _params, _options) { var self = this; var queryParams = unescape.interpolate(_query, _params) var query = queryParams.query var params = queryParams.params var options = _options || {} return this.whenConnected(function () { var command = options.insert ? self.driver.insert(query, params, options) : self.driver.query(query, params, options) return command.then(function (results) { self.logResults(query, params, results, options); return results; }, function (e) { self.logError(query, params, e); throw e; }); }); }, statement: function(query, params, options) { options = _.extend({statement: true}, options); return this.query(query, params, options); }, whenConnected: function(fn) { if (this.runningBeginSession) { return fn(); } else { return this.connect().then(fn); } }, logError: function(query, params, error) { debug(query, params, error); }, logResults: function(query, params, results, options) { if (typeof this.log == 'function') { return this.log(query, params, results, options); } else { if (params) { debug(query, params); } else { debug(query); } if (options.insert) { return debugResults('id = ' + results.id); } else if (options.statement) { return debugResults('rows affected = ' + results.changes); } else if (!options.statement && results) { return debugResults(results); } } }, ensureConfigured: function() { if (!this.config) { throw new Error('sworm has not been configured to a database, use db.connect(config) or sworm.db(config)'); } }, connected: false, connect: function (config, fn) { if (typeof config === 'function') { fn = config; config = undefined; } if (config) { this.config = config; } if (typeof this.config == 'string') { this.config = configFromUrl(this.config) } var self = this; if (this.connection) { return this.connection; } this.ensureConfigured(); debug('connecting to', redactConfig(this.config)); var driver = { mssql: mssqlDriver, pg: pgDriver, mysql: mysqlDriver, oracle: oracleDriver, sqlite: sqliteDriver, websql: websqlDriver }[this.config.driver]; if (!driver) { throw new Error("no such driver: `" + this.config.driver + "'"); } this.driver = driver(); this.connection = this.driver.connect(this.config).then(function () { debug('connected to', redact ...
...
return debugResults(results);
}
}
},
ensureConfigured: function() {
if (!this.config) {
throw new Error('sworm has not been configured to a database, use db.connect(config) or sworm.db(config)');
}
},
connected: false,
connect: function (config, fn) {
if (typeof config === 'function') {
...
escape = function (value) { if (typeof value == 'string') { return "'" + value.replace(/'/g, "''") + "'" } else { return value } }
...
4. each of those entities are saved
5. the array is assigned to the outer entity's field
# Unescaping
It's sometimes useful to pass in some real unescaped SQL, for this you can use `sworm.unescape()` for model values or query
parameters.
Usual qualifiers apply here: when using this feature, make sure to protect your application from SQL injection by properly escaping
strings with `sworm.escape()` or by being extra careful!
For example, you can pass in an array of values for an `in (...)` statement:
```js
db.query('select * from people where names in (@names)', {names: sworm.unescape("'bob', 'jane'
;")})
```
...
function unescape(value) { return new Unescape(value) }
...
2. the function is called, passing the outer entity as the first argument
3. the function returns an array of entities
4. each of those entities are saved
5. the array is assigned to the outer entity's field
# Unescaping
It's sometimes useful to pass in some real unescaped SQL, for this you can use `sworm.unescape
()` for model values or query parameters.
Usual qualifiers apply here: when using this feature, make sure to protect your application from SQL injection by properly escaping
strings with `sworm.escape()` or by being extra careful!
For example, you can pass in an array of values for an `in (...)` statement:
```js
db.query('select * from people where names in (@names)', {names: sworm.unescape("'bob', 'jane'
;")})
...
function unescape(value) { return new Unescape(value) }
...
2. the function is called, passing the outer entity as the first argument
3. the function returns an array of entities
4. each of those entities are saved
5. the array is assigned to the outer entity's field
# Unescaping
It's sometimes useful to pass in some real unescaped SQL, for this you can use `sworm.unescape
()` for model values or query parameters.
Usual qualifiers apply here: when using this feature, make sure to protect your application from SQL injection by properly escaping
strings with `sworm.escape()` or by being extra careful!
For example, you can pass in an array of values for an `in (...)` statement:
```js
db.query('select * from people where names in (@names)', {names: sworm.unescape("'bob', 'jane'
;")})
...
interpolate = function (query, params) { var driverParams = _.omit(params, function (value) { return unescape.isUnescape(value) }) var interpolatedQuery = query.replace(paramRegex, function(_, name) { if (params.hasOwnProperty(name)) { var value = params[name] if (unescape.isUnescape(value)) { delete driverParams[name] return value.value } else { return _ } } else { return _ } }) return { query: interpolatedQuery, params: driverParams } }
...
};
return model;
},
query: function(_query, _params, _options) {
var self = this;
var queryParams = unescape.interpolate(_query, _params)
var query = queryParams.query
var params = queryParams.params
var options = _options || {}
return this.whenConnected(function () {
var command = options.insert
? self.driver.insert(query, params, options)
...
isUnescape = function (value) { return value instanceof Unescape }
...
var unescape = require('./unescape')
var rowBase = function() {
function fieldsForObject(obj) {
return Object.keys(obj).filter(function (key) {
var value = obj[key];
return value instanceof Date
|| unescape.isUnescape(value)
|| value instanceof Buffer
|| !(
value === null
|| value === undefined
|| value instanceof Object
);
});
...