table-name.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * Copyright (c) 2015-present, Vitaly Tomilov
  3. *
  4. * See the LICENSE file at the top-level directory of this distribution
  5. * for licensing information.
  6. *
  7. * Removal or modification of this copyright notice is prohibited.
  8. */
  9. const {assert} = require('../assert');
  10. const npm = {
  11. utils: require('../utils'),
  12. format: require('../formatting').as // formatting namespace
  13. };
  14. /**
  15. * @class helpers.TableName
  16. * @description
  17. * Represents a full table name that can be injected into queries directly.
  18. *
  19. * This is a read-only type that can be used wherever parameter `table` is supported.
  20. *
  21. * It supports $[Custom Type Formatting], which means you can use the type directly as a formatting
  22. * parameter, without specifying any escaping.
  23. *
  24. * Filter `:alias` is an alternative approach to splitting an SQL name into multiple ones.
  25. *
  26. * @param {string|Table} table
  27. * Table name details, depending on the type:
  28. *
  29. * - table name, if `table` is a string
  30. * - {@link Table} object
  31. *
  32. * @property {string} name
  33. * Formatted/escaped full table name, combining `schema` + `table`.
  34. *
  35. * @property {string} table
  36. * Table name.
  37. *
  38. * @property {string} schema
  39. * Database schema name.
  40. *
  41. * It is `undefined` when no valid schema was specified.
  42. *
  43. * @returns {helpers.TableName}
  44. *
  45. * @see
  46. * {@link helpers._TN _TN},
  47. * {@link helpers.TableName#toPostgres toPostgres}
  48. *
  49. * @example
  50. *
  51. * const table = new pgp.helpers.TableName({table: 'my-table', schema: 'my-schema'});
  52. * console.log(table);
  53. * //=> "my-schema"."my-table"
  54. *
  55. * // Formatting the type directly:
  56. * pgp.as.format('SELECT * FROM $1', table);
  57. * //=> SELECT * FROM "my-schema"."my-table"
  58. *
  59. */
  60. class TableName {
  61. constructor(table) {
  62. if (typeof table === 'string') {
  63. this.table = table;
  64. } else {
  65. const config = assert(table, ['table', 'schema']);
  66. this.table = config.table;
  67. if (npm.utils.isText(config.schema)) {
  68. this.schema = config.schema;
  69. }
  70. }
  71. if (!npm.utils.isText(this.table)) {
  72. throw new TypeError('Table name must be a non-empty text string.');
  73. }
  74. this.name = npm.format.name(this.table);
  75. if (this.schema) {
  76. this.name = npm.format.name(this.schema) + '.' + this.name;
  77. }
  78. Object.freeze(this);
  79. }
  80. }
  81. /**
  82. * @method helpers.TableName#toPostgres
  83. * @description
  84. * $[Custom Type Formatting], based on $[Symbolic CTF], i.e. the actual method is available only via {@link external:Symbol Symbol}:
  85. *
  86. * ```js
  87. * const {toPostgres} = pgp.as.ctf; // Custom Type Formatting symbols namespace
  88. * const fullName = tn[toPostgres]; // tn = an object of type TableName
  89. * ```
  90. *
  91. * This is a raw formatting type (`rawType = true`), i.e. when used as a query-formatting parameter, type `TableName`
  92. * injects full table name as raw text.
  93. *
  94. * @param {helpers.TableName} [self]
  95. * Optional self-reference, for ES6 arrow functions.
  96. *
  97. * @returns {string}
  98. * Escaped full table name that includes optional schema name, if specified.
  99. */
  100. TableName.prototype[npm.format.ctf.toPostgres] = function (self) {
  101. self = this instanceof TableName && this || self;
  102. return self.name;
  103. };
  104. TableName.prototype[npm.format.ctf.rawType] = true; // use as pre-formatted
  105. /**
  106. * @method helpers.TableName#toString
  107. * @description
  108. * Creates a well-formatted string that represents the object.
  109. *
  110. * It is called automatically when writing the object into the console.
  111. *
  112. * @returns {string}
  113. */
  114. TableName.prototype.toString = function () {
  115. return this.name;
  116. };
  117. npm.utils.addInspection(TableName, function () {
  118. return this.toString();
  119. });
  120. /**
  121. * @interface Table
  122. * @description
  123. * Structure for any table name/path.
  124. *
  125. * Function {@link helpers._TN _TN} can help you construct it from a string.
  126. *
  127. * @property {string} [schema] - schema name, if specified
  128. * @property {string} table - table name
  129. *
  130. * @see {@link helpers.TableName TableName}, {@link helpers._TN _TN}
  131. */
  132. /**
  133. * @external TemplateStringsArray
  134. * @see https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules_typedoc_node_modules_typescript_lib_lib_es5_d_.templatestringsarray.html
  135. */
  136. /**
  137. * @function helpers._TN
  138. * @description
  139. * Table-Name helper function, to convert any `"schema.table"` string
  140. * into `{schema, table}` object. It also works as a template-tag function.
  141. *
  142. * @param {string|TemplateStringsArray} path
  143. * Table-name path, as a simple string or a template string (with parameters).
  144. *
  145. * @example
  146. * const {ColumnSet, _TN} = pgp.helpers;
  147. *
  148. * // Using as a regular function:
  149. * const cs1 = new ColumnSet(['id', 'name'], {table: _TN('schema.table')});
  150. *
  151. * // Using as a template-tag function:
  152. * const schema = 'schema';
  153. * const cs2 = new ColumnSet(['id', 'name'], {table: _TN`${schema}.table`});
  154. *
  155. * @returns {Table}
  156. *
  157. * @see {@link helpers.TableName TableName}, {@link external:TemplateStringsArray TemplateStringsArray}
  158. */
  159. function _TN(path, ...args) {
  160. if (Array.isArray(path)) {
  161. path = path.reduce((a, c, i) => a + c + (args[i] ?? ''), '');
  162. } // else 'path' is a string
  163. const [schema, table] = path.split('.');
  164. if (table === undefined) {
  165. return {table: schema};
  166. }
  167. return schema ? {schema, table} : {table};
  168. }
  169. module.exports = {TableName, _TN};