UNPKG

@knorm/knorm

Version:

A JavaScript ORM written using ES6 classes

569 lines (567 loc) 22.1 kB
/** * Creates and runs queries and parses any data returned. */ export class Query { /** * Creates a new Query instance. * * @param {Model} model * * @todo use short table alias except in strict/debug mode */ constructor(model: Model); model: Model; options: { debug: any; }; config: { table: any; index: number; alias: any; schema: any; primary: any; fields: any; fieldsToColumns: any; fieldNames: any; notUpdated: any; unique: any; }; clone(): any; setOption(option: any, value: any): Query; addOption(option: any, value: any): Query; appendOption(option: any, value: any): Query; unsetOption(option: any): Query; unsetOptions(options: any): Query; getOption(option: any): any; hasOption(option: any): boolean; debug(debug?: boolean): Query; require(require?: boolean): Query; /** * Configures the batch-size for {@link Query#insert} and {@link Query#update} * (where batch updates are supported). When a batch-size is configured and * either of these operations is called with an array of data, multiple * queries will be sent to the database instead of a single one. If any data * is returned from the queries, it is merged into a single array instead of * returning multiple arrays. * * ::: tip INFO * The queries are sent to the database in parallel (i.e. via `Promise.all`). * Take that into consideration when deciding how many queries to send vs how * many items to have in a single query. * ::: * * ::: warning NOTE * When using this option, the order of the items in the array returned is * unlikely to match the order of the rows in the original array. This is * because the queries are sent in parallel and are not guaranteed to complete * in the same order. * ::: * * @param {number} batchSize The number of items to send in a single INSERT * or UPDATE query (where array updates are supported). * * @returns {Query} The same {@link Query} instance to allow chaining. */ batchSize(batchSize: number): Query; /** * Configures whether or not to return the first item in a result set from the * database from a {@link Query#fetch}, {@link Query#insert}, * {@link Query#update} or {@link Query#delete} operation, instead of * returning an array. This is handy when one is sure that there's only one * item in the rows returned from the database. * * @param {boolean} [first=true] If `true`, return the first item, else return * an array. * * @returns {Query} The same {@link Query} instance to allow chaining. */ first(first?: boolean | undefined): Query; addFields(fields: any): Query; distinct(...fields: any[]): Query; /** * Configures what fields to return from a database call. * * ::: tip INFO * This is also aliased as {@link Query#returning}. * ::: * * @param {string|array|object|boolean} fields The fields to return. When * passed as an object, the keys are used as aliases while the values are used * in the query, which allows one to use raw SQL. When passed as `false`, no * fields will be returned from the database call. * * @example Using raw SQL for PostgreSQL: * ```js{10} * Model.insert( * { * firstName: 'Foo', * lastName: 'Bar', * }, * { * returning: { * firstName: 'firstName', * lastName: 'lastName', * fullNames: Model.query.sql(`"firstName" || ' ' || upper("lastName")`) * } * } * ); * ``` * * @returns {Query} The same {@link Query} instance to allow chaining. */ fields(...fields: any): Query; /** * Configures what fields to return from a database call. * * ::: tip INFO * This is an alias for {@link Query#fields}. * ::: * * @param {string|array|object|boolean} fields The fields to return. * * @see {@link Query#fields} * @returns {Query} The same {@link Query} instance to allow chaining. */ returning(...fields: any): Query; where(...args: any[]): Query; having(...args: any[]): Query; groupBy(...groupBy: any[]): Query; orderBy(...orderBy: any[]): Query; limit(limit: any): Query; offset(offset: any): Query; forUpdate(): Query; of(...tables: any[]): Query; noWait(): Query; setOptions(options?: {}): Query; quote(value: any): any; formatTable(table: any, { quote }?: { quote?: boolean | undefined; }): any; formatAlias(alias: any, { quote }?: { quote: any; }): any; getTable({ format, quote }?: { format?: boolean | undefined; quote?: boolean | undefined; }): any; getAlias({ format, quote }?: { format?: boolean | undefined; quote?: boolean | undefined; }): any; formatColumn(column: any, { quote }?: { quote?: boolean | undefined; }): string; getColumn(field: any, { format, quote }?: { format?: boolean | undefined; quote: any; }): any; formatFieldAlias(alias: any, { quote }?: { quote?: boolean | undefined; }): any; getColumns(fields: any): never[]; prepareGroupBy(sql: any, groupBy: any): void; prepareOrderBy(sql: any, orderBy: any): any; isField(field: any): boolean; isWhere(field: any): any; getWhere(where: any, options?: {}): any; prepareWhere(sql: any, fields: any): any; prepareHaving(sql: any, fields: any): any; prepareSql(sql: any): Promise<any>; getInstance(data: any): any; getRowValue({ value }: { value: any; }): any; getCastFields(fields: any): any; getRow(instance: any): Promise<{}>; prepareData(data: any): Promise<any[][]>; ensureFields(): void; prepareInsert(data: any, options: any): Promise<any[]>; prepareUpdateBatch(batch: any): sqlBricks.UpdateStatement; prepareUpdate(data: any, options: any): Promise<any[]>; prepareDelete(options: any): Promise<any>; prepareFetch(options: any): Promise<any>; throwFetchRequireError(): void; getParsedRow(): any; parseRow(row: any): any; parseRows(rows: any): any; /** * Executes a query. This method calls, in order, {@link Query#connect} to * connect to the database, {@link Query#formatSql} to format the SQL to be * queried, {@link Query#query} to run the query against the database, and * finally, {@link Query#disconnect} to close the database connection. * * ::: tip INFO: Usage * This method is used internally by all {@link Query} methods i.e. * {@link Query#fetch}, {@link Query#insert}, {@link Query#update} and * {@link Query#delete}. * ::: * * ::: tip INFO: Query errors * If the promise from {@link Query#query} is rejected, the {@link QueryError} * is passed to {@link Query#disconnect}. * ::: * * ::: tip INFO: Transactions * When queries are executed in a transaction (that has not yet * {@link Transaction#ended}), this method does not connect to the database * via {@link Query#connect}. Instead, it connects via * {@link Transaction#connect}. The first query to be executed in the * transaction causes {@link Transaction#connect} and * {@link Transaction#begin} to be run, after which subsequent queries re-use * the transaction's connection. * * In addition, the database connection is not closed after executing the * query. This is deferred to be handled by {@link Transaction#commit} or * {@link Transaction#rollback}. * * If {@link Query#query} rejects with an error, the error is passed to * {@link Transaction#rollback}. * * **NOTE:** once the transaction has {@link Transaction#ended}, connections * are established and closed as usual, via {@link Query#connect} and * {@link Query#disconnect}. * ::: * * ::: tip INFO: Multiple queries * When the `sql` parameter is an array, a single database connection will be * created but {@link Query#formatSql} and {@link Query#query} will be called * for each item in the array. * * Also note that the queries are run in parallel (via `Promise.all`) and the * rows returned from each query are merged into a single array (via * `Array.prototype.concat`). * ::: * * @param {SqlBricks|object|string|array} sql The SQL to run. When passed as * an array, it can be an array of `SqlBricks` instances, objects or strings. * @param {string} sql.text The parameterized SQL string (with placeholders), * when `sql` is passed as an object. * @param {array} sql.values The values for the parameterized SQL string, when * `sql` is passed as an object. * * @returns {Promise} A `Promise` that is resolved with an array of rows * returned from running the query. * * ::: tip INFO * If {@link Query#query} rejects with an error, the SQL that caused the error * is attached to the error as an `sql` property. * ::: */ execute(sql: any): Promise<any>; connection: any; /** * Connects to the database, via {@link Connection#create}. This method is * called by {@link Query#execute}. * * @returns {Promise} The `Promise` from {@link Connection#create}, that is * resolved when a connection is established or rejected with a * {@link QueryError} on error. */ connect(): Promise<any>; /** * Formats SQL before it's sent to the database. This method is called * by {@link Query#execute} and allows manipulating or changing the SQL * before it's run via {@link Query#query}. * * @param {SqlBricks|object|string} sql The SQL to be formatted. * @param {string} sql.text The parameterized SQL string (with placeholders), * when `sql` is passed as an object. * @param {array} sql.values The values for the parameterized SQL string, when * `sql` is passed as an object. * * ::: tip INFO * This method is called internally by {@link Query#execute}. * ::: * * @returns {object} An object with `text` and `values` properties. Note that * when `sql` is passed as a string, the object returned has no `values` * property. When an {@link SqlBricks} instance is passed, an object is * returned (via [`toParams`](https://csnw.github.io/sql-bricks/#toParams)). */ formatSql(sql: any): object; /** * Runs a query against the database, via {@link Connection#query}. This * method is called by {@link Query#execute}. * * @param {object|string} sql The SQL to be run, after it's formatted via * {@link Query#formatSql}. * * @returns {Promise} The `Promise` from {@link Connection#query}, that is * resolved with the query result or rejected with a {@link QueryError} on * error. */ query(sql: string | object): Promise<any>; /** * Closes the database connection after running the query, via * {@link Connection#close}. This method is called by {@link Query#execute}. * * @param {QueryError} [error] A {@link QueryError} from {@link Query#query}, * if one occurred. This error is then passed to {@link Connection#close}. * * @returns {Promise} The `Promise` from {@link Connection#close}, that is * resolved when the connection is closed or rejected with a * {@link QueryError} on error. */ disconnect(error?: QueryError | undefined): Promise<any>; _attachErrorStack(error: any, stack: any): any; /** * Inserts data into the database. * * @param {Model|object|array} data The data to insert. Can be a plain object, * a {@link Model} instance or an array of objects or {@link Model} instances. * @param {object} [options] {@link Query} options * * ::: tip INFO * When the {@link Query#batchSize} option is set, multiple insert batches are * created and multiple queries are sent to the database, but on the same * database connection. * ::: * * @returns {Promise} the promise is resolved with an array of the model's * instances, expect in the following cases: * * - if the {@link Query#first} query option was set to `true`, then the * promise is resolved with a single model instance or `null` if no rows * were inserted. * - if no rows were inserted, then the array will be empty. If the * {@link Query#require} query option was set to `true`, then the `Promise` * is rejected with a {@link Query.NoRowsInsertedError} instead. * - if the insert query failed, then the `Promise` is rejected with a * {@link Query.InsertError} instead. * * @todo Add support for inserting joined models (via * [@knorm/relations](https://github.com/knorm/relations)) * @todo debug/strict mode: throw/warn if data is empty */ insert(data: any, options?: object | undefined): Promise<any>; /** * Updates data in the database. * * ::: warning NOTE * When the `data` param is a single object or {@link Model} instance and the * {@link Query#where} option is not set, **ALL rows in the table will be * updated!** This mimics the behaviour of `UPDATE` queries. However, if the * primary field is set in the data, then only the row matching the primary * field is updated. * ::: * * ::: tip INFO * The `data` param only works as an array in conjunction with plugins that * support updating multiple (ideally, in a single query) e.g. * [@knorm/postgres](https://github.com/knorm/postgres). * ::: * * ::: tip INFO * When the {@link Query#batchSize} option is set, multiple update batches are * created and multiple queries are sent to the database, but on the same * database connection. * ::: * * @param {Model|object|array} data The data to update. Can be a plain object, * a {@link Model} instance or an array of objects or instances. * @param {object} [options] {@link Query} options * * @returns {Promise} the promise is resolved with an array of the model's * instances, expect in the following cases: * * - if the {@link Query#first} query option was set to `true`, then the * promise is resolved with a single model instance or `null` if no rows * were inserted. * - if no rows were updated, then the array will be empty. If the * {@link Query#require} query option was set to `true`, then the `Promise` * is rejected with a {@link Query.NoRowsUpdatedError} instead. * - if the update query failed, then the `Promise` is rejected with a * {@link Query.UpdateError} instead. * * @todo Add support for updating joined models (via * [@knorm/relations](https://github.com/knorm/relations)) * @todo Update a single row when unique fields are set (in addition to * the primary field being set) * @todo debug/strict mode: throw/warn if data is empty */ update(data: any, options?: object | undefined): Promise<any>; /** * Either inserts or updates data in the database. * * ::: warning NOTE * When the `data` param is a single object or {@link Model} instance and the * {@link Query#where} option is not set, **ALL rows in the table will be * updated!** This mimics the behaviour of `UPDATE` queries. However, if the * primary field is set in the data, then only the row matching the primary * field is updated. * ::: * * ::: tip INFO * - when the `data` param is an array, this method proxies to * {@link Query#insert}. * - when the `data` param is an object and the primary field is **not** set, * this method proxies to {@link Query#insert}. However, if the primary * field is set, then the method proxies to {@link Query#update}. * ::: * * @param {Model|object|array} data The data to update. Can be a plain object, * a {@link Model} instance or an array of objects or instances. * @param {object} [options] {@link Query} options */ save(data: any, options?: object | undefined): Promise<any>; /** * Fetches data from the database. * * @param {object} [options] {@link Query} options * * @returns {Promise} the promise is resolved with an array of the model's * instances, expect in the following cases: * * - if the {@link Query#first} query option was set to `true`, then the * promise is resolved with a single model instance or `null` if no rows * were inserted. * - if no rows were updated, then the array will be empty. If the * {@link Query#require} query option was set to `true`, then the `Promise` * is rejected with a {@link Query.NoRowsFetchedError} instead. * - if the fetch query failed, then the `Promise` is rejected with a * {@link Query.FetchError} instead. * * @todo [@knorm/relations](https://github.com/knorm/relations)): throw if a * fetch is attempted from a joined query * @todo [@knorm/relations](https://github.com/knorm/relations)): add support * for limit and offset options in joined queries (probably with a subquery) */ fetch(options?: object | undefined): Promise<any>; /** * Deletes data from the database. * * ::: warning NOTE * If the {@link Query#where} option is not set, **ALL rows in the table will * be deleted!** This mimics the behaviour of `DELETE` queries. * ::: * * @param {object} [options] {@link Query} options * * @returns {Promise} the promise is resolved with an array of the model's * instances, expect in the following cases: * * - if the {@link Query#first} query option was set to `true`, then the * promise is resolved with a single model instance or `null` if no rows * were inserted. * - if no rows were updated, then the array will be empty. If the * {@link Query#require} query option was set to `true`, then the `Promise` * is rejected with a {@link Query.NoRowsDeletedError} instead. * - if the delete query failed, then the `Promise` is rejected with a * {@link Query.DeleteError} instead. * * @todo [@knorm/relations](https://github.com/knorm/relations)): add support * for deleting joined queries */ delete(options?: object | undefined): Promise<any>; /** @type {typeof import("sql-bricks")} */ sql: typeof import("sql-bricks"); /** * Alias for {@link Query#fields}, improves code readability when configuring a * single field. * * ::: tip INFO * This is an alias for {@link Query#fields}. * ::: * * @param {string|array|object|boolean} fields The field to return. * * @see {@link Query#fields} * * @returns {Query} The same {@link Query} instance to allow chaining. */ field: (...fields: any) => Query; /** * A reference to the {@link Knorm} instance. * * ::: tip * This is the same instance assigned to the {@link Query.knorm} static * property, just added as a convenience for use in instance methods. * ::: */ knorm: any; /** * The model registry. This is an object containing all the models added to the * ORM, keyed by name. See [model registry](/guides/models.md#model-registry) * for more info. * * ::: tip * This is the same object assigned to the {@link Query.models} static property, * just added as a convenience for use in instance methods. * ::: * * @type {object} */ models: object; /** * For queries run within a transaction, this is reference to the * {@link Transaction} instance. * * ::: warning NOTE * This is only set for {@link Query} instances that are run within a * transaction, otherwise it's set to `null`. * ::: * * ::: tip * This is the same instance assigned to the {@link Query.transaction} static * property, just added as a convenience for use in static methods. * ::: * */ transaction: any; } export namespace Query { export { Where }; export { Connection }; export { QueryError }; export { FetchError }; export { InsertError }; export { UpdateError }; export { DeleteError }; export { NoRowsError }; export { NoRowsFetchedError }; export { NoRowsInsertedError }; export { NoRowsUpdatedError }; export { NoRowsDeletedError }; export const knorm: any; export const models: object; export const transaction: any; } import { Model } from "./Model"; import sqlBricks from "sql-bricks"; import { QueryError } from "./QueryError"; import { Where } from "./Where"; import { Connection } from "./Connection"; declare class FetchError extends QueryError { constructor(...args: any[]); } declare class InsertError extends QueryError { constructor(...args: any[]); } declare class UpdateError extends QueryError { constructor(...args: any[]); } declare class DeleteError extends QueryError { constructor(...args: any[]); } import { NoRowsError } from "./NoRowsError"; declare class NoRowsFetchedError extends NoRowsError { constructor({ query }: { query: any; }); } declare class NoRowsInsertedError extends NoRowsError { constructor({ query }: { query: any; }); } declare class NoRowsUpdatedError extends NoRowsError { constructor({ query }: { query: any; }); } declare class NoRowsDeletedError extends NoRowsError { constructor({ query }: { query: any; }); } export {};