UNPKG

pg-deparser

Version:
1,615 lines (1,313 loc) 128 kB
"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;