quote.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. /**
  2. * Quote helpers implement quote ability for all dialects.
  3. * These are basic block of query building
  4. *
  5. * Its better to implement all dialect implementation together here. Which will allow
  6. * even abstract generator to use them by just specifying dialect type.
  7. *
  8. * Defining these helpers in each query dialect will leave
  9. * code in dual dependency of abstract <-> specific dialect
  10. */
  11. 'use strict';
  12. const Utils = require('../../../../utils');
  13. /**
  14. * list of reserved words in PostgreSQL 10
  15. * source: https://www.postgresql.org/docs/10/static/sql-keywords-appendix.html
  16. *
  17. * @private
  18. */
  19. const postgresReservedWords = 'all,analyse,analyze,and,any,array,as,asc,asymmetric,authorization,binary,both,case,cast,check,collate,collation,column,concurrently,constraint,create,cross,current_catalog,current_date,current_role,current_schema,current_time,current_timestamp,current_user,default,deferrable,desc,distinct,do,else,end,except,false,fetch,for,foreign,freeze,from,full,grant,group,having,ilike,in,initially,inner,intersect,into,is,isnull,join,lateral,leading,left,like,limit,localtime,localtimestamp,natural,not,notnull,null,offset,on,only,or,order,outer,overlaps,placing,primary,references,returning,right,select,session_user,similar,some,symmetric,table,tablesample,then,to,trailing,true,union,unique,user,using,variadic,verbose,when,where,window,with'.split(',');
  20. /**
  21. *
  22. * @param {string} dialect Dialect name
  23. * @param {string} identifier Identifier to quote
  24. * @param {object} [options]
  25. * @param {boolean} [options.force=false]
  26. * @param {boolean} [options.quoteIdentifiers=true]
  27. *
  28. * @returns {string}
  29. * @private
  30. */
  31. function quoteIdentifier(dialect, identifier, options) {
  32. if (identifier === '*') return identifier;
  33. options = Utils.defaults(options || {}, {
  34. force: false,
  35. quoteIdentifiers: true
  36. });
  37. switch (dialect) {
  38. case 'sqlite':
  39. case 'mariadb':
  40. case 'mysql':
  41. return Utils.addTicks(Utils.removeTicks(identifier, '`'), '`');
  42. case 'postgres':
  43. const rawIdentifier = Utils.removeTicks(identifier, '"');
  44. if (
  45. options.force !== true &&
  46. options.quoteIdentifiers === false &&
  47. !identifier.includes('.') &&
  48. !identifier.includes('->') &&
  49. !postgresReservedWords.includes(rawIdentifier.toLowerCase())
  50. ) {
  51. // In Postgres, if tables or attributes are created double-quoted,
  52. // they are also case sensitive. If they contain any uppercase
  53. // characters, they must always be double-quoted. This makes it
  54. // impossible to write queries in portable SQL if tables are created in
  55. // this way. Hence, we strip quotes if we don't want case sensitivity.
  56. return rawIdentifier;
  57. }
  58. return Utils.addTicks(rawIdentifier, '"');
  59. case 'mssql':
  60. return `[${identifier.replace(/[[\]']+/g, '')}]`;
  61. default:
  62. throw new Error(`Dialect "${dialect}" is not supported`);
  63. }
  64. }
  65. module.exports.quoteIdentifier = quoteIdentifier;
  66. /**
  67. * Test if a give string is already quoted
  68. *
  69. * @param {string} identifier
  70. *
  71. * @returns {boolean}
  72. * @private
  73. */
  74. function isIdentifierQuoted(identifier) {
  75. return /^\s*(?:([`"'])(?:(?!\1).|\1{2})*\1\.?)+\s*$/i.test(identifier);
  76. }
  77. module.exports.isIdentifierQuoted = isIdentifierQuoted;