/* * Copyright (c) 2015-present, Vitaly Tomilov * * See the LICENSE file at the top-level directory of this distribution * for licensing information. * * Removal or modification of this copyright notice is prohibited. */ const {assert} = require('../assert'); const npm = { utils: require('../utils'), format: require('../formatting').as // formatting namespace }; /** * @class helpers.TableName * @description * Represents a full table name that can be injected into queries directly. * * This is a read-only type that can be used wherever parameter `table` is supported. * * It supports $[Custom Type Formatting], which means you can use the type directly as a formatting * parameter, without specifying any escaping. * * Filter `:alias` is an alternative approach to splitting an SQL name into multiple ones. * * @param {string|Table} table * Table name details, depending on the type: * * - table name, if `table` is a string * - {@link Table} object * * @property {string} name * Formatted/escaped full table name, combining `schema` + `table`. * * @property {string} table * Table name. * * @property {string} schema * Database schema name. * * It is `undefined` when no valid schema was specified. * * @returns {helpers.TableName} * * @see * {@link helpers._TN _TN}, * {@link helpers.TableName#toPostgres toPostgres} * * @example * * const table = new pgp.helpers.TableName({table: 'my-table', schema: 'my-schema'}); * console.log(table); * //=> "my-schema"."my-table" * * // Formatting the type directly: * pgp.as.format('SELECT * FROM $1', table); * //=> SELECT * FROM "my-schema"."my-table" * */ class TableName { constructor(table) { if (typeof table === 'string') { this.table = table; } else { const config = assert(table, ['table', 'schema']); this.table = config.table; if (npm.utils.isText(config.schema)) { this.schema = config.schema; } } if (!npm.utils.isText(this.table)) { throw new TypeError('Table name must be a non-empty text string.'); } this.name = npm.format.name(this.table); if (this.schema) { this.name = npm.format.name(this.schema) + '.' + this.name; } Object.freeze(this); } } /** * @method helpers.TableName#toPostgres * @description * $[Custom Type Formatting], based on $[Symbolic CTF], i.e. the actual method is available only via {@link external:Symbol Symbol}: * * ```js * const {toPostgres} = pgp.as.ctf; // Custom Type Formatting symbols namespace * const fullName = tn[toPostgres]; // tn = an object of type TableName * ``` * * This is a raw formatting type (`rawType = true`), i.e. when used as a query-formatting parameter, type `TableName` * injects full table name as raw text. * * @param {helpers.TableName} [self] * Optional self-reference, for ES6 arrow functions. * * @returns {string} * Escaped full table name that includes optional schema name, if specified. */ TableName.prototype[npm.format.ctf.toPostgres] = function (self) { self = this instanceof TableName && this || self; return self.name; }; TableName.prototype[npm.format.ctf.rawType] = true; // use as pre-formatted /** * @method helpers.TableName#toString * @description * Creates a well-formatted string that represents the object. * * It is called automatically when writing the object into the console. * * @returns {string} */ TableName.prototype.toString = function () { return this.name; }; npm.utils.addInspection(TableName, function () { return this.toString(); }); /** * @interface Table * @description * Structure for any table name/path. * * Function {@link helpers._TN _TN} can help you construct it from a string. * * @property {string} [schema] - schema name, if specified * @property {string} table - table name * * @see {@link helpers.TableName TableName}, {@link helpers._TN _TN} */ /** * @external TemplateStringsArray * @see https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules_typedoc_node_modules_typescript_lib_lib_es5_d_.templatestringsarray.html */ /** * @function helpers._TN * @description * Table-Name helper function, to convert any `"schema.table"` string * into `{schema, table}` object. It also works as a template-tag function. * * @param {string|TemplateStringsArray} path * Table-name path, as a simple string or a template string (with parameters). * * @example * const {ColumnSet, _TN} = pgp.helpers; * * // Using as a regular function: * const cs1 = new ColumnSet(['id', 'name'], {table: _TN('schema.table')}); * * // Using as a template-tag function: * const schema = 'schema'; * const cs2 = new ColumnSet(['id', 'name'], {table: _TN`${schema}.table`}); * * @returns {Table} * * @see {@link helpers.TableName TableName}, {@link external:TemplateStringsArray TemplateStringsArray} */ function _TN(path, ...args) { if (Array.isArray(path)) { path = path.reduce((a, c, i) => a + c + (args[i] ?? ''), ''); } // else 'path' is a string const [schema, table] = path.split('.'); if (table === undefined) { return {table: schema}; } return schema ? {schema, table} : {table}; } module.exports = {TableName, _TN};