UNPKG

@abaplint/core

Version:
123 lines (122 loc) 5.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SelectPerformance = exports.SelectPerformanceConf = void 0; const Expressions = require("../abap/2_statements/expressions"); const Statements = require("../abap/2_statements/statements"); const Structures = require("../abap/3_structures/structures"); const _basic_rule_config_1 = require("./_basic_rule_config"); const issue_1 = require("../issue"); const _irule_1 = require("./_irule"); const _abap_object_1 = require("../objects/_abap_object"); const syntax_1 = require("../abap/5_syntax/syntax"); const structure_type_1 = require("../abap/types/basic/structure_type"); const DEFAULT_COLUMNS = 10; class SelectPerformanceConf extends _basic_rule_config_1.BasicRuleConfig { constructor() { super(...arguments); /** Detects ENDSELECT */ this.endSelect = true; /** Detects SELECT * */ this.selectStar = true; /** "SELECT" * is considered okay if the table is less than X columns, the table must be known to the linter * @default 10 */ this.starOkayIfFewColumns = DEFAULT_COLUMNS; } } exports.SelectPerformanceConf = SelectPerformanceConf; class SelectPerformance { constructor() { this.conf = new SelectPerformanceConf(); } getMetadata() { return { key: "select_performance", title: "SELECT performance", shortDescription: `Various checks regarding SELECT performance.`, extendedInformation: `ENDSELECT: not reported when the corresponding SELECT has PACKAGE SIZE SELECT *: not reported if using INTO/APPENDING CORRESPONDING FIELDS OF`, tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Performance], badExample: `SELECT field1, field2 FROM table INTO @DATA(structure) UP TO 1 ROWS ORDER BY field3 DESCENDING. ENDSELECT.`, goodExample: `SELECT field1, field2 FROM table UP TO 1 ROWS INTO TABLE @DATA(table) ORDER BY field3 DESCENDING`, }; } initialize(reg) { this.reg = reg; return this; } getConfig() { if (this.conf.starOkayIfFewColumns === undefined) { this.conf.starOkayIfFewColumns = DEFAULT_COLUMNS; } return this.conf; } setConfig(conf) { this.conf = conf; } run(obj) { if (!(obj instanceof _abap_object_1.ABAPObject)) { return []; } const issues = []; for (const file of obj.getABAPFiles()) { const stru = file.getStructure(); if (stru === undefined) { return issues; } if (this.conf.endSelect) { for (const s of stru.findAllStructures(Structures.Select) || []) { const select = s.findDirectStatement(Statements.SelectLoop); if (select === undefined || select.concatTokens().toUpperCase().includes("PACKAGE SIZE")) { continue; } const message = "Avoid use of ENDSELECT"; issues.push(issue_1.Issue.atStatement(file, select, message, this.getMetadata().key, this.conf.severity)); } } if (this.conf.selectStar) { const spaghetti = new syntax_1.SyntaxLogic(this.reg, obj).run().spaghetti; const selects = stru.findAllStatements(Statements.Select); selects.push(...stru.findAllStatements(Statements.SelectLoop)); for (const s of selects) { const concat = s.concatTokens().toUpperCase(); if (concat.startsWith("SELECT * ") === false && concat.startsWith("SELECT SINGLE * ") === false) { continue; } else if (concat.includes(" INTO CORRESPONDING FIELDS OF ") || concat.includes(" APPENDING CORRESPONDING FIELDS OF ")) { continue; } const columnCount = this.findNumberOfColumns(s, file, spaghetti); if (columnCount && columnCount <= this.getConfig().starOkayIfFewColumns) { continue; } const message = "Avoid use of SELECT *"; issues.push(issue_1.Issue.atToken(file, s.getFirstToken(), message, this.getMetadata().key, this.conf.severity)); } } } return issues; } findNumberOfColumns(s, file, spaghetti) { const dbnames = s.findAllExpressions(Expressions.DatabaseTable); if (dbnames.length === 1) { const start = dbnames[0].getFirstToken().getStart(); const scope = spaghetti.lookupPosition(start, file.getFilename()); const name = scope === null || scope === void 0 ? void 0 : scope.findTableReference(start); const tabl = this.reg.getObject("TABL", name); const parsed = tabl === null || tabl === void 0 ? void 0 : tabl.parseType(this.reg); if (parsed instanceof structure_type_1.StructureType) { return parsed.getComponents().length; } } return undefined; } } exports.SelectPerformance = SelectPerformance; //# sourceMappingURL=select_performance.js.map