Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

types: support non-SQL styles of ds.execute #1855

Merged
merged 1 commit into from Jul 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 27 additions & 0 deletions types/__test__.ts
Expand Up @@ -88,3 +88,30 @@ const db = new DataSource('db', {connector: 'memory'});
await ctx.Model.expire('key', 100);
});
});

//-------
// DataSource supports different `execute` styles
//-------
(async function () {
// SQL style
const tx = await db.beginTransaction();
await db.execute('SELECT * FROM Product WHERE count > ?', [10], {
transaction: tx,
});
await tx.commit();

// MongoDB style
await db.execute('MyCollection', 'aggregate', [
{$lookup: { /* ... */ }},
{$unwind: '$data'},
{$out: 'tempData'}
]);

// Neo4J style
await db.execute({
query: 'MATCH (u:User {email: {email}}) RETURN u',
params: {
email: 'alice@example.com',
},
});
});
84 changes: 83 additions & 1 deletion types/datasource.d.ts
Expand Up @@ -300,12 +300,94 @@ export declare class DataSource extends EventEmitter {
ping(callback: Callback): void;

// Only promise variant, callback is intentionally not supported.

/**
* Execute a SQL command.
*
* **WARNING:** In general, it is always better to perform database actions
* through repository methods. Directly executing SQL may lead to unexpected
* results, corrupted data, security vulnerabilities and other issues.
*
* @example
*
* ```ts
* // MySQL
* const result = await db.execute(
* 'SELECT * FROM Products WHERE size > ?',
* [42]
* );
*
* // PostgreSQL
* const result = await db.execute(
* 'SELECT * FROM Products WHERE size > $1',
* [42]
* );
* ```
*
* @param command A parameterized SQL command or query.
* Check your database documentation for information on which characters to
* use as parameter placeholders.
* @param parameters List of parameter values to use.
* @param options Additional options, for example `transaction`.
* @returns A promise which resolves to the command output as returned by the
* database driver. The output type (data structure) is database specific and
* often depends on the command executed.
*/
execute(
command: string | object,
args?: any[] | object,
parameters?: any[] | object,
options?: Options,
): Promise<any>;

/**
* Execute a MongoDB command.
*
* **WARNING:** In general, it is always better to perform database actions
* through repository methods. Directly executing MongoDB commands may lead
* to unexpected results and other issues.
*
* @example
*
* ```ts
* const result = await db.execute('MyCollection', 'aggregate', [
* {$lookup: {
* // ...
* }},
* {$unwind: '$data'},
* {$out: 'tempData'}
* ]);
* ```
*
* @param collectionName The name of the collection to execute the command on.
* @param command The command name. See
* [Collection API docs](http://mongodb.github.io/node-mongodb-native/3.6/api/Collection.html)
* for the list of commands supported by the MongoDB client.
* @param parameters Command parameters (arguments), as described in MongoDB API
* docs for individual collection methods.
* @returns A promise which resolves to the command output as returned by the
* database driver.
*/
execute(
collectionName: string,
command: string,
...parameters: any[],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: the execute function in mongodb seems doesn't have a 3rd parameter, see
https://github.com/strongloop/loopback-connector-mongodb/blob/master/lib/mongodb.js#L467

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate your attention to details! 馃憤

MongoDB connector's execute function does not describe additional parameters in the function signature, but uses arguments.slice to access them:

https://github.com/strongloop/loopback-connector-mongodb/blob/c58e9fbe2b4161230751baf0385cb4c4f6958519/lib/mongodb.js#L469-L470

  // Get the parameters for the given command
  const args = [].slice.call(arguments, 2);

This code was written before rest parameters were introduced to the language, therefore it was not possible to encode ...parameters in the function signature.

): Promise<any>;

/**
* Execute a raw database command using a connector that's not described
* by LoopBack's `execute` API yet.
*
* **WARNING:** In general, it is always better to perform database actions
* through repository methods. Directly executing database commands may lead
* to unexpected results and other issues.
*
* @param args Command and parameters, please consult your connector's
* documentation to learn about supported commands and their parameters.
* @returns A promise which resolves to the command output as returned by the
* database driver.
*/
execute(...args: any[]): Promise<any>;

/**
* Begin a new transaction.
*
Expand Down