Skip to content

Commit

Permalink
Merge pull request #8 from treelinehq/update-inputs
Browse files Browse the repository at this point in the history
Update inputs
  • Loading branch information
particlebanana authored Feb 6, 2017
2 parents 04d95e0 + 55005a4 commit 8263b6b
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 41 deletions.
14 changes: 11 additions & 3 deletions machines/compile-statement.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ module.exports = {
outputDescription: 'The `nativeQuery` property is the compiled native query for the database. The `meta` property is reserved for custom driver-specific extensions.',
example: '==='
// example: {
// nativeQuery: '*',
// nativeQuery: 'SELECT * FROM foo',
// valuesToEscape: ['foo']
// meta: '==='
// }
},
Expand Down Expand Up @@ -105,9 +106,16 @@ module.exports = {
return exits.error(err);
}


// Attach a flag to the meta object to denote that the query was generated
// with Knex and that it's valuesToEscape don't need to be processed any further.
var meta = inputs.meta || {};
meta.isUsingQuestionMarks = true;

return exits.success({
nativeQuery: compiledNativeQuery,
meta: inputs.meta
nativeQuery: compiledNativeQuery.sql,
valuesToEscape: compiledNativeQuery.bindings || [],
meta: meta
});
}

Expand Down
81 changes: 45 additions & 36 deletions machines/send-native-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,23 @@ module.exports = {
},

nativeQuery: {
description: 'A SQL statement as a string (or to use built-in escaping, this should be provided as a dictionary).',
extendedDescription: 'If provided as a dictionary, this should contain `sql` (the SQL statement string; e.g. \'SELECT * FROM dogs WHERE name = ?\') as well as an array of `bindings` (e.g. [\'David\']).',
moreInfoUrl: 'https://github.com/felixge/node-mysql#performing-queries',
description: 'A native query for the database.',
extendedDescription: 'If `valuesToEscape` is provided, this supports template syntax like `$1`, `$2`, etc.',
whereToGet: {
description: 'This is oftentimes compiled from Waterline query syntax using "Compile statement", however it could also originate from userland code.',
description: 'Write a native query for this database, or if this driver supports it, use `compileStatement()` to build a native query from Waterline syntax.',
extendedDescription: 'This might be compiled from a Waterline statement (stage 4 query) using "Compile statement", however it could also originate directly from userland code.'
},
example: '===',
// example: '*',
example: 'SELECT * FROM pets WHERE species=$1 AND nickname=$2',
required: true
},

valuesToEscape: {
description: 'An optional list of strings, numbers, or special literals (true, false, or null) to escape and include in the native query, in order.',
extendedDescription: 'The first value in the list will be used to replace `$1`, the second value to replace `$2`, and so on. Note that numbers, `true`, `false`, and `null` are interpreted _differently_ than if they were strings wrapped in quotes. This array must never contain any arrays or dictionaries.',
example: '===',
defaultsTo: []
},

meta: {
friendlyName: 'Meta (custom)',
description: 'Additional stuff to pass to the driver.',
Expand Down Expand Up @@ -95,49 +101,52 @@ module.exports = {
}


// Validate query
// (supports raw SQL string or dictionary consisting of `sql` and `bindings` properties)
var sql;
var bindings = [];

if (_.isString(inputs.nativeQuery)) {
sql = inputs.nativeQuery;
} else if (_.isObject(inputs.nativeQuery) && _.isString(inputs.nativeQuery.sql)) {
sql = inputs.nativeQuery.sql;
if (_.isArray(inputs.nativeQuery.bindings)) {
bindings = inputs.nativeQuery.bindings;
}
} else {
return exits.error(new Error('Provided `nativeQuery` is invalid. Please specify either a string of raw SQL or a dictionary like `{sql: \'SELECT * FROM dogs WHERE name = $1\', bindings: [\'Rover\']}`.'));
}
// Validate provided native query.
var sql = inputs.nativeQuery;
var bindings = inputs.valuesToEscape || [];
var queryInfo;


debug('Running SQL Query:');
debug('SQL: ' + sql);
debug('Bindings: ' + bindings);
debug('Connection Id: ' + inputs.connection.id);

// Process SQL template, escaping bindings.
// This converts `$1`, `$2`, etc. into the escaped binding.
sql = sql.replace(/\$[1-9][0-9]*/g, function (substr){

// e.g. `'$3'` => `'3'` => `3` => `2`
var idx = +( substr.slice(1) ) - 1;
// If the meta flag is defined and it has a flag titled `isUsingQuestionMarks`
// then the query was generated by Knex in compileStatement and the query
// string is using `?` in place of values rather than the Waterline standardized
// $1, $2, etc.
if (!inputs.meta || !inputs.meta.isUsingQuestionMarks) {
// Process SQL template, escaping bindings.
// This converts `$1`, `$2`, etc. into the escaped binding.
sql = sql.replace(/\$[1-9][0-9]*/g, function (substr){

// e.g. `'$3'` => `'3'` => `3` => `2`
var idx = +( substr.slice(1) ) - 1;

// If no such binding exists, then just leave the original
// template string (e.g. "$3") alone.
if (idx >= bindings.length) {
return substr;
}

// If no such binding exists, then just leave the original
// template string (e.g. "$3") alone.
if (idx >= bindings.length) {
return substr;
}
// But otherwise, replace it with the escaped binding.
return inputs.connection.escape(bindings[idx]);
});

// But otherwise, replace it with the escaped binding.
return inputs.connection.escape(bindings[idx]);
});
// In this case the query has the values inline.
queryInfo = sql;
} else {
queryInfo = {
sql: sql,
values: bindings
};
}

debug('Compiled (final) SQL: ' + sql);

// Send native query to the database using node-mysql.
inputs.connection.query(sql, function query() {
inputs.connection.query(queryInfo, function query() {
// The exact format of the arguments for this callback are not part of
// the officially documented behavior of node-mysql (at least not as
// of March 2016 when this comment is being written).
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "machinepack-mysql",
"version": "2.0.0-3",
"version": "2.0.0-4",
"description": "Structured Node.js bindings for MySQL.",
"scripts": {
"test": "node ./node_modules/mocha/bin/mocha --recursive",
Expand Down
2 changes: 1 addition & 1 deletion test/queryable/compile-statement.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('Queryable ::', function() {
return done(err);
}

assert.equal(report.nativeQuery.sql, 'select `title`, `author`, `year` from `books`');
assert.equal(report.nativeQuery, 'select `title`, `author`, `year` from `books`');
return done();
});
});
Expand Down

0 comments on commit 8263b6b

Please sign in to comment.