UNPKG

@secam/pgsql-ast-parser

Version:

Fork of pgsql-ast-parser Simple Postgres SQL parser/modifier for pg-mem

1,633 lines (1,617 loc) 370 kB
(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 7); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { module.exports = require("moo"); /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.unbox = exports.doubleQuoted = exports.box = exports.track = exports.tracking = exports.trackingComments = exports.lexerAny = exports.lexer = void 0; const moo_1 = __webpack_require__(0); const keywords_1 = __webpack_require__(3); // build keywords const keywordsMap = {}; for (const k of keywords_1.sqlKeywords) { keywordsMap['kw_' + k.toLowerCase()] = k; } const caseInsensitiveKeywords = (map) => { const transform = (0, moo_1.keywords)(map); return (text) => transform(text.toUpperCase()); }; // build lexer exports.lexer = (0, moo_1.compile)({ word: { match: /[eE](?!')[A-Za-z0-9_]*|[a-df-zA-DF-Z_][A-Za-z0-9_]*/, type: caseInsensitiveKeywords(keywordsMap), value: x => x.toLowerCase(), }, wordQuoted: { match: /"(?:[^"\*]|"")+"/, type: () => 'quoted_word', value: x => x.substring(1, x.length - 1), }, string: { match: /'(?:[^']|\'\')*'/, value: x => { return x.substring(1, x.length - 1) .replace(/''/g, '\''); }, }, eString: { match: /\b(?:e|E)'(?:[^'\\]|[\r\n\s]|(?:\\\s)|(?:\\\n)|(?:\\.)|(?:\'\'))+'/, value: x => { return x.substring(2, x.length - 1) .replace(/''/g, '\'') .replace(/\\([\s\n])/g, (_, x) => x) .replace(/\\./g, m => JSON.parse('"' + m + '"')); }, }, qparam: { match: /\$\d+/, }, commentLine: /\-\-.*?$[\s\r\n]*/, commentFullOpen: /\/\*/, commentFullClose: /\*\/[\s\r\n]*/, star: '*', comma: ',', space: { match: /[\s\t\n\v\f\r]+/, lineBreaks: true, }, int: /\-?\d+(?![\.\d])/, float: /\-?(?:(?:\d*\.\d+)|(?:\d+\.\d*))/, // word: /[a-zA-Z][A-Za-z0-9_\-]*/, lparen: '(', rparen: ')', lbracket: '[', rbracket: ']', semicolon: ';', dot: /\.(?!\d)/, op_cast: '::', op_colon: ':', op_plus: '+', op_eq: '=', op_neq: { match: /(?:!=)|(?:\<\>)/, value: () => '!=', }, op_membertext: '->>', op_member: '->', op_minus: '-', op_div: /\//, op_not_ilike: /\!~~\*/, op_not_like: /\!~~/, op_ilike: /~~\*/, op_like: /~~/, op_mod: '%', op_exp: '^', op_additive: { // group other additive operators match: ['||', '-', '#-', '&&'], }, op_compare: { // group other comparison operators // ... to add: "IN" and "NOT IN" that are matched by keywords match: ['>', '>=', '<', '<=', '@>', '<@', '?', '?|', '?&', '#>>', '>>', '<<', '~', '~*', '!~', '!~*', '@@'], }, ops_others: { // referenced as (any other operator) in https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-PRECEDENCE // see also https://www.postgresql.org/docs/9.0/functions-math.html match: ['|', '&', '^', '#'], }, codeblock: { match: /\$\$(?:.|[\s\t\n\v\f\r])*?\$\$/s, lineBreaks: true, value: (x) => x.substring(2, x.length - 2), }, }); exports.lexer.next = (next => () => { let tok; let commentFull = null; while (tok = next.call(exports.lexer)) { // js regex can't be recursive, so we'll keep track of nested opens (/*) and closes (*/). if (tok.type === 'commentFullOpen') { if (commentFull === null) { // initial open - start collecting content commentFull = { nested: 0, offset: tok.offset, text: tok.text }; continue; } commentFull.nested++; } if (commentFull != null) { // collect comment content commentFull.text += tok.text; if (tok.type === 'commentFullClose') { if (commentFull.nested === 0) { // finish comment, if not nested comments === null || comments === void 0 ? void 0 : comments.push(makeComment(commentFull)); commentFull = null; continue; } commentFull.nested--; } continue; } if (tok.type === 'space') { continue; } if (tok.type === 'commentLine') { comments === null || comments === void 0 ? void 0 : comments.push(makeComment(tok)); continue; } break; } if (trackingLoc && tok) { const start = tok.offset; const loc = { start, end: start + tok.text.length, }; tok._location = loc; } return tok; })(exports.lexer.next); exports.lexerAny = exports.lexer; let comments = null; const makeComment = ({ offset, text }) => ({ _location: { start: offset, end: offset + text.length }, comment: text, }); function trackingComments(act) { if (comments) { throw new Error('WAT ? Recursive comments tracking 🤔🤨 ?'); } try { comments = []; const ast = act(); return { comments, ast }; } finally { comments = null; } } exports.trackingComments = trackingComments; let trackingLoc = false; function tracking(act) { if (trackingLoc) { return act(); } try { trackingLoc = true; return act(); } finally { trackingLoc = false; } } exports.tracking = tracking; function track(xs, ret) { if (!trackingLoc || !ret || typeof ret !== 'object') { return ret; } const start = seek(xs, true); const end = seek(xs, false); if (!start || !end) { return ret; } if (start === end) { ret._location = start; } else { const loc = { start: start.start, end: end.end, }; ret._location = loc; } return ret; } exports.track = track; const literal = Symbol('_literal'); const doubleQuotedSym = Symbol('_doublequoted'); function box(xs, value, doubleQuoted) { if (!trackingLoc && !doubleQuoted) { return value; } return track(xs, { [literal]: value, [doubleQuotedSym]: doubleQuoted }); } exports.box = box; function unwrapNoBox(e) { if (Array.isArray(e) && e.length === 1) { e = unwrapNoBox(e[0]); } if (Array.isArray(e) && !e.length) { return null; } return e; } function doubleQuoted(value) { const uw = unwrapNoBox(value); if (typeof value === 'object' && (uw === null || uw === void 0 ? void 0 : uw[doubleQuotedSym])) { return { doubleQuoted: true }; } return undefined; } exports.doubleQuoted = doubleQuoted; function unbox(value) { var _a; if (typeof value === 'object') { return (_a = value === null || value === void 0 ? void 0 : value[literal]) !== null && _a !== void 0 ? _a : value; } return value; } exports.unbox = unbox; function seek(xs, start) { if (!xs) { return null; } if (Array.isArray(xs)) { const diff = start ? 1 : -1; for (let i = start ? 0 : xs.length - 1; i >= 0 && i < xs.length; i += diff) { const v = seek(xs[i], start); if (v) { return v; } } return null; } if (typeof xs !== 'object') { return null; } return xs._location; } /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AstDefaultMapper = exports.arrayNilMap = exports.assignChanged = exports.astMapper = void 0; const utils_1 = __webpack_require__(6); /** * Builds an AST modifier based on the default implementation, merged with the one you provide. * * Example of a modifier that renames all reference to columns 'foo' to 'bar' * ```ts * const mapper = astMapper(b => ({ * ref: a => assignChanged(a, { * name: a.name === 'foo' * ? 'bar' * : a.name * }) * })); * * const modified = mapper.statement(myStatementToModify); * ``` */ function astMapper(modifierBuilder) { const instance = new AstDefaultMapper(); instance.wrapped = modifierBuilder(instance); return instance; } exports.astMapper = astMapper; /** * An helper function that returns a copy of an object with modified properties * (similar to Object.assign()), but ONLY if thos properties have changed. * Will return the original object if not. */ function assignChanged(orig, assign) { if (!orig) { return orig; } let changed = false; for (const k of Object.keys(assign)) { if (orig[k] !== assign[k]) { changed = true; break; } } if (!changed) { return orig; } return (0, utils_1.trimNullish)({ ...orig, ...assign, }, 0); } exports.assignChanged = assignChanged; /** * An helper function that returns a map of an array, but: * - It will return the original array if it is null-ish * - It will remove all null-ish entries * - It will return the original array if nothing has changed */ function arrayNilMap(collection, mapper) { if (!(collection === null || collection === void 0 ? void 0 : collection.length)) { return collection; } let changed = false; let ret = collection; for (let i = 0; i < collection.length; i++) { const orig = collection[i]; const val = mapper(orig); if (!changed && (!val || val !== orig)) { changed = true; ret = collection.slice(0, i); } if (!val) { continue; } if (changed) { ret.push(val); } } return ret; } exports.arrayNilMap = arrayNilMap; function withAccepts(val) { switch (val === null || val === void 0 ? void 0 : val.type) { case 'select': case 'delete': case 'insert': case 'update': case 'union': case 'union all': case 'with': return true; default: return false; } } /** * Can be used to modify an AST. * * You will have to override functions that you're interested in to use this class. * * Example: Will remove all references in */ class AstDefaultMapper { super() { return new SkipModifier(this); } statement(val) { switch (val.type) { case 'alter table': return this.alterTable(val); case 'alter index': return this.alterIndex(val); case 'commit': case 'start transaction': case 'rollback': return this.transaction(val); case 'create index': return this.createIndex(val); case 'create table': return this.createTable(val); case 'truncate table': return this.truncateTable(val); case 'delete': return this.delete(val); case 'insert': return this.insert(val); case 'with': return this.with(val); case 'with recursive': return this.withRecursive(val); case 'select': return this.selection(val); case 'update': return this.update(val); case 'create extension': return this.createExtension(val); case 'tablespace': return this.tablespace(val); case 'set': return this.setGlobal(val); case 'set timezone': return this.setTimezone(val); case 'set names': return this.setNames(val); case 'create sequence': return this.createSequence(val); case 'alter sequence': return this.alterSequence(val); case 'begin': return this.begin(val); case 'drop table': case 'drop index': case 'drop sequence': case 'drop type': case 'drop trigger': return this.drop(val); case 'create enum': return this.createEnum(val); case 'alter enum': return this.alterEnum(val); case 'create composite type': return this.createCompositeType(val); case 'union': case 'union all': return this.union(val); case 'show': return this.show(val); case 'prepare': return this.prepare(val); case 'deallocate': return this.deallocate(val); case 'create view': return this.createView(val); case 'create materialized view': return this.createMaterializedView(val); case 'refresh materialized view': return this.refreshMaterializedView(val); case 'create schema': return this.createSchema(val); case 'raise': return this.raise(val); case 'comment': return this.comment(val); case 'do': return this.do(val); case 'create function': return this.createFunction(val); case 'drop function': return this.dropFunction(val); case 'values': return this.values(val); default: throw utils_1.NotSupported.never(val); } } comment(val) { // not really supported :/ return val; } createView(val) { const query = this.select(val.query); if (!query) { return null; } const ref = this.tableRef(val.name); if (!ref) { return null; } return assignChanged(val, { query, name: ref, }); } createMaterializedView(val) { const query = this.select(val.query); if (!query) { return null; } const ref = this.tableRef(val.name); if (!ref) { return null; } return assignChanged(val, { query, name: ref, }); } refreshMaterializedView(val) { return val; } do(val) { return val; } createFunction(val) { // process arguments const args = arrayNilMap(val.arguments, a => { const type = this.dataType(a.type); return assignChanged(a, { type }); }); // process return type let returns; if (val.returns) { switch (val.returns.kind) { case 'table': returns = assignChanged(val.returns, { columns: arrayNilMap(val.returns.columns, v => { const type = this.dataType(v.type); return type && assignChanged(v, { type }); }) }); break; case undefined: case null: case 'array': returns = this.dataType(val.returns); break; default: throw utils_1.NotSupported.never(val.returns); } } return assignChanged(val, { returns, arguments: args, }); } dropFunction(val) { const args = arrayNilMap(val.arguments, a => { const type = this.dataType(a.type); return assignChanged(a, { type }); }); return assignChanged(val, { arguments: args, }); } show(val) { return val; } createEnum(val) { return val; } alterEnum(val) { return val; } createCompositeType(val) { const attributes = arrayNilMap(val.attributes, a => assignChanged(a, { dataType: this.dataType(a.dataType), })); return assignChanged(val, { attributes }); } drop(val) { return val; } alterSequence(seq) { if (seq.change.type === 'set options') { if (seq.change.as) { this.dataType(seq.change.as); } } return seq; } begin(begin) { return begin; } createSequence(seq) { if (seq.options.as) { this.dataType(seq.options.as); } return seq; } tablespace(val) { return val; } setGlobal(val) { return val; } setTimezone(val) { return val; } setNames(val) { return val; } update(val) { if (!val) { return val; } const table = this.tableRef(val.table); if (!table) { return null; // nothing to update } const from = val.from && this.from(val.from); const where = val.where && this.expr(val.where); const sets = arrayNilMap(val.sets, x => this.set(x)); if (!(sets === null || sets === void 0 ? void 0 : sets.length)) { return null; // nothing to update } const returning = arrayNilMap(val.returning, c => this.selectionColumn(c)); return assignChanged(val, { table, where, sets, from, returning, }); } insert(val) { var _a, _b; const into = this.tableRef(val.into); if (!into) { return null; // nowhere to insert into } const select = val.insert && this.select(val.insert); if (!select) { // nothing to insert return null; } const returning = arrayNilMap(val.returning, c => this.selectionColumn(c)); let on = (_a = val.onConflict) === null || _a === void 0 ? void 0 : _a.on; switch (on === null || on === void 0 ? void 0 : on.type) { case 'on constraint': // nothing to do break; case 'on expr': on = assignChanged(on, { exprs: arrayNilMap(on.exprs, e => this.expr(e)), }); break; case null: case undefined: break; default: throw utils_1.NotSupported.never(on); } let ocdo = (_b = val.onConflict) === null || _b === void 0 ? void 0 : _b.do; if (ocdo && ocdo !== 'do nothing') { const sets = arrayNilMap(ocdo.sets, x => this.set(x)); if (!(sets === null || sets === void 0 ? void 0 : sets.length)) { ocdo = 'do nothing'; } else if (ocdo.sets !== sets) { ocdo = { sets }; } } return assignChanged(val, { into, insert: select, returning, onConflict: !ocdo ? val.onConflict : assignChanged(val.onConflict, { do: ocdo, on, }), }); } raise(val) { return assignChanged(val, { formatExprs: val.formatExprs && arrayNilMap(val.formatExprs, x => this.expr(x)), using: val.using && arrayNilMap(val.using, u => { return assignChanged(u, { value: this.expr(u.value), }); }), }); } delete(val) { const from = this.tableRef(val.from); if (!from) { return null; // nothing to delete } const where = val.where && this.expr(val.where); const returning = arrayNilMap(val.returning, c => this.selectionColumn(c)); return assignChanged(val, { where, returning, from, }); } createSchema(val) { return val; } createTable(val) { const columns = arrayNilMap(val.columns, col => { switch (col.kind) { case 'column': return this.createColumn(col); case 'like table': return this.likeTable(col); default: throw utils_1.NotSupported.never(col); } }); if (!(columns === null || columns === void 0 ? void 0 : columns.length)) { return null; // no column to create } return assignChanged(val, { columns, }); } likeTable(col) { const like = this.tableRef(col.like); if (!like) { return null; } return assignChanged(col, { like }); } truncateTable(val) { return val; } constraint(c) { switch (c.type) { case 'not null': case 'null': case 'primary key': case 'unique': case 'add generated': return c; case 'default': { const def = this.expr(c.default); if (!def) { return null; } return assignChanged(c, { default: def, }); } case 'check': { const def = this.expr(c.expr); if (!def) { return null; } return assignChanged(c, { expr: def, }); } case 'reference': { const foreignTable = this.tableRef(c.foreignTable); if (!foreignTable) { return null; } return assignChanged(c, { foreignTable, }); } default: throw utils_1.NotSupported.never(c); } } set(st) { const value = this.expr(st.value); if (!value) { return null; } return assignChanged(st, { value, }); } // ========================================= // ================ STUFF ================== // ========================================= /** Called when a data type definition is encountered */ dataType(dataType) { return dataType; } /** Called when an alias of a table is created */ tableRef(st) { return st; } transaction(val) { return val; } createExtension(val) { return val; } createIndex(val) { const expressions = arrayNilMap(val.expressions, e => { const expression = this.expr(e.expression); if (expression === e.expression) { return e; } if (!expression) { return null; // no more index expression } return { ...e, expression, }; }); if (!(expressions === null || expressions === void 0 ? void 0 : expressions.length)) { return null; // no columns to create index on } return assignChanged(val, { expressions, }); } prepare(st) { const statement = this.statement(st.statement); if (!statement) { return null; } return assignChanged(st, { args: arrayNilMap(st.args, a => this.dataType(a)), statement, }); } deallocate(st) { return st; } // ========================================= // ============== ALTER INDEX ============== // ========================================= alterIndex(st) { // not much as of today...might improve this in the future return st; } // ========================================= // ============== ALTER TABLE ============== // ========================================= alterTable(st) { var _a; const table = this.tableRef(st.table); if (!table) { return null; // no table } let changes = []; let hasChanged = false; for (let i = 0; i < (((_a = st.changes) === null || _a === void 0 ? void 0 : _a.length) || 0); i++) { const currentChange = st.changes[i]; const change = this.tableAlteration(currentChange, st.table); hasChanged = hasChanged || (change != currentChange); if (!!change) { changes.push(change); } } if (!changes.length) { return null; // no change left } if (!hasChanged) { return st; } return assignChanged(st, { table, changes, }); } tableAlteration(change, table) { switch (change.type) { case 'add column': return this.addColumn(change, table); case 'add constraint': return this.addConstraint(change, table); case 'alter column': return this.alterColumn(change, table); case 'rename': return this.renameTable(change, table); case 'rename column': return this.renameColumn(change, table); case 'rename constraint': return this.renameConstraint(change, table); case 'drop column': return this.dropColumn(change, table); case 'drop constraint': return this.dropConstraint(change, table); case 'owner': return this.setTableOwner(change, table); default: throw utils_1.NotSupported.never(change); } } dropColumn(change, table) { return change; } dropConstraint(change, table) { return change; } setTableOwner(change, table) { return change; } renameConstraint(change, table) { return change; } renameColumn(change, table) { return change; } renameTable(change, table) { return change; } alterColumn(change, inTable) { let alter; switch (change.alter.type) { case 'set default': alter = this.setColumnDefault(change.alter, inTable, change.column); break; case 'set type': alter = this.setColumnType(change.alter, inTable, change.column); break; case 'drop default': case 'set not null': case 'drop not null': alter = this.alterColumnSimple(change.alter, inTable, change.column); break; case 'add generated': alter = this.alterColumnAddGenerated(change.alter, inTable, change.column); break; default: throw utils_1.NotSupported.never(change.alter); } if (!alter) { return null; // no more alter } return assignChanged(change, { alter, }); } setColumnType(alter, inTable, inColumn) { const dataType = this.dataType(alter.dataType); return assignChanged(alter, { dataType, }); } alterColumnAddGenerated(alter, inTable, inColumn) { return alter; } alterColumnSimple(alter, inTable, inColumn) { return alter; } setColumnDefault(alter, inTable, inColumn) { const def = this.expr(alter.default); if (!def) { return null; // no more default to set } return assignChanged(alter, { default: def, }); } addConstraint(change, inTable) { return change; } addColumn(change, inTable) { const column = this.createColumn(change.column); if (!column) { return null; // no more column to add } return assignChanged(change, { column, }); } createColumn(col) { var _a; // to be overriden const dataType = this.dataType(col.dataType); if (!dataType) { return null; // no data type => remove column } const constraints = (_a = arrayNilMap(col.constraints, m => this.constraint(m))) !== null && _a !== void 0 ? _a : undefined; return assignChanged(col, { dataType, constraints, }); } // ========================================= // ============== SELECTIONS ============== // ========================================= select(val) { switch (val.type) { case 'select': return this.selection(val); case 'union': case 'union all': return this.union(val); case 'with': return this.with(val); case 'values': return this.values(val); case 'with recursive': return this.withRecursive(val); default: throw utils_1.NotSupported.never(val); } } selection(val) { var _a, _b; const from = arrayNilMap(val.from, c => this.from(c)); const columns = arrayNilMap(val.columns, c => this.selectionColumn(c)); const where = val.where && this.expr(val.where); const groupBy = arrayNilMap(val.groupBy, c => this.expr(c)); const having = val.having && this.expr(val.having); const orderBy = this.orderBy(val.orderBy); const limit = assignChanged(val.limit, { limit: this.expr((_a = val.limit) === null || _a === void 0 ? void 0 : _a.limit), offset: this.expr((_b = val.limit) === null || _b === void 0 ? void 0 : _b.offset), }); return assignChanged(val, { from, columns, where, groupBy, having, orderBy, limit, }); } orderBy(orderBy) { return arrayNilMap(orderBy, c => { const by = this.expr(c.by); if (!by) { return null; } if (by === c.by) { return c; } return { ...c, by, }; }); } union(val) { const left = this.select(val.left); const right = this.select(val.right); if (!left || !right) { return left !== null && left !== void 0 ? left : right; } return assignChanged(val, { left, right }); } with(val) { const bind = arrayNilMap(val.bind, s => { const statement = this.statement(s.statement); return withAccepts(statement) ? assignChanged(s, { statement }) : null; }); // no bindngs if (!bind) { return null; } const _in = this.statement(val.in); if (!withAccepts(_in)) { return null; } return assignChanged(val, { bind, in: _in, }); } withRecursive(val) { const statement = this.union(val.bind); if (!statement) { return null; } // 'with recursive' only accepts unions if (statement.type !== 'union' && statement.type !== 'union all') { return null; } const _in = this.statement(val.in); if (!withAccepts(_in)) { return null; } return assignChanged(val, { bind: statement, in: _in, }); } from(from) { switch (from.type) { case 'table': return this.fromTable(from); case 'statement': return this.fromStatement(from); case 'call': return this.fromCall(from); default: throw utils_1.NotSupported.never(from); } } fromCall(from) { const call = this.call(from); if (!call || call.type !== 'call') { return null; } return assignChanged(from, call); } fromStatement(from) { const statement = this.select(from.statement); if (!statement) { return null; // nothing to select from } const join = from.join && this.join(from.join); return assignChanged(from, { statement, join, }); } values(from) { const values = arrayNilMap(from.values, x => arrayNilMap(x, y => this.expr(y))); if (!(values === null || values === void 0 ? void 0 : values.length)) { return null; // nothing to select from } return assignChanged(from, { values, }); } join(join) { const on = join.on && this.expr(join.on); if (!on && !join.using) { return join; } return assignChanged(join, { on, }); } fromTable(from) { const nfrom = this.tableRef(from.name); if (!nfrom) { return null; // nothing to select from } const join = from.join && this.join(from.join); return assignChanged(from, { name: nfrom, join, }); } selectionColumn(val) { const expr = this.expr(val.expr); if (!expr) { return null; // not selected anymore } return assignChanged(val, { expr, }); } // ========================================= // ============== EXPRESSIONS ============== // ========================================= expr(val) { if (!val) { return val; } switch (val.type) { case 'binary': return this.binary(val); case 'unary': return this.unary(val); case 'ref': return this.ref(val); case 'string': case 'numeric': case 'integer': case 'boolean': case 'constant': case 'null': return this.constant(val); case 'list': case 'array': return this.array(val); case 'array select': return this.arraySelect(val); case 'call': return this.call(val); case 'cast': return this.cast(val); case 'case': return this.case(val); case 'member': return this.member(val); case 'arrayIndex': return this.arrayIndex(val); case 'ternary': return this.ternary(val); case 'select': case 'union': case 'union all': case 'with': case 'with recursive': return this.select(val); case 'keyword': return this.valueKeyword(val); case 'parameter': return this.parameter(val); case 'extract': return this.extract(val); case 'overlay': return this.callOverlay(val); case 'substring': return this.callSubstring(val); case 'values': return this.values(val); case 'default': return this.default(val); default: throw utils_1.NotSupported.never(val); } } arraySelect(val) { const select = this.select(val.select); if (!select) { return null; } return assignChanged(val, { select }); } extract(st) { const from = this.expr(st.from); if (!from) { return null; } return assignChanged(st, { from }); } valueKeyword(val) { return val; } ternary(val) { const value = this.expr(val.value); const lo = this.expr(val.lo); const hi = this.expr(val.hi); if (!value || !lo || !hi) { return null; // missing a branch } return assignChanged(val, { value, lo, hi, }); } parameter(st) { return st; } arrayIndex(val) { const array = this.expr(val.array); const index = this.expr(val.index); if (!array || !index) { return null; } return assignChanged(val, { array, index, }); } member(val) { const operand = this.expr(val.operand); if (!operand) { return null; } return assignChanged(val, { operand, }); } case(val) { const value = val.value && this.expr(val.value); const whens = arrayNilMap(val.whens, w => { const when = this.expr(w.when); const value = this.expr(w.value); if (!when || !value) { return null; } return assignChanged(w, { value, when, }); }); if (!(whens === null || whens === void 0 ? void 0 : whens.length)) { return null; // no case } const els = val.else && this.expr(val.else); return assignChanged(val, { value, whens, else: els, }); } cast(val) { const operand = this.expr(val.operand); if (!operand) { return null; } return assignChanged(val, { operand, }); } call(val) { var _a; const args = arrayNilMap(val.args, a => this.expr(a)); if (!args) { return null; } const orderBy = this.orderBy(val.orderBy); const filter = this.expr(val.filter); const withinGroupList = val.withinGroup ? [val.withinGroup] : undefined; const withinGroup = (_a = this.orderBy(withinGroupList)) === null || _a === void 0 ? void 0 : _a[0]; return assignChanged(val, { args, orderBy, filter, withinGroup, }); } callSubstring(val) { return assignChanged(val, { value: this.expr(val.value), from: this.expr(val.from), for: this.expr(val.for), }); } callOverlay(val) { return assignChanged(val, { value: this.expr(val.value), placing: this.expr(val.placing), from: this.expr(val.from), for: this.expr(val.for), }); } array(val) { const expressions = arrayNilMap(val.expressions, a => this.expr(a)); if (!expressions) { return null; } return assignChanged(val, { expressions, }); } constant(value) { return value; } default(value) { return value; } /** Called when a reference is used */ ref(val) { return val; } unary(val) { const operand = this.expr(val.operand); if (!operand) { return null; } return assignChanged(val, { operand, }); } binary(val) { const left = this.expr(val.left); const right = this.expr(val.right); if (!left || !right) { return null; } return assignChanged(val, { left, right, }); } } exports.AstDefaultMapper = AstDefaultMapper; // ====== auto implement the replace mechanism const proto = AstDefaultMapper.prototype; for (const k of Object.getOwnPropertyNames(proto)) { const orig = proto[k]; if (k === 'constructor' || k === 'super' || typeof orig !== 'function') { continue; } Object.defineProperty(proto, k, { configurable: false, get() { return function (...args) { var _a; if (this.skipNext) { this.skipNext = false; return orig.apply(this, args); } const impl = (_a = this.wrapped) === null || _a === void 0 ? void 0 : _a[k]; if (!impl) { return orig.apply(this, args); } return impl.apply(this.wrapped, args); }; } }); } // ====== auto implement the skip mechanism class SkipModifier extends AstDefaultMapper { constructor(parent) { super(); this.parent = parent; } } for (const k of Object.getOwnPropertyNames(proto)) { const orig = proto[k]; if (k === 'constructor' || k === 'super' || typeof orig !== 'function') { continue; } Object.defineProperty(SkipModifier.prototype, k, { configurable: false, get() { return function (...args) { this.parent.skipNext = true; return orig.apply(this.parent, args); }; } }); } /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.sqlKeywords = void 0; // https://www.postgresql.org/docs/current/sql-keywords-appendix.html // $('table.table').children('tbody').children().toArray().filter(x => { const txt = $($(x).children()[1]).text(); return txt.includes('reserved') && !txt.includes('non-reserved')}).map(x => $($(x).children()[0]).text()) exports.sqlKeywords = [ "ALL", "ANALYSE", "ANALYZE", "AND", "ANY", "ARRAY", "AS", "ASC", "ASYMMETRIC", "AUTHORIZATION", "BINARY", "BOTH", "CASE", "CAST", "CHECK", "COLLATE", "COLLATION", "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" // added manually , "PRECISION" ]; /***/ }), /* 4 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.intervalToString = exports.normalizeInterval = exports.buildInterval = void 0; const types = [ ['years', 12], ['months', 30], ['days', 24], ['hours', 60], ['minutes', 60], ['seconds', 1000], ['milliseconds', 0], ]; function* unwrap(k) { if (typeof k[1] === 'number') { yield k; } else { for (const v of k) { yield* unwrap(v); } } } function buildInterval(orig, vals) { var _a; const ret = {}; if (vals === 'invalid') { throw new Error(`invalid input syntax for type interval: "${orig}"`); } for (const [k, v] of unwrap(vals)) { ret[k] = ((_a = ret[k]) !== null && _a !== void 0 ? _a : 0) + v; } return ret; } exports.buildInterval = buildInterval; /** Returns a normalized copy of the given interval */ function normalizeInterval(value) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; const ret = { ...value }; // trim non-integers for (let i = 0; i < types.length; i++) { const [k, mul] = types[i]; const v = (_a = ret[k]) !== null && _a !== void 0 ? _a : 0; const int = v >= 0 ? Math.floor(v) : Math.ceil(v); if (!v || int === v) { continue; } const nk = (_b = types[i + 1]) === null || _b === void 0 ? void 0 : _b[0]; if (nk) { ret[nk] = ((_c = ret[nk]) !== null && _c !== void 0 ? _c : 0) + mul * (v - int); } ret[k] = int; } if (ret.months || ret.years) { const m = ((_d = ret.months) !== null && _d !== void 0 ? _d : 0) + ((_e = ret.years) !== null && _e !== void 0 ? _e : 0) * 12; ret.months = m % 12; ret.years = (m - ret.months) / 12; } // normalize time let t = ((_f = ret.hours) !== null && _f !== void 0 ? _f : 0) * 3600 + ((_g = ret.minutes) !== null && _g !== void 0 ? _g : 0) * 60 + ((_h = ret.seconds) !== null && _h !== void 0 ? _h : 0) + ((_j = ret.milliseconds) !== null && _j !== void 0 ? _j : 0) / 1000; let sign = 1; if (t < 0) { sign = -1; t = -t; } if (t >= 3600) { ret.hours = sign * Math.floor(t / 3600); t -= sign * ret.hours * 3600; } else { delete ret.hours; } if (t >= 60) { ret.minutes = sign * Math.floor(t / 60); t -= sign * ret.minutes * 60; } else { delete ret.minutes; } if (t > 0) { ret.seconds = sign * Math.floor(t); t -= sign * ret.seconds; } else { delete ret.seconds; } if (t > 0) { ret.milliseconds = sign * Math.round(t * 1000); } else { delete ret.milliseconds; } // trim zeros. for (const [k] of types) { if (!ret[k]) { delete ret[k]; } } return ret; } exports.normalizeInterval = normalizeInterval; /** Interval value to postgres string representation */ function intervalToString(value) { var _a, _b, _c; value = normalizeInterval(value); const ret = []; if (value.years) { ret.push(value.years === 1 ? '1 year' : value.years