Merge pull request #1857 from strongloop/feat/execute-db-command
feat: improve `dataSource.execute` to support more flavors
This commit is contained in:
commit
dd23a14b24
|
@ -2690,19 +2690,10 @@ DataSource.prototype.ping = function(cb) {
|
||||||
* Execute an arbitrary command. The commands are connector specific,
|
* Execute an arbitrary command. The commands are connector specific,
|
||||||
* please refer to the documentation of your connector for more details.
|
* please refer to the documentation of your connector for more details.
|
||||||
*
|
*
|
||||||
* @param command String|Object The command to execute, e.g. an SQL query.
|
* @param [...params] Array The command and its arguments, e.g. an SQL query.
|
||||||
* @param [args] Array Parameters values to set in the command.
|
|
||||||
* @param [options] Object Additional options, e.g. the transaction to use.
|
|
||||||
* @returns Promise A promise of the result
|
* @returns Promise A promise of the result
|
||||||
*/
|
*/
|
||||||
DataSource.prototype.execute = function(command, args = [], options = {}) {
|
DataSource.prototype.execute = function(...params) {
|
||||||
assert(typeof command === 'string' || typeof command === 'object',
|
|
||||||
'"command" must be a string or an object.');
|
|
||||||
assert(typeof args === 'object',
|
|
||||||
'"args" must be an object, an array or undefined.');
|
|
||||||
assert(typeof options === 'object',
|
|
||||||
'"options" must be an object or undefined.');
|
|
||||||
|
|
||||||
if (!this.connector) {
|
if (!this.connector) {
|
||||||
return Promise.reject(errorNotImplemented(
|
return Promise.reject(errorNotImplemented(
|
||||||
`DataSource "${this.name}" is missing a connector to execute the command.`,
|
`DataSource "${this.name}" is missing a connector to execute the command.`,
|
||||||
|
@ -2717,7 +2708,7 @@ DataSource.prototype.execute = function(command, args = [], options = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.connector.execute(command, args, options, onExecuted);
|
this.connector.execute(...params, onExecuted);
|
||||||
function onExecuted(err, result) {
|
function onExecuted(err, result) {
|
||||||
if (err) return reject(err);
|
if (err) return reject(err);
|
||||||
if (arguments.length > 2) {
|
if (arguments.length > 2) {
|
||||||
|
|
|
@ -415,6 +415,14 @@ describe('DataSource', function() {
|
||||||
it('supports shorthand version (cmd)', async () => {
|
it('supports shorthand version (cmd)', async () => {
|
||||||
let called = 'not called';
|
let called = 'not called';
|
||||||
ds.connector.execute = function(command, args, options, callback) {
|
ds.connector.execute = function(command, args, options, callback) {
|
||||||
|
// copied from loopback-connector/lib/sql.js
|
||||||
|
if (typeof args === 'function' && options === undefined && callback === undefined) {
|
||||||
|
// execute(sql, callback)
|
||||||
|
options = {};
|
||||||
|
callback = args;
|
||||||
|
args = [];
|
||||||
|
}
|
||||||
|
|
||||||
called = {command, args, options};
|
called = {command, args, options};
|
||||||
callback(null, 'a-result');
|
callback(null, 'a-result');
|
||||||
};
|
};
|
||||||
|
@ -431,6 +439,13 @@ describe('DataSource', function() {
|
||||||
it('supports shorthand version (cmd, args)', async () => {
|
it('supports shorthand version (cmd, args)', async () => {
|
||||||
let called = 'not called';
|
let called = 'not called';
|
||||||
ds.connector.execute = function(command, args, options, callback) {
|
ds.connector.execute = function(command, args, options, callback) {
|
||||||
|
// copied from loopback-connector/lib/sql.js
|
||||||
|
if (typeof options === 'function' && callback === undefined) {
|
||||||
|
// execute(sql, params, callback)
|
||||||
|
callback = options;
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
|
||||||
called = {command, args, options};
|
called = {command, args, options};
|
||||||
callback(null, 'a-result');
|
callback(null, 'a-result');
|
||||||
};
|
};
|
||||||
|
@ -444,7 +459,8 @@ describe('DataSource', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('converts multiple callbacks arguments into a promise resolved with an array', async () => {
|
it('converts multiple callbacks arguments into a promise resolved with an array', async () => {
|
||||||
ds.connector.execute = function(command, args, options, callback) {
|
ds.connector.execute = function() {
|
||||||
|
const callback = arguments[arguments.length - 1];
|
||||||
callback(null, 'result1', 'result2');
|
callback(null, 'result1', 'result2');
|
||||||
};
|
};
|
||||||
const result = await ds.execute('command');
|
const result = await ds.execute('command');
|
||||||
|
@ -460,14 +476,64 @@ describe('DataSource', function() {
|
||||||
|
|
||||||
// See https://www.npmjs.com/package/loopback-connector-neo4j-graph
|
// See https://www.npmjs.com/package/loopback-connector-neo4j-graph
|
||||||
const command = 'MATCH (u:User {email: {email}}) RETURN u';
|
const command = 'MATCH (u:User {email: {email}}) RETURN u';
|
||||||
await ds.execute(command, {email: 'alice@example.com'});
|
await ds.execute(command, {email: 'alice@example.com'}, {options: true});
|
||||||
called.should.be.eql({
|
called.should.be.eql({
|
||||||
command,
|
command,
|
||||||
args: {email: 'alice@example.com'},
|
args: {email: 'alice@example.com'},
|
||||||
options: {},
|
options: {options: true},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('supports MongoDB version (collection, cmd, args, options)', async () => {
|
||||||
|
let called = 'not called';
|
||||||
|
ds.connector.execute = function(...params) {
|
||||||
|
const callback = params.pop();
|
||||||
|
called = params;
|
||||||
|
callback(null, 'a-result');
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await ds.execute(
|
||||||
|
'collection',
|
||||||
|
'command',
|
||||||
|
['arg1', 'arg2'],
|
||||||
|
{options: true},
|
||||||
|
);
|
||||||
|
|
||||||
|
result.should.equal('a-result');
|
||||||
|
called.should.be.eql([
|
||||||
|
'collection',
|
||||||
|
'command',
|
||||||
|
['arg1', 'arg2'],
|
||||||
|
{options: true},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports free-form version (...params)', async () => {
|
||||||
|
let called = 'not called';
|
||||||
|
ds.connector.execute = function(...params) {
|
||||||
|
const callback = params.pop();
|
||||||
|
called = params;
|
||||||
|
callback(null, 'a-result');
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await ds.execute(
|
||||||
|
'arg1',
|
||||||
|
'arg2',
|
||||||
|
'arg3',
|
||||||
|
'arg4',
|
||||||
|
{options: true},
|
||||||
|
);
|
||||||
|
|
||||||
|
result.should.equal('a-result');
|
||||||
|
called.should.be.eql([
|
||||||
|
'arg1',
|
||||||
|
'arg2',
|
||||||
|
'arg3',
|
||||||
|
'arg4',
|
||||||
|
{options: true},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('throws NOT_IMPLEMENTED when no connector is provided', () => {
|
it('throws NOT_IMPLEMENTED when no connector is provided', () => {
|
||||||
ds.connector = undefined;
|
ds.connector = undefined;
|
||||||
return ds.execute('command').should.be.rejectedWith({
|
return ds.execute('command').should.be.rejectedWith({
|
||||||
|
|
Loading…
Reference in New Issue