@knorm/knorm
Version:
A JavaScript ORM written using ES6 classes
569 lines (567 loc) • 22.1 kB
TypeScript
/**
* 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 {};