@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
JavaScript
(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