@abaplint/core 2.120.27 → 2.120.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,7 @@ const sql_field_1 = require("./sql_field");
9
9
  const sql_grouping_sets_1 = require("./sql_grouping_sets");
10
10
  class SQLGroupBy extends combi_1.Expression {
11
11
  getRunnable() {
12
- const fieldName = (0, combi_1.alt)(sql_field_name_1.SQLFieldName, dynamic_1.Dynamic);
12
+ const fieldName = (0, combi_1.seq)((0, combi_1.stopBefore)("ORDER", "BY"), (0, combi_1.alt)(sql_field_name_1.SQLFieldName, dynamic_1.Dynamic));
13
13
  const expr = (0, combi_1.ver)(version_1.Release.v740sp02, sql_field_1.SQLField, { also: combi_1.AlsoIn.OpenABAP });
14
14
  const newGroup = (0, combi_1.ver)(version_1.Release.v740sp02, (0, combi_1.seq)("GROUP BY", expr, (0, combi_1.altPrio)((0, combi_1.plus)((0, combi_1.seq)(",", expr)), (0, combi_1.optPrio)((0, combi_1.plus)(fieldName)))), { also: combi_1.AlsoIn.OpenABAP });
15
15
  const old = (0, combi_1.seq)((0, combi_1.plus)((0, combi_1.seq)(fieldName, ",")), fieldName);
@@ -25,7 +25,7 @@ function checkDatabaseFields(fields, dbSources, input, token) {
25
25
  if (field === "*") {
26
26
  continue;
27
27
  }
28
- if (/^\w+$/.test(field) && type.getComponentByName(field) === undefined) {
28
+ if (/^[A-Z_]\w*$/i.test(field) && type.getComponentByName(field) === undefined) {
29
29
  const message = `checkFields, field ${field} not found`;
30
30
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, token, message));
31
31
  return;
@@ -74,7 +74,7 @@ class Select {
74
74
  return;
75
75
  }
76
76
  (0, _check_database_fields_1.checkDatabaseFields)(fields.map(field => field.code), dbSources, input, node.getFirstToken());
77
- const intoExpression = this.handleInto(node, input, fields, dbSources);
77
+ const intoExpression = this.handleInto(node, input, fields, dbSources, from);
78
78
  const fae = node.findDirectExpression(Expressions.SQLForAllEntries);
79
79
  if (fae) {
80
80
  input.scope.push(_scope_type_1.ScopeType.OpenSQL, "SELECT", token.getStart(), input.filename);
@@ -235,12 +235,12 @@ class Select {
235
235
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
236
236
  }
237
237
  }
238
- static handleInto(node, input, fields, dbSources) {
238
+ static handleInto(node, input, fields, dbSources, from) {
239
239
  const intoTable = node.findDirectExpression(Expressions.SQLIntoTable);
240
240
  if (intoTable) {
241
241
  const inline = intoTable.findFirstExpression(Expressions.InlineData);
242
242
  if (inline) {
243
- inline_data_1.InlineData.runSyntax(inline, input, this.buildTableType(fields, dbSources, input.scope));
243
+ inline_data_1.InlineData.runSyntax(inline, input, this.buildTableType(fields, dbSources, input.scope, from));
244
244
  }
245
245
  return intoTable;
246
246
  }
@@ -388,11 +388,36 @@ class Select {
388
388
  return basic_1.VoidType.get("SELECT_todo13");
389
389
  }
390
390
  }
391
- static buildTableType(fields, dbSources, scope) {
392
- if (dbSources.length !== 1) {
391
+ static buildTableType(fields, dbSources, scope, from) {
392
+ var _a;
393
+ const tableOptions = { withHeader: false, keyType: basic_1.TableKeyType.empty };
394
+ if (dbSources.length > 1) {
395
+ const sourceInfos = this.buildDatabaseSourceInfos(from, dbSources);
396
+ if (fields.length === 1 && fields[0].code === "*") {
397
+ const components = [];
398
+ for (const info of sourceInfos) {
399
+ const type = (_a = info.source) === null || _a === void 0 ? void 0 : _a.parseType(scope.getRegistry());
400
+ if (!(type instanceof basic_1.StructureType)) {
401
+ return basic_1.VoidType.get("SELECT_todo3");
402
+ }
403
+ components.push({ name: info.alias || info.name, type });
404
+ }
405
+ return new basic_1.TableType(new basic_1.StructureType(components), tableOptions, undefined);
406
+ }
407
+ const components = [];
408
+ for (const field of fields) {
409
+ const type = this.findFieldType(field.code, sourceInfos, scope);
410
+ if (type === undefined) {
411
+ return basic_1.VoidType.get("SELECT_todo3");
412
+ }
413
+ const name = field.as || field.code.split("~").pop();
414
+ components.push({ name, type });
415
+ }
416
+ return new basic_1.TableType(new basic_1.StructureType(components), tableOptions, undefined);
417
+ }
418
+ else if (dbSources.length !== 1) {
393
419
  return basic_1.VoidType.get("SELECT_todo3");
394
420
  }
395
- const tableOptions = { withHeader: false, keyType: basic_1.TableKeyType.empty };
396
421
  if (dbSources[0] === undefined) {
397
422
  // then its a voided table
398
423
  return new basic_1.TableType(basic_1.VoidType.get("SELECT_todo4"), tableOptions, undefined);
@@ -418,6 +443,39 @@ class Select {
418
443
  }
419
444
  return basic_1.VoidType.get("SELECT_todo7");
420
445
  }
446
+ static buildDatabaseSourceInfos(from, dbSources) {
447
+ const fromSources = from.findAllExpressions(Expressions.SQLFromSource);
448
+ return dbSources.map((source, index) => {
449
+ var _a, _b;
450
+ const fromSource = fromSources[index];
451
+ const name = ((_a = fromSource === null || fromSource === void 0 ? void 0 : fromSource.findFirstExpression(Expressions.DatabaseTable)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStr().replace(/^\*/, "").toUpperCase()) || "";
452
+ const alias = ((_b = fromSource === null || fromSource === void 0 ? void 0 : fromSource.findDirectExpression(Expressions.SQLAsName)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase()) || "";
453
+ return { source, name, alias };
454
+ });
455
+ }
456
+ static findFieldType(code, sourceInfos, scope) {
457
+ var _a;
458
+ const separator = code.indexOf("~");
459
+ const qualifier = separator >= 0 ? code.substring(0, separator) : undefined;
460
+ const fieldName = separator >= 0 ? code.substring(separator + 1) : code;
461
+ const candidates = qualifier === undefined
462
+ ? sourceInfos
463
+ : sourceInfos.filter(info => info.alias === qualifier || info.name === qualifier);
464
+ for (const candidate of candidates) {
465
+ let type = (_a = candidate.source) === null || _a === void 0 ? void 0 : _a.parseType(scope.getRegistry());
466
+ for (const component of fieldName.split("-")) {
467
+ if (!(type instanceof basic_1.StructureType)) {
468
+ type = undefined;
469
+ break;
470
+ }
471
+ type = type.getComponentByName(component);
472
+ }
473
+ if (type) {
474
+ return type;
475
+ }
476
+ }
477
+ return undefined;
478
+ }
421
479
  static findFields(node, input) {
422
480
  var _a, _b;
423
481
  let expr = undefined;
@@ -431,7 +489,7 @@ class Select {
431
489
  let code = field.concatTokens().toUpperCase();
432
490
  const as = ((_b = field.findDirectExpression(Expressions.SQLAsName)) === null || _b === void 0 ? void 0 : _b.concatTokens()) || "";
433
491
  if (as !== "") {
434
- code = code.replace(" AS " + as, "");
492
+ code = code.replace(" AS " + as.toUpperCase(), "");
435
493
  }
436
494
  ret.push({ code, as, expression: field });
437
495
  }
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.ValueBody = void 0;
37
+ const nodes_1 = require("../../nodes");
37
38
  const Expressions = __importStar(require("../../2_statements/expressions"));
38
39
  const for_1 = require("./for");
39
40
  const source_1 = require("./source");
@@ -43,7 +44,7 @@ const basic_1 = require("../../types/basic");
43
44
  const _syntax_input_1 = require("../_syntax_input");
44
45
  class ValueBody {
45
46
  static runSyntax(node, input, targetType) {
46
- var _a, _b;
47
+ var _a, _b, _c;
47
48
  if (node === undefined) {
48
49
  return targetType;
49
50
  }
@@ -60,26 +61,45 @@ class ValueBody {
60
61
  }
61
62
  }
62
63
  const fields = new Set();
63
- for (const s of node.findDirectExpressions(Expressions.FieldAssignment)) {
64
- field_assignment_1.FieldAssignment.runSyntax(s, input, targetType);
65
- if (node.findDirectExpression(Expressions.ValueBodyLine) === undefined) {
66
- // todo: refine, still needs to be checked when there are table lines
67
- const fieldname = (_a = s.findDirectExpression(Expressions.FieldSub)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
64
+ const hasTableLines = node.findDirectExpression(Expressions.ValueBodyLine) !== undefined;
65
+ for (const child of node.getChildren()) {
66
+ if (!(child instanceof nodes_1.ExpressionNode)) {
67
+ continue;
68
+ }
69
+ else if (child.get() instanceof Expressions.FieldAssignment) {
70
+ const fieldname = (_a = child.findDirectExpression(Expressions.FieldSub)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
71
+ if (fieldname && hasTableLines === false && fields.has(fieldname)) {
72
+ const message = "Duplicate field assignment";
73
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, child.getFirstToken(), message));
74
+ return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
75
+ }
68
76
  if (fieldname) {
69
- if (fields.has(fieldname)) {
77
+ fields.add(fieldname);
78
+ }
79
+ }
80
+ else if (child.get() instanceof Expressions.ValueBodyLine) {
81
+ const rowFields = new Set(fields);
82
+ for (const assignment of child.findDirectExpressions(Expressions.FieldAssignment)) {
83
+ const fieldname = (_b = assignment.findDirectExpression(Expressions.FieldSub)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase();
84
+ if (fieldname && rowFields.has(fieldname)) {
70
85
  const message = "Duplicate field assignment";
71
- input.issues.push((0, _syntax_input_1.syntaxIssue)(input, s.getFirstToken(), message));
86
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, assignment.getFirstToken(), message));
72
87
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
73
88
  }
74
- fields.add(fieldname);
89
+ if (fieldname) {
90
+ rowFields.add(fieldname);
91
+ }
75
92
  }
76
93
  }
77
94
  }
95
+ for (const s of node.findDirectExpressions(Expressions.FieldAssignment)) {
96
+ field_assignment_1.FieldAssignment.runSyntax(s, input, targetType);
97
+ }
78
98
  let type = undefined; // todo, this is only correct if there is a single source in the body
79
99
  for (const s of node.findDirectExpressions(Expressions.Source)) {
80
100
  type = source_1.Source.runSyntax(s, input, type);
81
101
  }
82
- for (const s of ((_b = node.findDirectExpression(Expressions.ValueBase)) === null || _b === void 0 ? void 0 : _b.findDirectExpressions(Expressions.Source)) || []) {
102
+ for (const s of ((_c = node.findDirectExpression(Expressions.ValueBase)) === null || _c === void 0 ? void 0 : _c.findDirectExpressions(Expressions.Source)) || []) {
83
103
  type = source_1.Source.runSyntax(s, input, type);
84
104
  }
85
105
  for (const foo of node.findDirectExpressions(Expressions.ValueBodyLine)) {
@@ -75,7 +75,7 @@ class Registry {
75
75
  }
76
76
  static abaplintVersion() {
77
77
  // magic, see build script "version.js"
78
- return "2.120.27";
78
+ return "2.120.28";
79
79
  }
80
80
  getDDICReferences() {
81
81
  return this.ddicReferences;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.120.27",
3
+ "version": "2.120.28",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",