Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"supportLevel": "Stable",
"groupId": "org.eclipse.dirigible",
"artifactId": "dirigible-components-engine-camel",
"version": "14.0.0-SNAPSHOT",
"version": "15.0.0-SNAPSHOT",
"scheme": "dirigible-java-script",
"extendsScheme": "",
"syntax": "dirigible-java-script:javaScriptPath",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,19 @@ private static String buildWhere(IntentGenerationContext context, IntentModel mo
Matcher.quoteReplacement(baseAlias + "." + quote(column(source.getName(), field.getName()))));
}
}
// A bare to-one RELATION name filters by its FK column (`Status != 8` -> the status FK
// id column) - previously it passed through untranslated and broke the generated SQL.
// The negative lookahead skips join-alias usages (`Customer."CUSTOMER_NAME"` from the
// dotted-ref pass above); the lookbehind skips already-qualified column tokens.
if (source.getRelations() != null) {
for (RelationIntent relation : source.getRelations()) {
if (relation.getName() != null && !relation.getName()
.isBlank()) {
where = where.replaceAll("(?<![.\"\\w])" + Pattern.quote(relation.getName()) + "\\b(?!\\s*[.\"])",
Matcher.quoteReplacement(baseAlias + "." + quote(column(source.getName(), relation.getName()))));
}
}
}
// Authors used to the intent's guard syntax write `Status == 2`; SQL equality is a single
// `=` (H2 tolerates `==`, PostgreSQL rejects it), so normalize. `<=`/`>=`/`!=` are untouched.
// Normalize only OUTSIDE single-quoted string literals so a value literal that itself contains
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,49 @@ void listWidgetCarriesTheLimitAndLiteralPinsKeepTheirValue() {
.get("token"));
}

private static final String STATUS_FILTER_INTENT = """
name: billing
entities:
- name: InvoiceStatus
kind: setting
fields:
- { name: id, type: integer, primaryKey: true, generated: true }
- { name: name, type: string }
- name: Customer
fields:
- { name: id, type: integer, primaryKey: true, generated: true }
- { name: name, type: string }
- name: Invoice
fields:
- { name: id, type: integer, primaryKey: true, generated: true }
- { name: number, type: string }
- { name: due, type: date }
- { name: balance, type: decimal }
relations:
- { name: Status, kind: manyToOne, to: InvoiceStatus, function: EntityStatus, init: 1 }
- { name: Customer, kind: manyToOne, to: Customer }
reports:
- name: OverdueInvoices
source: Invoice
dimensions: [number, due, Customer.name]
filter: "due <= CURRENT_DATE AND Customer.name != 'X' AND Status != 8"
""";

@Test
void filterTranslatesABareToOneRelationToItsFkColumn() {
IntentModel model = IntentParser.parse(STATUS_FILTER_INTENT);
Map<String, Object> document = ReportIntentGenerator.buildForTest(TestContexts.context(model), model.getReports()
.get(0));
String query = (String) document.get("query");
// A bare to-one relation name filters by its FK column - previously it passed through
// untranslated (`AND Status != 8`) and broke the generated SQL.
assertTrue(query.contains("Invoice.\"INVOICE_STATUS\" != 8"), query);
// The dotted ref keeps its join-alias form - the bare-relation pass must not mangle the
// alias token it produced.
assertTrue(query.contains("Customer.\"CUSTOMER_NAME\" != 'X'"), query);
assertTrue(!query.contains(" Status "), query);
}

private static final String LEDGER_INTENT = """
name: ledger
entities:
Expand Down
Loading