pg-deparser
Version:
PostgreSQL AST Deparser
1,615 lines (1,313 loc) • 128 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
var _lodash = _interopRequireDefault(require("lodash"));
var _util = require("util");
var _pgsqlEnums = require("pgsql-enums");
var _preparse = require("./preparse");
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
var TAB_CHAR = '\t';
var NEWLINE_CHAR = '\n';
var isEmptyObject = function isEmptyObject(obj) {
return !obj || (0, _typeof2["default"])(obj) === 'object' && !Object.keys(obj).length;
};
var dotty = require('dotty');
var fail = function fail(type, node) {
throw new Error((0, _util.format)('Unhandled %s node: %s', type, JSON.stringify(node)));
}; // select word from pg_get_keywords() where catcode = 'R';
var RESERVED_WORDS = ['all', 'analyse', 'analyze', 'and', 'any', 'array', 'as', 'asc', 'asymmetric', 'both', 'case', 'cast', 'check', 'collate', 'column', 'constraint', 'create', 'current_catalog', 'current_date', 'current_role', 'current_time', 'current_timestamp', 'current_user', 'default', 'deferrable', 'desc', 'distinct', 'do', 'else', 'end', 'except', 'false', 'fetch', 'for', 'foreign', 'from', 'grant', 'group', 'having', 'in', 'initially', 'intersect', 'into', 'lateral', 'leading', 'limit', 'localtime', 'localtimestamp', 'not', 'null', 'offset', 'on', 'only', 'or', 'order', 'placing', 'primary', 'references', 'returning', 'select', 'session_user', 'some', 'symmetric', 'table', 'then', 'to', 'trailing', 'true', 'union', 'unique', 'user', 'using', 'variadic', 'when', 'where', 'window', 'with']; // https://github.com/pganalyze/libpg_query/blob/b2790f8140721ff7f047167ecd7d44267b0a3880/src/postgres/include/storage/lockdefs.h
var LOCK_MODES = {
1: 'ACCESS SHARE',
2: 'ROW SHARE',
3: 'ROW EXCLUSIVE',
4: 'SHARE UPDATE EXCLUSIVE',
5: 'SHARE',
6: 'SHARE ROW',
7: 'EXCLUSIVE',
8: 'ACCESS EXCLUSIVE'
};
var isReserved = function isReserved(value) {
return RESERVED_WORDS.includes(value.toLowerCase());
}; // usually the AST lowercases all the things, so if we
// have both, the author most likely used double quotes
var needsQuotes = function needsQuotes(value) {
return value.match(/[a-z]+[\W\w]*[A-Z]+|[A-Z]+[\W\w]*[a-z]+/) || value.match(/\W/) || isReserved(value);
};
var keys = _lodash["default"].keys;
var compact = function compact(o) {
return _lodash["default"].filter(_lodash["default"].compact(o), function (p) {
if (p == null) {
return false;
}
return p.toString().length;
});
};
var parens = function parens(string) {
return '(' + string + ')';
};
var indent = function indent(text) {
var count = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return text;
};
var Deparser = /*#__PURE__*/function () {
function Deparser(tree) {
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
(0, _classCallCheck2["default"])(this, Deparser);
this.tree = (0, _preparse.preparse)(tree);
if (opts.hasOwnProperty('newline')) {
NEWLINE_CHAR = opts.newline;
}
if (opts.hasOwnProperty('tab')) {
TAB_CHAR = opts.tab;
}
if (!_lodash["default"].isArray(this.tree)) this.tree = [this.tree];
}
(0, _createClass2["default"])(Deparser, [{
key: "deparseQuery",
value: function deparseQuery() {
var _this = this;
return this.tree.map(function (node) {
return _this.deparse(node);
}).join(NEWLINE_CHAR + NEWLINE_CHAR);
}
}, {
key: "deparseNodes",
value: function deparseNodes(nodes, context) {
var _this2 = this;
return nodes.map(function (node) {
return _lodash["default"].isArray(node) ? _this2.list(node, ', ', '', context) : _this2.deparse(node, context);
});
}
}, {
key: "list",
value: function list(nodes) {
var separator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ', ';
var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
var context = arguments.length > 3 ? arguments[3] : undefined;
if (!nodes) {
return '';
}
return this.deparseNodes(nodes, context).map(function (l) {
return "".concat(prefix).concat(l);
}).join(separator);
}
}, {
key: "listQuotes",
value: function listQuotes(nodes) {
var _this3 = this;
var separator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ', ';
return this.list(nodes, separator).split(separator).map(function (a) {
return _this3.quote(a.trim());
}).join(separator);
}
}, {
key: "quote",
value: function quote(value) {
var _this4 = this;
if (value == null) {
return null;
}
if (_lodash["default"].isArray(value)) {
return value.map(function (o) {
return _this4.quote(o);
});
}
if (needsQuotes(value)) {
return '"' + value + '"';
}
return value;
} // SELECT encode(E'''123\\000\\001', 'base64')
}, {
key: "escape",
value: function escape(literal) {
return "'" + literal.replace(/'/g, "''") + "'";
}
}, {
key: "getPgCatalogTypeName",
value: function getPgCatalogTypeName(typeName, size) {
switch (typeName) {
case 'bpchar':
if (size != null) {
return 'char';
} // return `pg_catalog.bpchar` below so that the following is symmetric
// SELECT char 'c' = char 'c' AS true
return 'pg_catalog.bpchar';
case 'varchar':
return 'varchar';
case 'numeric':
return 'numeric';
case 'bool':
return 'boolean';
case 'int2':
return 'smallint';
case 'int4':
return 'int';
case 'int8':
return 'bigint';
case 'real':
return 'pg_catalog.float4';
case 'time':
return 'time';
case 'timestamp':
return 'timestamp';
case 'interval':
return 'interval';
case 'bit':
return 'bit';
default:
return 'pg_catalog.' + typeName;
}
}
}, {
key: "type",
value: function type(names, args) {
var _this5 = this;
var _names$map = names.map(function (name) {
return _this5.deparse(name);
}),
_names$map2 = (0, _slicedToArray2["default"])(_names$map, 2),
catalog = _names$map2[0],
type = _names$map2[1];
var mods = function mods(name, size) {
if (size != null) {
return name + '(' + size + ')';
}
return name;
}; // handle the special "char" (in quotes) type
if (catalog === 'char' && !type) {
return mods('"char"', args);
}
if (catalog === 'pg_catalog' && type === 'char') {
return mods('pg_catalog."char"', args);
}
if (catalog !== 'pg_catalog') {
return mods(this.listQuotes(names, '.'), args);
}
var res = this.getPgCatalogTypeName(type, args);
return mods(res, args);
}
}, {
key: "deparse",
value: function deparse(item, context) {
if (item == null) {
return null;
}
if (_lodash["default"].isNumber(item)) {
return item;
}
var type = keys(item)[0];
var node = _lodash["default"].values(item)[0];
if (this[type] == null) {
throw new Error(type + ' is not implemented: ' + JSON.stringify(node));
}
return this[type](node, context);
}
}, {
key: 'RawStmt',
value: function RawStmt(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (node.stmt_len) {
return this.deparse(node.stmt, context) + ';';
}
return this.deparse(node.stmt, context);
}
}, {
key: 'RuleStmt',
value: function RuleStmt(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
output.push('CREATE');
output.push('RULE');
if (node.rulename === '_RETURN') {
// special rules
output.push('"_RETURN"');
} else {
output.push(node.rulename);
}
output.push('AS');
output.push('ON');
switch (node.event) {
case 'CMD_SELECT':
output.push('SELECT');
break;
case 'CMD_UPDATE':
output.push('UPDATE');
break;
case 'CMD_INSERT':
output.push('INSERT');
break;
case 'CMD_DELETE':
output.push('DELETE');
break;
default:
throw new Error('event type not yet implemented for RuleStmt');
}
output.push('TO');
output.push(this.RangeVar(node.relation, context));
if (node.instead) {
output.push('DO');
output.push('INSTEAD');
}
if (node.whereClause) {
output.push('WHERE');
output.push(this.deparse(node.whereClause, context));
output.push('DO');
}
if (!node.actions || !node.actions.length) {
output.push('NOTHING');
} else {
// TODO how do multiple actions happen?
output.push(this.deparse(node.actions[0], context));
}
return output.join(' ');
}
}, {
key: 'A_Expr',
value: function A_Expr(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
switch (node.kind) {
case 'AEXPR_OP':
{
var operator;
if (node.lexpr) {
// PARENS
if (dotty.exists(node, 'lexpr.A_Expr')) {
output.push(parens(this.deparse(node.lexpr, context)));
} else {
output.push(this.deparse(node.lexpr, context));
}
}
if (node.name.length > 1) {
var schema = this.deparse(node.name[0], context);
operator = this.deparse(node.name[1], context);
output.push("OPERATOR(".concat(schema, ".").concat(operator, ")"));
} else {
operator = this.deparse(node.name[0], context);
output.push(operator);
}
if (node.rexpr) {
// PARENS
if (dotty.exists(node, 'rexpr.A_Expr')) {
output.push(parens(this.deparse(node.rexpr, context)));
} else {
output.push(this.deparse(node.rexpr, context));
}
}
if (output.length === 2) {
return output.join('');
}
if (['->', '->>'].includes(operator)) {
return output.join('');
}
return output.join(' ');
}
case 'AEXPR_OP_ANY':
/* scalar op ANY (array) */
output.push(this.deparse(node.lexpr, context));
output.push((0, _util.format)('ANY (%s)', this.deparse(node.rexpr, context)));
return output.join(" ".concat(this.deparse(node.name[0], context), " "));
case 'AEXPR_OP_ALL':
/* scalar op ALL (array) */
output.push(this.deparse(node.lexpr, context));
output.push((0, _util.format)('ALL (%s)', this.deparse(node.rexpr, context)));
return output.join(" ".concat(this.deparse(node.name[0], context), " "));
case 'AEXPR_DISTINCT':
/* IS DISTINCT FROM - name must be "=" */
return (0, _util.format)('%s IS DISTINCT FROM %s', this.deparse(node.lexpr, context), this.deparse(node.rexpr, context));
case 'AEXPR_NOT_DISTINCT':
/* IS NOT DISTINCT FROM - name must be "=" */
return (0, _util.format)('%s IS NOT DISTINCT FROM %s', this.deparse(node.lexpr, context), this.deparse(node.rexpr, context));
case 'AEXPR_NULLIF':
/* NULLIF - name must be "=" */
return (0, _util.format)('NULLIF(%s, %s)', this.deparse(node.lexpr, context), this.deparse(node.rexpr, context));
case 'AEXPR_OF':
{
/* IS [NOT] OF - name must be "=" or "<>" */
var op = node.name[0].String.str === '=' ? 'IS OF' : 'IS NOT OF';
return (0, _util.format)('%s %s (%s)', this.deparse(node.lexpr, context), op, this.list(node.rexpr, ', ', '', context));
}
case 'AEXPR_IN':
{
/* [NOT] IN - name must be "=" or "<>" */
var _operator = node.name[0].String.str === '=' ? 'IN' : 'NOT IN';
return (0, _util.format)('%s %s (%s)', this.deparse(node.lexpr, context), _operator, this.list(node.rexpr, ', ', '', context));
}
case 'AEXPR_LIKE':
/* [NOT] LIKE - name must be "~~" or "!~~" */
output.push(this.deparse(node.lexpr, context));
if (node.name[0].String.str === '!~~') {
output.push((0, _util.format)('NOT LIKE (%s)', this.deparse(node.rexpr, context)));
} else {
output.push((0, _util.format)('LIKE (%s)', this.deparse(node.rexpr, context)));
}
return output.join(' ');
case 'AEXPR_ILIKE':
/* [NOT] ILIKE - name must be "~~*" or "!~~*" */
output.push(this.deparse(node.lexpr, context));
if (node.name[0].String.str === '!~~*') {
output.push((0, _util.format)('NOT ILIKE (%s)', this.deparse(node.rexpr, context)));
} else {
output.push((0, _util.format)('ILIKE (%s)', this.deparse(node.rexpr, context)));
}
return output.join(' ');
case 'AEXPR_SIMILAR':
// SIMILAR TO emits a similar_escape FuncCall node with the first argument
output.push(this.deparse(node.lexpr, context));
if (node.name[0].String.str === '~') {
if (node.rexpr.FuncCall.args.length > 1) {
output.push((0, _util.format)('SIMILAR TO %s ESCAPE %s', this.deparse(node.rexpr.FuncCall.args[0], context), this.deparse(node.rexpr.FuncCall.args[1], context)));
} else {
output.push((0, _util.format)('SIMILAR TO %s', this.deparse(node.rexpr.FuncCall.args[0], context)));
}
} else {
if (node.rexpr.FuncCall.args.length > 1) {
output.push((0, _util.format)('NOT SIMILAR TO %s ESCAPE %s', this.deparse(node.rexpr.FuncCall.args[0], context), this.deparse(node.rexpr.FuncCall.args[1], context)));
} else {
output.push((0, _util.format)('NOT SIMILAR TO %s', this.deparse(node.rexpr.FuncCall.args[0], context)));
}
}
return output.join(' ');
case 'AEXPR_BETWEEN':
output.push(this.deparse(node.lexpr, context));
output.push((0, _util.format)('BETWEEN %s AND %s', this.deparse(node.rexpr[0], context), this.deparse(node.rexpr[1], context)));
return output.join(' ');
case 'AEXPR_NOT_BETWEEN':
output.push(this.deparse(node.lexpr, context));
output.push((0, _util.format)('NOT BETWEEN %s AND %s', this.deparse(node.rexpr[0], context), this.deparse(node.rexpr[1], context)));
return output.join(' ');
case 'AEXPR_BETWEEN_SYM':
output.push(this.deparse(node.lexpr, context));
output.push((0, _util.format)('BETWEEN SYMMETRIC %s AND %s', this.deparse(node.rexpr[0], context), this.deparse(node.rexpr[1], context)));
return output.join(' ');
case 'AEXPR_NOT_BETWEEN_SYM':
output.push(this.deparse(node.lexpr, context));
output.push((0, _util.format)('NOT BETWEEN SYMMETRIC %s AND %s', this.deparse(node.rexpr[0], context), this.deparse(node.rexpr[1], context)));
return output.join(' ');
// case 15:
// AEXPR_PAREN
default:
return fail('A_Expr', node);
}
}
}, {
key: 'Alias',
value: function Alias(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var name = node.aliasname;
var output = ['AS'];
if (node.colnames) {
output.push(this.quote(name) + parens(this.listQuotes(node.colnames)));
} else {
output.push(this.quote(name));
}
return output.join(' ');
}
}, {
key: 'A_ArrayExpr',
value: function A_ArrayExpr(node) {
return (0, _util.format)('ARRAY[%s]', this.list(node.elements));
}
}, {
key: 'A_Const',
value: function A_Const(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (node.val.String) {
return this.escape(this.deparse(node.val, context));
}
return this.deparse(node.val, context);
}
}, {
key: 'A_Indices',
value: function A_Indices(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (node.lidx) {
return (0, _util.format)('[%s:%s]', this.deparse(node.lidx, context), this.deparse(node.uidx, context));
}
return (0, _util.format)('[%s]', this.deparse(node.uidx, context));
}
}, {
key: 'A_Indirection',
value: function A_Indirection(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = ["(".concat(this.deparse(node.arg, context), ")")]; // TODO(zhm) figure out the actual rules for when a '.' is needed
//
// select a.b[0] from a;
// select (select row(1)).*
// select c2[2].f2 from comptable
// select c2.a[2].f2[1].f3[0].a1 from comptable
for (var i = 0; i < node.indirection.length; i++) {
var subnode = node.indirection[i];
if (subnode.String || subnode.A_Star) {
var value = subnode.A_Star ? '*' : this.quote(subnode.String.str);
output.push(".".concat(value));
} else {
output.push(this.deparse(subnode, context));
}
}
return output.join('');
}
}, {
key: 'A_Star',
value: function A_Star(node) {
return '*';
}
}, {
key: 'BitString',
value: function BitString(node) {
var prefix = node.str[0];
return "".concat(prefix, "'").concat(node.str.substring(1), "'");
}
}, {
key: 'BoolExpr',
value: function BoolExpr(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var fmt_str = '%s';
if (context.bool) {
fmt_str = '(%s)';
}
var ctx = _objectSpread({}, context);
ctx.bool = true;
switch (node.boolop) {
case 'AND_EXPR':
return (0, _util.format)(fmt_str, this.list(node.args, ' AND ', '', ctx));
case 'OR_EXPR':
return (0, _util.format)(fmt_str, this.list(node.args, ' OR ', '', ctx));
case 'NOT_EXPR':
return (0, _util.format)('NOT (%s)', this.deparse(node.args[0], context));
default:
return fail('BoolExpr', node);
}
}
}, {
key: 'BooleanTest',
value: function BooleanTest(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
var ctx = _objectSpread({}, context);
ctx.bool = true;
output.push(this.deparse(node.arg, ctx));
switch (node.booltesttype) {
case 'IS_TRUE':
output.push('IS TRUE');
break;
case 'IS_NOT_TRUE':
output.push('IS NOT TRUE');
break;
case 'IS_FALSE':
output.push('IS FALSE');
break;
case 'IS_NOT_FALSE':
output.push('IS NOT FALSE');
break;
case 'IS_UNKNOWN':
output.push('IS UNKNOWN');
break;
case 'IS_NOT_UNKNOWN':
output.push('IS NOT UNKNOWN');
break;
}
return output.join(' ');
}
}, {
key: 'CaseExpr',
value: function CaseExpr(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = ['CASE'];
if (node.arg) {
output.push(this.deparse(node.arg, context));
}
for (var i = 0; i < node.args.length; i++) {
output.push(this.deparse(node.args[i], context));
}
if (node.defresult) {
output.push('ELSE');
output.push(this.deparse(node.defresult, context));
}
output.push('END');
return output.join(' ');
}
}, {
key: 'CoalesceExpr',
value: function CoalesceExpr(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return (0, _util.format)('COALESCE(%s)', this.list(node.args, ', ', '', context));
}
}, {
key: 'CollateClause',
value: function CollateClause(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
if (node.arg) {
output.push(this.deparse(node.arg, context));
}
output.push('COLLATE');
if (node.collname) {
output.push(this.quote(this.deparseNodes(node.collname, context)));
}
return output.join(' ');
}
}, {
key: 'CompositeTypeStmt',
value: function CompositeTypeStmt(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
output.push('CREATE TYPE');
output.push(this.RangeVar(node.typevar, context));
output.push('AS');
output.push('(');
output.push(this.list(node.coldeflist, ",".concat(NEWLINE_CHAR), TAB_CHAR, context));
output.push(')');
return output.join(' ');
}
}, {
key: 'RenameStmt',
value: function RenameStmt(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
if (node.renameType === 'OBJECT_FUNCTION' || node.renameType === 'OBJECT_FOREIGN_TABLE' || node.renameType === 'OBJECT_FDW' || node.renameType === 'OBJECT_FOREIGN_SERVER') {
output.push('ALTER');
output.push((0, _pgsqlEnums.objtypeName)(node.renameType));
if (node.missing_ok) {
output.push('IF EXISTS');
}
output.push(this.deparse(node.object, context));
output.push('RENAME');
output.push('TO');
output.push(this.quote(node.newname));
} else if (node.renameType === 'OBJECT_ATTRIBUTE') {
output.push('ALTER');
output.push((0, _pgsqlEnums.objtypeName)(node.relationType));
if (node.missing_ok) {
output.push('IF EXISTS');
}
output.push(this.RangeVar(node.relation, context));
output.push('RENAME');
output.push((0, _pgsqlEnums.objtypeName)(node.renameType));
output.push(this.quote(node.subname));
output.push('TO');
output.push(this.quote(node.newname));
} else if (node.renameType === 'OBJECT_DOMAIN' || node.renameType === 'OBJECT_TYPE') {
output.push('ALTER');
output.push((0, _pgsqlEnums.objtypeName)(node.renameType));
if (node.missing_ok) {
output.push('IF EXISTS');
}
var typObj = {
TypeName: {
names: node.object
}
};
output.push(this.deparse(typObj, context));
output.push('RENAME');
output.push('TO');
output.push(this.quote(node.newname));
} else if (node.renameType === 'OBJECT_SCHEMA') {
output.push('ALTER');
output.push((0, _pgsqlEnums.objtypeName)(node.renameType));
if (node.missing_ok) {
output.push('IF EXISTS');
}
output.push(this.quote(node.subname));
output.push('RENAME');
output.push('TO');
output.push(this.quote(node.newname));
} else if (node.renameType === 'OBJECT_DOMCONSTRAINT') {
output.push('ALTER');
output.push('DOMAIN');
if (node.missing_ok) {
output.push('IF EXISTS');
}
var _typObj = {
TypeName: {
names: node.object
}
};
output.push(this.deparse(_typObj, context));
output.push('RENAME CONSTRAINT');
output.push(this.quote(node.subname));
output.push('TO');
output.push(this.quote(node.newname));
} else {
output.push('ALTER');
output.push('TABLE');
if (node.missing_ok) {
output.push('IF EXISTS');
}
output.push(this.RangeVar(node.relation, context));
output.push('RENAME');
output.push(this.quote(node.subname));
output.push('TO');
output.push(this.quote(node.newname));
}
if (node.behavior === 'DROP_CASCADE') {
output.push('CASCADE');
}
return output.join(' ');
}
}, {
key: 'AlterOwnerStmt',
value: function AlterOwnerStmt(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
output.push('ALTER');
output.push((0, _pgsqlEnums.objtypeName)(node.objectType));
if (Array.isArray(node.object)) {
output.push(this.listQuotes(node.object, '.'));
} else {
output.push(this.deparse(node.object, context));
}
output.push('OWNER TO');
output.push(this.RoleSpec(node.newowner, context));
return output.join(' ');
}
}, {
key: 'AlterObjectSchemaStmt',
value: function AlterObjectSchemaStmt(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
if (node.objectType === 'OBJECT_TABLE') {
output.push('ALTER');
output.push((0, _pgsqlEnums.objtypeName)(node.objectType));
if (node.missing_ok) {
output.push('IF EXISTS');
}
output.push(this.RangeVar(node.relation, context));
output.push('SET SCHEMA');
output.push(this.quote(node.newschema));
} else {
output.push('ALTER');
output.push((0, _pgsqlEnums.objtypeName)(node.objectType));
if (node.missing_ok) {
output.push('IF EXISTS');
}
if (Array.isArray(node.object)) {
output.push(this.listQuotes(node.object, '.'));
} else {
output.push(this.deparse(node.object, context));
}
output.push('SET SCHEMA');
output.push(this.quote(node.newschema));
}
return output.join(' ');
}
}, {
key: 'ColumnDef',
value: function ColumnDef(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [this.quote(node.colname)];
output.push(this.TypeName(node.typeName, context));
if (node.raw_default) {
output.push('USING');
output.push(this.deparse(node.raw_default, context));
}
if (node.constraints) {
output.push(this.list(node.constraints, ' ', '', context));
}
if (node.collClause) {
output.push('COLLATE');
var str = dotty.get(node, 'collClause.collname.0.String.str');
output.push(this.quote(str));
}
return _lodash["default"].compact(output).join(' ');
}
}, {
key: 'SQLValueFunction',
value: function SQLValueFunction(node) {
if (node.op === 'SVFOP_CURRENT_DATE') {
return 'CURRENT_DATE';
}
if (node.op === 'SVFOP_CURRENT_TIMESTAMP') {
return 'CURRENT_TIMESTAMP';
}
if (node.op === 'SVFOP_CURRENT_USER') {
return 'CURRENT_USER';
}
if (node.op === 'SVFOP_SESSION_USER') {
return 'SESSION_USER';
}
throw new Error("op=".concat(node.op, " SQLValueFunction not implemented"));
}
}, {
key: 'ColumnRef',
value: function ColumnRef(node) {
var _this6 = this;
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var KEYWORDS = ['old', 'new'];
var fields = node.fields.map(function (field) {
if (field.String) {
var value = _this6.deparse(field, context);
if (context === 'trigger' && KEYWORDS.includes(value.toLowerCase())) {
return value.toUpperCase();
}
return _this6.quote(value);
}
return _this6.deparse(field, context);
});
return fields.join('.');
}
}, {
key: 'CommentStmt',
value: function CommentStmt(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
output.push('COMMENT');
output.push('ON');
output.push((0, _pgsqlEnums.objtypeName)(node.objtype));
if (node.objtype === 'OBJECT_CAST') {
output.push('(');
output.push(this.deparse(node.object[0], context));
output.push('AS');
output.push(this.deparse(node.object[1], context));
output.push(')');
} else if (node.objtype === 'OBJECT_DOMCONSTRAINT') {
output.push(this.deparse(node.object[1], context));
output.push('ON');
output.push('DOMAIN');
output.push(this.deparse(node.object[0], context));
} else if (node.objtype === 'OBJECT_OPCLASS' || node.objtype === 'OBJECT_OPFAMILY') {
output.push(this.deparse(node.object[1], context));
output.push('USING');
output.push(this.deparse(node.object[0], context));
} else if (node.objtype === 'OBJECT_OPERATOR') {
output.push(this.deparse(node.object, 'noquotes'));
} else if (node.objtype === 'OBJECT_POLICY') {
output.push(this.deparse(node.object[1], context));
output.push('ON');
output.push(this.deparse(node.object[0], context));
} else if (node.objtype === 'OBJECT_ROLE') {
output.push(this.deparse(node.object, context));
} else if (node.objtype === 'OBJECT_RULE') {
output.push(this.deparse(node.object[1], context));
output.push('ON');
output.push(this.deparse(node.object[0], context));
} else if (node.objtype === 'OBJECT_TABCONSTRAINT') {
if (node.object.length === 3) {
output.push(this.deparse(node.object[2], context));
output.push('ON');
output.push(this.deparse(node.object[0], context) + '.' + this.deparse(node.object[1], context));
} else {
output.push(this.deparse(node.object[1], context));
output.push('ON');
output.push(this.deparse(node.object[0], context));
}
} else if (node.objtype === 'OBJECT_TRANSFORM') {
output.push('FOR');
output.push(this.deparse(node.object[0], context));
output.push('LANGUAGE');
output.push(this.deparse(node.object[1], context));
} else if (node.objtype === 'OBJECT_TRIGGER') {
output.push(this.deparse(node.object[1], context));
output.push('ON');
output.push(this.deparse(node.object[0], context));
} else {
if (node.objtype === 'OBJECT_LARGEOBJECT') {
output.push(dotty.get(node, 'object.Integer.ival'));
} else if (node.object instanceof Array) {
output.push(this.listQuotes(node.object, '.'));
} else {
output.push(this.deparse(node.object, context));
}
if (node.objargs) {
output.push('(');
output.push(this.list(node.objargs, ', ', '', context));
output.push(')');
}
}
output.push('IS');
var escapeComment = function escapeComment(str) {
return str.replace(/\\/g, '\\');
};
if (node.comment) {
if (/[^a-zA-Z0-9]/.test(node.comment)) {
// special chars we care about...
output.push("E'".concat(escapeComment(node.comment), "'"));
} else {
// find a double \\n or \\ something...
output.push("'".concat(node.comment, "'"));
}
} else {
output.push('NULL');
}
return output.join(' ');
}
}, {
key: 'CommonTableExpr',
value: function CommonTableExpr(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
output.push(node.ctename);
if (node.aliascolnames) {
output.push((0, _util.format)('(%s)', this.quote(this.deparseNodes(node.aliascolnames, context))));
}
output.push((0, _util.format)('AS (%s)', this.deparse(node.ctequery)));
return output.join(' ');
}
}, {
key: 'DefineStmt',
value: function DefineStmt(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
output.push('CREATE');
if (node.replace) {
output.push('OR REPLACE');
}
switch (node.kind) {
case 'OBJECT_AGGREGATE':
output.push('AGGREGATE');
break;
case 'OBJECT_OPERATOR':
output.push('OPERATOR');
break;
case 'OBJECT_TYPE':
output.push('TYPE');
break;
case 'OBJECT_TSPARSER':
output.push('TEXT SEARCH PARSER');
break;
case 'OBJECT_TSDICTIONARY':
output.push('TEXT SEARCH DICTIONARY');
break;
case 'OBJECT_TSTEMPLATE':
output.push('TEXT SEARCH TEMPLATE');
break;
case 'OBJECT_TSCONFIGURATION':
output.push('TEXT SEARCH CONFIGURATION');
break;
case 'OBJECT_COLLATION':
output.push('COLLATION');
break;
default:
throw new Error('DefineStmt not recognized');
}
if (node.if_not_exists) {
output.push('IF NOT EXISTS');
}
switch (node.kind) {
case 'OBJECT_AGGREGATE':
// output.push(this.deparse(node.defnames));
output.push(this.list(node.defnames, '.', '', context));
break;
case 'OBJECT_OPERATOR':
output.push(this.list(node.defnames, '.', '', context)); // output.push(this.deparse(node.defnames));
break;
case 'OBJECT_TYPE':
case 'OBJECT_TSPARSER':
case 'OBJECT_TSDICTIONARY':
case 'OBJECT_TSTEMPLATE':
case 'OBJECT_TSCONFIGURATION':
case 'OBJECT_COLLATION':
output.push(this.deparse(node.defnames));
break;
default:
throw new Error('DefineStmt not recognized');
}
if (!node.oldstyle && node.kind == 'OBJECT_AGGREGATE') {
output.push('(');
output.push("".concat(this.listQuotes(node.args[0], ',')));
output.push(')');
}
if (node.definition.length > 0) {
output.push('(');
for (var n = 0; n < node.definition.length; n++) {
var defElement = node.definition[n].DefElem;
output.push(defElement.defname);
if (defElement.arg) {
output.push('=');
output.push(this.deparse(defElement.arg));
}
if (n !== node.definition.length - 1) {
output.push(',');
}
}
output.push(')');
}
return output.join(' ');
}
}, {
key: 'DefElem',
value: function DefElem(node) {
var _this7 = this;
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (node.defname === 'transaction_isolation') {
return (0, _util.format)('ISOLATION LEVEL %s', node.arg.A_Const.val.String.str.toUpperCase());
}
if (node.defname === 'transaction_read_only') {
return node.arg.A_Const.val.Integer.ival === 0 ? 'READ WRITE' : 'READ ONLY';
}
if (node.defname === 'transaction_deferrable') {
return node.arg.A_Const.val.Integer.ival === 0 ? 'NOT DEFERRABLE' : 'DEFERRABLE';
}
if (node.defname === 'set') {
return this.deparse(node.arg, context);
}
var name = node.defname;
if (node.defnamespace) {
name = "".concat(node.defnamespace, ".").concat(node.defname);
}
if (context === 'generated' || context === 'sequence') {
switch (name) {
case 'start':
{
var start = this.deparse(node.arg, context);
return "START WITH ".concat(start);
}
case 'increment':
{
var inc = this.deparse(node.arg, context);
if (context === 'sequence') {
// we need 'simple' so it doesn't wrap negative numbers in parens
return "".concat(name, " ").concat(this.deparse(node.arg, 'simple'));
}
return "INCREMENT BY ".concat(inc);
}
case 'sequence_name':
{
return "SEQUENCE NAME ".concat(this.listQuotes(node.arg, '.'));
}
case 'cycle':
{
var on = this.deparse(node.arg, context) + '' === '1';
return on ? 'CYCLE' : 'NO CYCLE';
}
case 'minvalue':
{
var off = !node.hasOwnProperty('arg');
return off ? 'NO MINVALUE' : "".concat(name, " ").concat(this.deparse(node.arg, 'simple'));
}
case 'maxvalue':
{
var _off = !node.hasOwnProperty('arg');
return _off ? 'NO MAXVALUE' : "".concat(name, " ").concat(this.deparse(node.arg, 'simple'));
}
// alter
case 'owned_by':
{
var output = [];
node.arg.forEach(function (opt) {
output.push(_this7.quote(_this7.deparse(opt, context)));
});
return "OWNED BY ".concat(output.join('.'));
}
// alter
case 'restart':
{
if (node.arg) {
return "RESTART WITH ".concat(this.deparse(node.arg, context));
}
return "RESTART";
}
default:
if (node.arg) {
// we need 'simple' so it doesn't wrap negative numbers in parens
return "".concat(name, " ").concat(this.deparse(node.arg, 'simple'));
}
}
} else if (node.arg) {
return "".concat(name, " = ").concat(this.deparse(node.arg, context));
}
return name;
}
}, {
key: 'DoStmt',
value: function DoStmt(node) {
return "DO $$".concat(NEWLINE_CHAR, " ").concat(dotty.get(node, 'args.0.DefElem.arg.String.str').trim(), " $$");
}
}, {
key: 'Float',
value: function Float(node) {
// wrap negative numbers in parens, SELECT (-2147483648)::int4 * (-1)::int4
if (node.str[0] === '-') {
return "(".concat(node.str, ")");
}
return node.str;
}
}, {
key: 'FuncCall',
value: function FuncCall(node) {
var _this8 = this;
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
var params = [];
if (node.args) {
params = node.args.map(function (item) {
return _this8.deparse(item, context);
});
} // COUNT(*)
if (node.agg_star) {
params.push('*');
}
var name = this.list(node.funcname, '.', '', context);
var order = [];
var withinGroup = node.agg_within_group;
if (node.agg_order) {
order.push('ORDER BY');
order.push(this.list(node.agg_order, ', ', '', context));
}
var call = [];
call.push(name + '(');
if (node.agg_distinct) {
call.push('DISTINCT ');
} // prepend variadic before the last parameter
// SELECT CONCAT('|', VARIADIC ARRAY['1','2','3'])
if (node.func_variadic) {
params[params.length - 1] = 'VARIADIC ' + params[params.length - 1];
}
call.push(params.join(', '));
if (order.length && !withinGroup) {
call.push(' ');
call.push(order.join(' '));
}
call.push(')');
output.push(compact(call).join(''));
if (order.length && withinGroup) {
output.push('WITHIN GROUP');
output.push(parens(order.join(' ')));
}
if (node.agg_filter != null) {
output.push((0, _util.format)('FILTER (WHERE %s)', this.deparse(node.agg_filter, context)));
}
if (node.over != null) {
output.push((0, _util.format)('OVER %s', this.WindowDef(node.over, context)));
}
return output.join(' ');
}
}, {
key: 'GroupingFunc',
value: function GroupingFunc(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return 'GROUPING(' + this.list(node.args, ', ', '', context) + ')';
}
}, {
key: 'GroupingSet',
value: function GroupingSet(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
switch (node.kind) {
case 'GROUPING_SET_EMPTY':
return '()';
case 'GROUPING_SET_SIMPLE':
return fail('GroupingSet', node);
case 'GROUPING_SET_ROLLUP':
return 'ROLLUP (' + this.list(node.content, ', ', '', context) + ')';
case 'GROUPING_SET_CUBE':
return 'CUBE (' + this.list(node.content, ', ', '', context) + ')';
case 'GROUPING_SET_SETS':
return 'GROUPING SETS (' + this.list(node.content, ', ', '', context) + ')';
default:
return fail('GroupingSet', node);
}
}
}, {
key: 'IndexStmt',
value: function IndexStmt(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
output.push('CREATE');
if (node.unique) {
output.push('UNIQUE');
}
output.push('INDEX');
if (node.concurrent) {
output.push('CONCURRENTLY');
}
if (node.idxname) {
output.push(node.idxname);
}
output.push('ON');
output.push(this.RangeVar(node.relation, context));
if (node.accessMethod) {
var accessMethod = node.accessMethod.toUpperCase();
if (accessMethod !== 'BTREE') {
output.push('USING');
output.push(accessMethod);
}
}
if (node.indexParams) {
output.push('(');
output.push(this.list(node.indexParams, ', ', '', context));
output.push(')');
}
if (node.indexIncludingParams) {
output.push('INCLUDE (');
output.push(this.list(node.indexIncludingParams, ', ', '', context));
output.push(')');
}
if (node.whereClause) {
output.push('WHERE');
output.push(this.deparse(node.whereClause, context));
}
return output.join(' ');
}
}, {
key: 'IndexElem',
value: function IndexElem(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
if (node.name) {
output.push(node.name);
if (node.ordering === 'SORTBY_DESC') {
output.push('DESC');
} else if (node.ordering === 'SORTBY_ASC') {
output.push('ASC');
}
return output.join(' ');
}
if (node.expr) {
return this.deparse(node.expr, context);
}
return fail('IndexElem', node);
}
}, {
key: 'InsertStmt',
value: function InsertStmt(node) {
var _this9 = this;
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
output.push('INSERT INTO');
output.push(this.RangeVar(node.relation, context));
if (node.cols && node.cols.length) {
output.push('(');
output.push(this.list(node.cols, ', ', '', context));
output.push(')');
}
if (node.selectStmt) {
output.push(this.deparse(node.selectStmt, context));
} else {
output.push('DEFAULT VALUES');
}
if (node.onConflictClause) {
var clause = node.onConflictClause;
output.push('ON CONFLICT');
if (clause.infer.indexElems) {
output.push('(');
output.push(this.list(clause.infer.indexElems, ', ', '', context));
output.push(')');
} else if (clause.infer.conname) {
output.push('ON CONSTRAINT');
output.push(clause.infer.conname);
}
switch (clause.action) {
case 'ONCONFLICT_NOTHING':
output.push('DO NOTHING');
break;
case 'ONCONFLICT_UPDATE':
output.push('DO');
output.push(this.UpdateStmt(clause, context));
break;
default:
throw new Error('unhandled CONFLICT CLAUSE');
}
}
if (node.returningList) {
output.push('RETURNING');
output.push(node.returningList.map(function (returning) {
return _this9.deparse(returning.ResTarget.val, context) + (returning.ResTarget.name ? ' AS ' + _this9.quote(returning.ResTarget.name) : '');
}).join(','));
}
return output.join(' ');
}
}, {
key: 'SetToDefault',
value: function SetToDefault(node) {
return 'DEFAULT';
}
}, {
key: 'MultiAssignRef',
value: function MultiAssignRef(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
output.push(this.deparse(node.source, context));
return output.join(' ');
}
}, {
key: 'DeleteStmt',
value: function DeleteStmt(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [''];
output.push('DELETE');
output.push('FROM');
output.push(this.RangeVar(node.relation, context));
if (node.whereClause) {
output.push('WHERE');
output.push(this.deparse(node.whereClause, context));
}
return output.join(' ');
}
}, {
key: 'UpdateStmt',
value: function UpdateStmt(node) {
var _this10 = this;
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
output.push('UPDATE');
if (node.relation) {
// onConflictClause no relation..
output.push(this.RangeVar(node.relation, context));
}
output.push('SET');
if (node.targetList && node.targetList.length) {
if (node.targetList[0].ResTarget && node.targetList[0].ResTarget.val && node.targetList[0].ResTarget.val.MultiAssignRef) {
output.push('(');
output.push(node.targetList.map(function (target) {
return target.ResTarget.name;
}).join(','));
output.push(')');
output.push('=');
output.push(this.deparse(node.targetList[0].ResTarget.val, context));
} else {
output.push(node.targetList.map(function (target) {
return _this10.deparse(target, 'update');
}).join(','));
}
}
if (node.fromClause) {
output.push('FROM');
output.push(this.list(node.fromClause, ', ', '', context));
}
if (node.whereClause) {
output.push('WHERE');
output.push(this.deparse(node.whereClause, context));
}
if (node.returningList) {
output.push('RETURNING');
output.push(node.returningList.map(function (returning) {
return _this10.deparse(returning.ResTarget.val, context) + (returning.ResTarget.name ? ' AS ' + _this10.quote(returning.ResTarget.name) : '');
}).join(','));
}
return output.join(' ');
}
}, {
key: 'Integer',
value: function Integer(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (node.ival < 0 && context !== 'simple') {
return "(".concat(node.ival, ")");
}
return node.ival.toString();
}
}, {
key: 'IntoClause',
value: function IntoClause(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return this.RangeVar(node.rel, context);
}
}, {
key: 'JoinExpr',
value: function JoinExpr(node) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var output = [];
output.push(this.deparse(node.larg, context));
if (node.isNatural) {
output.push('NATURAL');
}
var join = null;