UNPKG

@abaplint/runtime

Version:
554 lines • 18.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Table = exports.HashedTable = exports.TableFactory = exports.LoopController = exports.TableKeyType = exports.TableAccessType = void 0; const integer_1 = require("./integer"); const abap_object_1 = require("./abap_object"); const string_1 = require("./string"); const structure_1 = require("./structure"); const field_symbol_1 = require("./field_symbol"); const data_reference_1 = require("./data_reference"); const insert_internal_1 = require("../statements/insert_internal"); const sort_1 = require("../statements/sort"); const character_1 = require("./character"); const hex_1 = require("./hex"); const hex_uint8_1 = require("./hex_uint8"); var TableAccessType; (function (TableAccessType) { TableAccessType["standard"] = "STANDARD"; TableAccessType["sorted"] = "SORTED"; TableAccessType["hashed"] = "HASHED"; TableAccessType["index"] = "INDEX"; TableAccessType["any"] = "ANY"; })(TableAccessType || (exports.TableAccessType = TableAccessType = {})); var TableKeyType; (function (TableKeyType) { TableKeyType["default"] = "DEFAULT"; TableKeyType["user"] = "USER"; TableKeyType["empty"] = "EMPTY"; })(TableKeyType || (exports.TableKeyType = TableKeyType = {})); class LoopController { index; loopTo; array; constructor(from, loopTo, array) { this.index = from; this.loopTo = loopTo; this.array = array; } } exports.LoopController = LoopController; class TableFactory { static construct(rowType, options, qualifiedName) { if (options === undefined) { options = { primaryKey: { name: "primary_key", type: TableAccessType.standard, keyFields: [], isUnique: false, }, keyType: TableKeyType.default, withHeader: false, }; } if (options.primaryKey?.type === TableAccessType.hashed) { return new HashedTable(rowType, options, qualifiedName); } else { return new Table(rowType, options, qualifiedName); } } } exports.TableFactory = TableFactory; /* export class SortedTable { // todo } */ class HashedTable { value; header; rowType; loops; options; qualifiedName; isStructured; secondaryIndexes; constructor(rowType, options, qualifiedName) { this.value = {}; this.secondaryIndexes = {}; this.loops = new Set(); this.rowType = rowType; this.options = options; this.isStructured = rowType instanceof structure_1.Structure; if (options?.withHeader === true) { this.header = this.rowType.clone(); } this.qualifiedName = qualifiedName?.toUpperCase(); } clone() { const copy = new HashedTable(this.rowType, this.options, this.qualifiedName); for (const hash in this.value) { copy.value[hash] = this.value[hash].clone(); } return copy; } getArrayLength() { return Object.keys(this.value).length; } getKeyByName(name) { return this.getOptions()?.secondary?.find(s => s.name.toUpperCase() === name.toUpperCase()); } getSecondaryIndex(name) { if (this.secondaryIndexes[name.toUpperCase()]) { return this.secondaryIndexes[name.toUpperCase()]; } const secondary = this.getKeyByName(name); if (secondary === undefined) { throw `Table, secondary key "${name}" not found`; } // note, array() already is a copy, so it can be used, const copy = this.array(); (0, sort_1.sort)(copy, { by: secondary.keyFields.map(k => { return { component: k.toLowerCase() }; }) }); this.secondaryIndexes[name.toUpperCase()] = copy; return copy; } buildHashFromData(data) { let hash = ""; for (const k of this.options.primaryKey.keyFields) { if (k === "TABLE_LINE") { if (data instanceof structure_1.Structure) { hash += k + ":" + data.getCharacter(true) + "|"; } else if (data instanceof abap_object_1.ABAPObject) { const moo = data.getInternalID(); hash += k + ":" + moo + "|"; } else { // @ts-ignore hash += k + ":" + data.get() + "|"; } } else { // @ts-ignore let val = data.get()[k.toLowerCase()]; if (val instanceof structure_1.Structure) { val = val.getCharacter(true); } else if (val instanceof abap_object_1.ABAPObject) { val = val.getInternalID(); } else { val = val.get(); } hash += k + ":" + val + "|"; } } return hash; } deleteIndex(_index) { throw new Error("HashedTable, deleteIndex"); } deleteFrom(row) { const hash = this.buildHashFromData(row); delete this.value[hash]; } buildHashFromSimple(data) { let hash = ""; const tableRowType = this.getRowType(); const isStructured = tableRowType instanceof structure_1.Structure; for (const k of this.options.primaryKey.keyFields) { let val = data[k.toLowerCase()]; if (val === undefined && tableRowType.get()[k.toLowerCase()] instanceof structure_1.Structure && Object.keys(tableRowType.get()[k.toLowerCase()].get()).length === 1) { // todo: this might need to be extended and fixed val = data[Object.keys(tableRowType.get()[k.toLowerCase()].get())[0]]; } // convert to correct type, eg Chars have specific length, or rounding, if (k === "TABLE_LINE") { const row = tableRowType.clone(); row.set(val.get()); val = row.get(); } else if (isStructured === true) { const field = tableRowType.get()[k.toLowerCase()]; // if types match, there is no need to clone if (field instanceof string_1.String && val instanceof string_1.String) { val = val.get(); } else if (field instanceof character_1.Character && val instanceof character_1.Character && field.getLength() === val.getLength()) { val = val.get(); } else if (field instanceof hex_1.Hex && val instanceof hex_1.Hex && field.getLength() === val.getLength()) { val = val.get(); } else if (field instanceof hex_uint8_1.HexUInt8 && val instanceof hex_uint8_1.HexUInt8 && field.getLength() === val.getLength()) { val = val.get(); } else if (val instanceof abap_object_1.ABAPObject) { val = val.getInternalID(); } else if (val instanceof structure_1.Structure) { val = val.getCharacter(true); } else { // convert const row = field.clone(); row.set(val.get()); val = row.get(); } } else { throw new Error("HashedTable, buildHashFromSimple, unexpected type"); } hash += k + ":" + val + "|"; } return hash; } read(hash) { return this.value[hash]; } insert(data) { const hash = this.buildHashFromData(data); if (this.value[hash] !== undefined) { return { value: undefined, subrc: 4 }; } else { const val = this.cloneRow(data); for (const loopController of this.loops.values()) { loopController.array.push(val); } this.secondaryIndexes = {}; this.value[hash] = val; return { value: val, subrc: 0 }; } } appendThis(data) { this.insert(data); return this; } array() { // used for LOOP const ret = []; for (const hash in this.value) { ret.push(this.value[hash]); } return ret; } startLoop(from, to, array) { const l = new LoopController(from, to, array); this.loops.add(l); return l; } unregisterLoop(loop) { this.loops.delete(loop); } insertIndex(_item, _index) { throw new Error("Hash table insert index"); } append(_item) { throw new Error("Hash table append"); } getQualifiedName() { return this.qualifiedName; } getOptions() { return this.options; } getRowType() { return this.rowType; } clear() { this.value = {}; this.secondaryIndexes = {}; } set(tab) { if (tab instanceof field_symbol_1.FieldSymbol) { if (tab.getPointer() === undefined) { throw new Error("GETWA_NOT_ASSIGNED"); } return this.set(tab.getPointer()); } if (tab === this) { return this; } this.clear(); if (tab instanceof Table || tab instanceof HashedTable) { for (const a of tab.array()) { this.insert(a); } return this; } else { throw new Error("Method not implemented, set hashed table"); } } getHeader() { if (this.header === undefined) { throw "table, getHeader"; } return this.header; } /////////////////////////// cloneRow(item) { // make sure to do conversion if needed if (typeof item === "number") { const tmp = this.getRowType().clone(); tmp.set(new integer_1.Integer().set(item)); return tmp; } else if (typeof item === "string") { const tmp = this.getRowType().clone(); tmp.set(new string_1.String().set(item)); return tmp; // @ts-ignore } else if (this.isStructured === true && item.getQualifiedName && this.rowType.getQualifiedName && item.getQualifiedName() !== "" && item.getQualifiedName() === this.rowType.getQualifiedName()) { // types match, so no need to do conversions, just clone the item const val = item.clone(); return val; } else { const tmp = this.getRowType().clone(); tmp.set(item); return tmp; } } } exports.HashedTable = HashedTable; class Table { value; header; rowType; loops; options; qualifiedName; isStructured; secondaryIndexes; constructor(rowType, options, qualifiedName) { this.value = []; this.secondaryIndexes = {}; this.loops = new Set(); this.rowType = rowType; this.options = options; this.isStructured = rowType instanceof structure_1.Structure; if (options?.withHeader === true) { this.header = this.rowType.clone(); } this.qualifiedName = qualifiedName?.toUpperCase(); } clone() { const copy = new Table(this.rowType, this.options, this.qualifiedName); for (const val of this.value) { // @ts-ignore copy.value.push(val.clone()); } return copy; } getArrayLength() { return this.value.length; } getKeyByName(name) { return this.getOptions()?.secondary?.find(s => s.name.toUpperCase() === name.toUpperCase()); } getSecondaryIndex(name) { if (this.secondaryIndexes[name.toUpperCase()]) { return this.secondaryIndexes[name.toUpperCase()]; } const secondary = this.getKeyByName(name); if (secondary === undefined) { throw `Table, secondary key "${name}" not found`; } const copy = [...this.value]; (0, sort_1.sort)(copy, { by: secondary.keyFields.map(k => { return { component: k.toLowerCase() }; }), skipSortedCheck: true }); this.secondaryIndexes[name.toUpperCase()] = copy; return copy; } getQualifiedName() { return this.qualifiedName; } getOptions() { return this.options; } startLoop(from, to, array) { const l = new LoopController(from, to, array); this.loops.add(l); return l; } getCurrentLoopIndex() { if (this.loops.size !== 1) { throw new Error("More than one LOOP"); } return Array.from(this.loops)[0].index; } unregisterLoop(loop) { this.loops.delete(loop); } getRowType() { return this.rowType; } // Modifications to the array must be done inside this class, in order to keep track of LOOP indexes array() { return this.value; } clear() { this.value = []; this.secondaryIndexes = {}; } set(tab) { this.secondaryIndexes = {}; if (this.options?.withHeader === true) { this.header?.set(tab); } else { if (tab instanceof field_symbol_1.FieldSymbol) { tab = tab.getPointer(); } if (!(tab instanceof Table) && !(tab instanceof HashedTable)) { throw new Error("Table, set error, " + tab?.constructor.name); } if (tab === this) { return this; } this.clear(); // this clones the values, and add sorting if required (0, insert_internal_1.insertInternal)({ table: this, data: tab, lines: true }); } return this; } getHeader() { if (this.header === undefined) { throw new Error("table, getHeader"); } return this.header; } get() { if (this.header === undefined) { throw new Error("table, no header line"); } return this.header.get(); } insertIndex(item, index, noClone = false) { this.secondaryIndexes = {}; if (item instanceof field_symbol_1.FieldSymbol) { const p = item.getPointer(); if (p === undefined) { throw new Error("insertIndex, fs not assigned"); } this.insertIndex(p, index); return p; } let val; if (noClone === false) { val = this.cloneRow(item); } else { val = item; } if (index === 0) { this.value.unshift(val); } else if (index === this.value.length) { this.value.push(val); } else { this.value.splice(index, 0, val); } for (const loopController of this.loops.values()) { if (index <= loopController.index) { loopController.index++; } } return val; } /** index = javascript indexed */ deleteIndex(index) { this.secondaryIndexes = {}; if (index > this.value.length) { return; } if (index === this.value.length - 1) { this.value.pop(); // pop'ing is faster than splice } else if (index === 0) { this.value.shift(); } else { this.value.splice(index, 1); } for (const l of this.loops.values()) { if (l.index >= index) { l.index--; } } } append(item) { if (item === undefined) { throw new Error("APPEND, item is undefined"); } this.secondaryIndexes = {}; if (item instanceof field_symbol_1.FieldSymbol) { const p = item.getPointer(); if (p === undefined) { throw new Error("APPEND, fs not assigned"); } this.append(p); return p; } else if (item instanceof data_reference_1.DataReference) { const ref = new data_reference_1.DataReference(item.getType()); ref.assign(item.getPointer()); this.value.push(ref); return ref; } else { const val = this.cloneRow(item); this.value.push(val); return val; } } /* appends and returns this */ appendThis(item) { this.append(item); return this; } appendInitial() { this.secondaryIndexes = {}; // note that this will clone the object this.append(this.rowType); abap.builtin.sy.get().tabix.set(this.value.length); return this.value[this.value.length - 1]; } sort(compareFn) { this.value.sort(compareFn); } /////////////////////////// cloneRow(item) { // make sure to do conversion if needed if (typeof item === "number") { const tmp = this.getRowType().clone(); tmp.set(new integer_1.Integer().set(item)); return tmp; } else if (typeof item === "string") { const tmp = this.getRowType().clone(); tmp.set(new string_1.String().set(item)); return tmp; // @ts-ignore } else if (this.isStructured === true && item.getQualifiedName && this.rowType.getQualifiedName && item.getQualifiedName() !== "" && item.getQualifiedName() === this.rowType.getQualifiedName()) { // types match, so no need to do conversions, just clone the item const val = item.clone(); return val; } else { const tmp = this.getRowType().clone(); tmp.set(item); return tmp; } } } exports.Table = Table; //# sourceMappingURL=table.js.map