All files / src/rules select_add_order_by.ts

100% Statements 44/44
85.71% Branches 42/49
100% Functions 6/6
100% Lines 44/44

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 951x 1x 1x 1x 1x 1x   1x   1x   1x     1x   7265x     21660x                             7008x       122x 122x       114x       140x 140x 18x     122x   122x 126x 126x 12x     114x 114x 114x 8x 8x 1x       7x 7x 3x 4x 1x     3x 3x 3x 3x 3x 3x   2x       1x       110x      
import * as Expressions from "../abap/2_statements/expressions";
import * as Statements from "../abap/2_statements/statements";
import {BasicRuleConfig} from "./_basic_rule_config";
import {Issue} from "../issue";
import {IRule, IRuleMetadata, RuleTag} from "./_irule";
import {SyntaxLogic} from "../abap/5_syntax/syntax";
import {IObject} from "../objects/_iobject";
import {ABAPObject} from "../objects/_abap_object";
import {IRegistry} from "../_iregistry";
import {TableAccessType, TableType} from "../abap/types/basic";
 
export class SelectAddOrderByConf extends BasicRuleConfig {
}
 
export class SelectAddOrderBy implements IRule {
  private reg: IRegistry;
  private conf = new SelectAddOrderByConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "select_add_order_by",
      title: "SELECT add ORDER BY",
      shortDescription: `SELECTs add ORDER BY clause`,
      extendedInformation: `
This will make sure that the SELECT statement returns results in the same sequence on different databases
 
add ORDER BY PRIMARY KEY if in doubt
 
If the target is a sorted/hashed table, no issue is reported`,
      tags: [RuleTag.SingleFile],
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public initialize(reg: IRegistry) {
    this.reg = reg;
    return this;
  }
 
  public setConfig(conf: SelectAddOrderByConf): void {
    this.conf = conf;
  }
 
  public run(obj: IObject): Issue[] {
    const issues: Issue[] = [];
    if (!(obj instanceof ABAPObject) || obj.getType() === "INTF") {
      return [];
    }
 
    const spaghetti = new SyntaxLogic(this.reg, obj).run().spaghetti;
 
    for (const file of obj.getABAPFiles()) {
      const stru = file.getStructure();
      if (stru === undefined) {
        return issues;
      }
 
      const selects = stru.findAllStatements(Statements.Select);
      selects.push(...stru.findAllStatements(Statements.SelectLoop));
      for (const s of selects) {
        const c = s.concatTokens();
        if (c.startsWith("SELECT SINGLE ")) {
          continue;
        }
 
        // skip COUNT(*)
        const list = s.findFirstExpression(Expressions.SQLFieldList);
        if (list?.getChildren().length === 1 && list.getFirstChild()?.get() instanceof Expressions.SQLAggregation) {
          continue;
        } else if (s.findFirstExpression(Expressions.SQLOrderBy)) {
          continue;
        }
 
        const target = s.findFirstExpression(Expressions.SQLIntoTable)?.findFirstExpression(Expressions.Target);
        Eif (target) {
          const start = target.getFirstToken().getStart();
          const scope = spaghetti.lookupPosition(start, file.getFilename());
          const type = scope?.findWriteReference(start)?.getType();
          if (type instanceof TableType
              && (type?.getAccessType() === TableAccessType.sorted || type?.getAccessType() === TableAccessType.hashed)) {
            continue;
          }
        }
 
        issues.push(Issue.atStatement(file, s, "Add ORDER BY", this.getMetadata().key, this.conf.severity));
      }
    }
 
    return issues;
  }
 
}