@abaplint/transpiler
Version:
164 lines • 7.97 kB
JavaScript
;
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