UNPKG

@abaplint/transpiler

Version:
164 lines • 7.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SelectTranspiler = void 0; const abaplint = require("@abaplint/core"); const chunk_1 = require("../chunk"); const expressions_1 = require("../expressions"); const unique_identifier_1 = require("../unique_identifier"); const sql_from_1 = require("../expressions/sql_from"); const sql_group_by_1 = require("../expressions/sql_group_by"); function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string } // TODO: currently SELECT into are always handled as CORRESPONDING class SelectTranspiler { transpile(node, traversal, targetOverride) { if (node.findDirectTokenByText("UNION") !== undefined) { return new chunk_1.Chunk(`throw new Error("SELECT UNION, not supported, transpiler, todo");`); } else if (node.findDirectTokenByText("ALL") !== undefined) { throw new Error("SelectTranspiler, UNION ALL todo"); } else if (node.findDirectTokenByText("DISTINCT") !== undefined) { throw new Error("SelectTranspiler, UNION DISTINCT todo"); } let target = "undefined"; if (targetOverride) { // SelectLoop structure uses override target = targetOverride; } else if (node.findFirstExpression(abaplint.Expressions.SQLIntoTable)) { target = traversal.traverse(node.findFirstExpression(abaplint.Expressions.Target)).getCode(); } else if (node.findFirstExpression(abaplint.Expressions.SQLIntoList)) { target = traversal.traverse(node.findFirstExpression(abaplint.Expressions.SQLIntoList)).getCode(); } else if (node.findFirstExpression(abaplint.Expressions.SQLIntoStructure)) { target = traversal.traverse(node.findFirstExpression(abaplint.Expressions.SQLIntoStructure)).getCode(); } let select = "SELECT "; const fieldList = node.findFirstExpression(abaplint.Expressions.SQLFieldList) || node.findFirstExpression(abaplint.Expressions.SQLFieldListLoop); if (fieldList === undefined) { throw new Error("SelectTranspiler, field list not found"); } select += new expressions_1.SQLFieldListTranspiler().transpile(fieldList, traversal).getCode() + " "; const from = node.findFirstExpression(abaplint.Expressions.SQLFrom); if (from) { select += new sql_from_1.SQLFromTranspiler().transpile(from, traversal).getCode(); } const { table, keys } = this.findTable(node, traversal); let where = undefined; for (const sqlCond of node.findAllExpressions(abaplint.Expressions.SQLCond)) { if (this.isWhereExpression(node, sqlCond)) { where = sqlCond; } } if (where) { select += "WHERE " + new expressions_1.SQLCondTranspiler().transpile(where, traversal, table).getCode() + " "; } const groupBy = node.findFirstExpression(abaplint.Expressions.SQLGroupBy); if (groupBy) { select += new sql_group_by_1.SQLGroupByTranspiler().transpile(groupBy, traversal).getCode() + " "; } const upTo = node.findFirstExpression(abaplint.Expressions.SQLUpTo); if (upTo) { const s = upTo.findFirstExpression(abaplint.Expressions.SimpleSource3); if (s) { select += `UP TO " + ${new expressions_1.SourceTranspiler(true).transpile(s, traversal).getCode()} + " ROWS `; } else { select += upTo.concatTokens() + " "; } } const orderBy = node.findFirstExpression(abaplint.Expressions.SQLOrderBy); if (orderBy) { select += new expressions_1.SQLOrderByTranspiler().transpile(orderBy, traversal).getCode(); } for (const d of node.findAllExpressionsRecursive(abaplint.Expressions.Dynamic)) { const chain = d.findFirstExpression(abaplint.Expressions.FieldChain); if (chain) { const code = new expressions_1.FieldChainTranspiler(true).transpile(chain, traversal).getCode(); const search = d.concatTokens(); select = select.replace(search, `" + ${code} + "`); } } const concat = node.concatTokens().toUpperCase(); if (concat.startsWith("SELECT SINGLE ")) { select += "UP TO 1 ROWS"; } let runtimeOptions = ""; const runtimeOptionsList = []; if (concat.includes(" APPENDING TABLE ") || concat.includes(" APPENDING CORRESPONDING FIELDS OF TABLE ")) { runtimeOptionsList.push(`appending: true`); } if (runtimeOptionsList.length > 0) { runtimeOptions = `, {` + runtimeOptionsList.join(", ") + `}`; } let extra = ""; if (keys.length > 0) { extra = `, primaryKey: ${JSON.stringify(keys)}`; } if (node.findFirstExpression(abaplint.Expressions.SQLForAllEntries)) { const unique = unique_identifier_1.UniqueIdentifier.get(); const unique2 = unique_identifier_1.UniqueIdentifier.get(); const fn = node.findFirstExpression(abaplint.Expressions.SQLForAllEntries)?.findDirectExpression(abaplint.Expressions.SQLSource); const faeTranspiled = new expressions_1.SQLSourceTranspiler().transpile(fn, traversal).getCode(); select = select.replace(new RegExp(" " + escapeRegExp(faeTranspiled), "g"), " " + unique); select = select.replace(unique + ".get().table_line.get()", unique + ".get()"); // there can be only one? let by = `Object.keys(${target}.getRowType().get())`; if (keys.length > 0) { by = JSON.stringify(keys); } const code = `if (${faeTranspiled}.array().length === 0) { throw new Error("FAE, todo, empty table"); } else { const ${unique2} = ${faeTranspiled}.array(); ${target}.clear(); for await (const ${unique} of ${unique2}) { await abap.statements.select(${target}, {select: "${select.trim()}"${extra}}, {appending: true}); } if (!(${target} instanceof abap.types.HashedTable) && ${target}.getOptions()?.primaryKey?.type !== "SORTED") { abap.statements.sort(${target}, {by: ${by}.map(k => { return {component: k}; })}); await abap.statements.deleteInternal(${target}, {adjacent: true, by: ${by}}); } abap.builtin.sy.get().dbcnt.set(${target}.getArrayLength()); }`; return new chunk_1.Chunk().append(code, node, traversal); } else { return new chunk_1.Chunk().append(`await abap.statements.select(${target}, {select: "${select.trim()}"${extra}}${runtimeOptions});`, node, traversal); } } findTable(node, traversal) { let keys = []; let tabl = undefined; const from = node.findAllExpressions(abaplint.Expressions.SQLFromSource).map(e => e.concatTokens()); if (from.length === 1) { tabl = traversal.findTable(from[0]); if (tabl) { keys = tabl.listKeys(traversal.reg).map(k => k.toLowerCase()); } } return { table: tabl, keys }; } isWhereExpression(node, expression) { // check if previous token before sqlCond is "WHERE". It could also be "ON" in case of join condition let prevToken; const sqlCondToken = expression.getFirstToken(); for (const token of node.getTokens()) { if (token.getStart() === sqlCondToken.getStart()) { break; } prevToken = token; } if (prevToken && prevToken.getStr().toUpperCase() === "WHERE") { return true; } else { return false; } } } exports.SelectTranspiler = SelectTranspiler; //# sourceMappingURL=select.js.map