@memberjunction/core-entities-server 4.0.0 → 4.1.0
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.
- package/README.md +147 -11
- package/dist/custom/ApplicationEntity.server.d.ts +9 -0
- package/dist/custom/ApplicationEntity.server.d.ts.map +1 -1
- package/dist/custom/ApplicationEntity.server.js +23 -6
- package/dist/custom/ApplicationEntity.server.js.map +1 -1
- package/dist/custom/QueryEntity.server.d.ts +0 -22
- package/dist/custom/QueryEntity.server.d.ts.map +1 -1
- package/dist/custom/QueryEntity.server.js +22 -268
- package/dist/custom/QueryEntity.server.js.map +1 -1
- package/dist/custom/sql-parser.d.ts +95 -0
- package/dist/custom/sql-parser.d.ts.map +1 -0
- package/dist/custom/sql-parser.js +313 -0
- package/dist/custom/sql-parser.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +15 -15
package/README.md
CHANGED
|
@@ -1,19 +1,38 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @memberjunction/core-entities-server
|
|
2
2
|
|
|
3
3
|
Server-side entity subclasses for MemberJunction that provide extended functionality and business logic for core entities when running in a Node.js environment.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
This package contains server-side implementations of MemberJunction entity subclasses that require server-specific functionality such as
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
This package contains server-side implementations of MemberJunction entity subclasses that require server-specific functionality such as direct database access, file system operations, server-side API integrations, complex business logic, and automatic creation/management of related entities.
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
graph TD
|
|
11
|
+
A["Core Entities Server"] --> B["AIPromptEntityExtended"]
|
|
12
|
+
A --> C["QueryEntityExtended"]
|
|
13
|
+
A --> D["ComponentEntityExtended"]
|
|
14
|
+
A --> E["ActionEntityExtended"]
|
|
15
|
+
A --> F["ApplicationEntityExtended"]
|
|
16
|
+
A --> G["Other Server Entities"]
|
|
17
|
+
|
|
18
|
+
B -->|manages| H["Templates<br/>Template Contents"]
|
|
19
|
+
C -->|manages| H
|
|
20
|
+
D -->|generates| I["Vector Embeddings"]
|
|
21
|
+
|
|
22
|
+
J["MJ Class Factory"] -->|returns server subclass| A
|
|
23
|
+
K["Core Entities<br/>(base classes)"] -->|extended by| A
|
|
24
|
+
|
|
25
|
+
style A fill:#2d6a9f,stroke:#1a4971,color:#fff
|
|
26
|
+
style B fill:#7c5295,stroke:#563a6b,color:#fff
|
|
27
|
+
style C fill:#7c5295,stroke:#563a6b,color:#fff
|
|
28
|
+
style D fill:#7c5295,stroke:#563a6b,color:#fff
|
|
29
|
+
style E fill:#7c5295,stroke:#563a6b,color:#fff
|
|
30
|
+
style F fill:#7c5295,stroke:#563a6b,color:#fff
|
|
31
|
+
style H fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
32
|
+
style I fill:#b8762f,stroke:#8a5722,color:#fff
|
|
33
|
+
style J fill:#2d6a9f,stroke:#1a4971,color:#fff
|
|
34
|
+
style K fill:#b8762f,stroke:#8a5722,color:#fff
|
|
35
|
+
```
|
|
17
36
|
|
|
18
37
|
### Key Differences from Core Entities
|
|
19
38
|
|
|
@@ -264,6 +283,123 @@ export class OrderEntityServer extends OrderEntity {
|
|
|
264
283
|
}
|
|
265
284
|
```
|
|
266
285
|
|
|
286
|
+
## SQL Parser
|
|
287
|
+
|
|
288
|
+
The `SQLParser` utility class extracts table/view references and column references from SQL statements. It uses `node-sql-parser` for AST-based parsing with automatic regex fallback when the AST parser fails. This class has **no dependency on MJ Metadata** — it returns raw parse results that callers cross-reference against entities themselves.
|
|
289
|
+
|
|
290
|
+
### When to Use
|
|
291
|
+
|
|
292
|
+
- **Virtual entity decoration**: Parse a view's SQL to identify which source entities it pulls from
|
|
293
|
+
- **Query entity metadata**: Parse SQL queries to find referenced tables and columns
|
|
294
|
+
- **Any server-side SQL analysis**: Extract structural information from SQL without executing it
|
|
295
|
+
|
|
296
|
+
### Basic Usage — Plain SQL
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
import { SQLParser } from '@memberjunction/core-entities-server';
|
|
300
|
+
|
|
301
|
+
const sql = `
|
|
302
|
+
SELECT c.Name, c.Email, o.OrderDate, o.Total
|
|
303
|
+
FROM [dbo].[Customer] c
|
|
304
|
+
INNER JOIN [dbo].[Order] o ON o.CustomerID = c.ID
|
|
305
|
+
WHERE o.Status = 'Active'
|
|
306
|
+
`;
|
|
307
|
+
|
|
308
|
+
const result = SQLParser.Parse(sql);
|
|
309
|
+
|
|
310
|
+
// Tables found in the query
|
|
311
|
+
for (const table of result.Tables) {
|
|
312
|
+
console.log(`${table.SchemaName}.${table.TableName} (alias: ${table.Alias})`);
|
|
313
|
+
}
|
|
314
|
+
// Output:
|
|
315
|
+
// dbo.Customer (alias: c)
|
|
316
|
+
// dbo.Order (alias: o)
|
|
317
|
+
|
|
318
|
+
// Columns referenced in the query
|
|
319
|
+
for (const col of result.Columns) {
|
|
320
|
+
console.log(`${col.TableQualifier ? col.TableQualifier + '.' : ''}${col.ColumnName}`);
|
|
321
|
+
}
|
|
322
|
+
// Output:
|
|
323
|
+
// c.Name, c.Email, o.OrderDate, o.Total, o.CustomerID, c.ID, o.Status
|
|
324
|
+
|
|
325
|
+
// Whether AST parsing succeeded (true) or regex fallback was used (false)
|
|
326
|
+
console.log(`Used AST: ${result.UsedASTParsing}`);
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Nunjucks Template SQL
|
|
330
|
+
|
|
331
|
+
For SQL that contains Nunjucks template syntax (e.g., MemberJunction query templates), use `ParseWithTemplatePreprocessing`. This replaces template expressions with safe placeholder values before parsing:
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import { SQLParser } from '@memberjunction/core-entities-server';
|
|
335
|
+
|
|
336
|
+
const templateSQL = `
|
|
337
|
+
SELECT * FROM [dbo].[Customer]
|
|
338
|
+
WHERE Status = {{ status | sqlString }}
|
|
339
|
+
{% if regionId %}
|
|
340
|
+
AND RegionID = {{ regionId | sqlNumber }}
|
|
341
|
+
{% endif %}
|
|
342
|
+
`;
|
|
343
|
+
|
|
344
|
+
// Nunjucks syntax is replaced with placeholders, then parsed normally
|
|
345
|
+
const result = SQLParser.ParseWithTemplatePreprocessing(templateSQL);
|
|
346
|
+
console.log(result.Tables); // [{ TableName: 'Customer', SchemaName: 'dbo', Alias: 'Customer' }]
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Cross-Referencing with Entity Metadata
|
|
350
|
+
|
|
351
|
+
The parser returns raw table/column references. To resolve them to MemberJunction entities:
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
import { Metadata } from '@memberjunction/core';
|
|
355
|
+
import { SQLParser } from '@memberjunction/core-entities-server';
|
|
356
|
+
|
|
357
|
+
const parseResult = SQLParser.Parse(viewDefinitionSQL);
|
|
358
|
+
const md = new Metadata();
|
|
359
|
+
|
|
360
|
+
for (const tableRef of parseResult.Tables) {
|
|
361
|
+
const entity = md.Entities.find(e =>
|
|
362
|
+
(e.BaseTable.toLowerCase() === tableRef.TableName.toLowerCase() ||
|
|
363
|
+
e.BaseView.toLowerCase() === tableRef.TableName.toLowerCase()) &&
|
|
364
|
+
e.SchemaName.toLowerCase() === tableRef.SchemaName.toLowerCase()
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
if (entity) {
|
|
368
|
+
console.log(`Table ${tableRef.TableName} → Entity "${entity.Name}"`);
|
|
369
|
+
// Access entity.Fields for full field metadata
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Return Types
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
interface SQLParseResult {
|
|
378
|
+
Tables: SQLTableReference[]; // All table/view references (FROM, JOIN, subqueries, CTEs)
|
|
379
|
+
Columns: SQLColumnReference[]; // All column references (SELECT, WHERE, JOIN ON, etc.)
|
|
380
|
+
UsedASTParsing: boolean; // true = AST parsed, false = regex fallback
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
interface SQLTableReference {
|
|
384
|
+
TableName: string; // Table or view name
|
|
385
|
+
SchemaName: string; // Schema name (defaults to 'dbo')
|
|
386
|
+
Alias: string; // Query alias, or table name if no alias
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
interface SQLColumnReference {
|
|
390
|
+
ColumnName: string; // Column name
|
|
391
|
+
TableQualifier: string | null; // Table alias prefix (e.g., "c" in "c.Name")
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### How It Works
|
|
396
|
+
|
|
397
|
+
1. **AST Parsing** (preferred): Uses `node-sql-parser` with `TransactSQL` dialect to build an AST, then recursively walks it to extract table references from `FROM`/`JOIN` clauses, subqueries, and CTEs, plus column references from `SELECT`, `WHERE`, `GROUP BY`, `ORDER BY`, and `ON` conditions.
|
|
398
|
+
|
|
399
|
+
2. **Regex Fallback**: If AST parsing fails (complex SQL, dialect edge cases), a regex-based extractor finds `FROM`/`JOIN` table references. Column references are not extracted in regex mode (the `Columns` array will be empty).
|
|
400
|
+
|
|
401
|
+
3. **Nunjucks Preprocessing**: `ParseWithTemplatePreprocessing` first renders the SQL through a Nunjucks environment with placeholder filters (`sqlString` → `'placeholder'`, `sqlNumber` → `0`, etc.), stripping template blocks while preserving the SQL structure. If Nunjucks rendering fails, it falls back to regex-based template removal.
|
|
402
|
+
|
|
267
403
|
## Troubleshooting
|
|
268
404
|
|
|
269
405
|
### Entity subclass not being used
|
|
@@ -32,6 +32,15 @@ export declare class ApplicationEntityServerEntity extends ApplicationEntity {
|
|
|
32
32
|
* Example: "my-app" -> "my-app-2" if "my-app" already exists.
|
|
33
33
|
*/
|
|
34
34
|
protected ensureUniqueSlug(baseSlug: string): Promise<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Calculates the appropriate Sequence value for a new UserApplication record
|
|
37
|
+
* using the application's DefaultSequence to determine placement.
|
|
38
|
+
* If DefaultSequence fits between existing sequences, it's used directly.
|
|
39
|
+
* Otherwise, the app is appended after the highest existing sequence.
|
|
40
|
+
*/
|
|
41
|
+
protected calculateSequenceFromDefault(existingUserApps: {
|
|
42
|
+
Sequence: number;
|
|
43
|
+
}[]): number;
|
|
35
44
|
/**
|
|
36
45
|
* Creates UserApplication records for all users in the system for this application
|
|
37
46
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApplicationEntity.server.d.ts","sourceRoot":"","sources":["../../src/custom/ApplicationEntity.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,UAAU,EAAE,iBAAiB,EAA6D,MAAM,sBAAsB,CAAC;AAClK,OAAO,EAAE,iBAAiB,EAAyB,MAAM,+BAA+B,CAAC;AAGzF;;;;;;;GAOG;AACH,qBACa,6BAA8B,SAAQ,iBAAiB;gBACpD,MAAM,EAAE,UAAU;IAS9B;;;;OAIG;IACmB,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IA+CzE;;;;OAIG;cACa,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBjD;;;OAGG;IACH,SAAS,CAAC,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAgBpD;;;OAGG;cACa,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqCnE;;OAEG;cACa,iCAAiC,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ApplicationEntity.server.d.ts","sourceRoot":"","sources":["../../src/custom/ApplicationEntity.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,UAAU,EAAE,iBAAiB,EAA6D,MAAM,sBAAsB,CAAC;AAClK,OAAO,EAAE,iBAAiB,EAAyB,MAAM,+BAA+B,CAAC;AAGzF;;;;;;;GAOG;AACH,qBACa,6BAA8B,SAAQ,iBAAiB;gBACpD,MAAM,EAAE,UAAU;IAS9B;;;;OAIG;IACmB,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IA+CzE;;;;OAIG;cACa,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBjD;;;OAGG;IACH,SAAS,CAAC,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAgBpD;;;OAGG;cACa,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqCnE;;;;;OAKG;IACH,SAAS,CAAC,4BAA4B,CAAC,gBAAgB,EAAE;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,EAAE,GAAG,MAAM;IAkBtF;;OAEG;cACa,iCAAiC,IAAI,OAAO,CAAC,IAAI,CAAC;CA4ErE"}
|
|
@@ -144,6 +144,26 @@ let ApplicationEntityServerEntity = class ApplicationEntityServerEntity extends
|
|
|
144
144
|
}
|
|
145
145
|
return `${baseSlug}-${suffix}`;
|
|
146
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Calculates the appropriate Sequence value for a new UserApplication record
|
|
149
|
+
* using the application's DefaultSequence to determine placement.
|
|
150
|
+
* If DefaultSequence fits between existing sequences, it's used directly.
|
|
151
|
+
* Otherwise, the app is appended after the highest existing sequence.
|
|
152
|
+
*/
|
|
153
|
+
calculateSequenceFromDefault(existingUserApps) {
|
|
154
|
+
const defaultSeq = this.DefaultSequence ?? 100;
|
|
155
|
+
if (existingUserApps.length === 0) {
|
|
156
|
+
return defaultSeq;
|
|
157
|
+
}
|
|
158
|
+
// Check if DefaultSequence conflicts with an existing sequence
|
|
159
|
+
const existingSequences = new Set(existingUserApps.map(ua => ua.Sequence || 0));
|
|
160
|
+
if (!existingSequences.has(defaultSeq)) {
|
|
161
|
+
return defaultSeq;
|
|
162
|
+
}
|
|
163
|
+
// Conflict exists — append after the highest existing sequence
|
|
164
|
+
const maxSequence = Math.max(...existingSequences);
|
|
165
|
+
return maxSequence + 1;
|
|
166
|
+
}
|
|
147
167
|
/**
|
|
148
168
|
* Creates UserApplication records for all users in the system for this application
|
|
149
169
|
*/
|
|
@@ -184,18 +204,15 @@ let ApplicationEntityServerEntity = class ApplicationEntityServerEntity extends
|
|
|
184
204
|
LogStatus(`UserApplication already exists for user ${user.Name}, skipping`);
|
|
185
205
|
continue;
|
|
186
206
|
}
|
|
187
|
-
// Calculate
|
|
207
|
+
// Calculate sequence using DefaultSequence to place the app in its intended position
|
|
188
208
|
const userApps = allUserApps.filter((ua) => ua.UserID === user.ID);
|
|
189
|
-
|
|
190
|
-
if (userApps.length > 0) {
|
|
191
|
-
maxSequence = Math.max(...userApps.map((ua) => ua.Sequence || 0));
|
|
192
|
-
}
|
|
209
|
+
const sequence = this.calculateSequenceFromDefault(userApps);
|
|
193
210
|
// Create new UserApplication record
|
|
194
211
|
const userApp = await md.GetEntityObject('User Applications', this.ContextCurrentUser);
|
|
195
212
|
userApp.NewRecord();
|
|
196
213
|
userApp.UserID = user.ID;
|
|
197
214
|
userApp.ApplicationID = this.ID;
|
|
198
|
-
userApp.Sequence =
|
|
215
|
+
userApp.Sequence = sequence;
|
|
199
216
|
userApp.IsActive = true;
|
|
200
217
|
const saveResult = await userApp.Save();
|
|
201
218
|
if (saveResult) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApplicationEntity.server.js","sourceRoot":"","sources":["../../src/custom/ApplicationEntity.server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ApplicationEntity.server.js","sourceRoot":"","sources":["../../src/custom/ApplicationEntity.server.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,28 +32,6 @@ export declare class QueryEntityExtended extends QueryEntity {
|
|
|
32
32
|
* Uses node-sql-parser for robust SQL parsing after pre-processing Nunjucks templates.
|
|
33
33
|
*/
|
|
34
34
|
private extractEntityMetadataFromSQL;
|
|
35
|
-
/**
|
|
36
|
-
* Pre-processes Nunjucks templates in SQL to create valid SQL for parsing.
|
|
37
|
-
* Replaces Nunjucks syntax with placeholder values.
|
|
38
|
-
*/
|
|
39
|
-
private preProcessNunjucksForParsing;
|
|
40
|
-
/**
|
|
41
|
-
* Recursively extracts table references and column references from SQL AST.
|
|
42
|
-
*/
|
|
43
|
-
private extractFromAST;
|
|
44
|
-
/**
|
|
45
|
-
* Extracts table information from a FROM clause item, handling tables and JOINs.
|
|
46
|
-
*/
|
|
47
|
-
private extractTableFromItem;
|
|
48
|
-
/**
|
|
49
|
-
* Extracts column references from an expression node.
|
|
50
|
-
* Also extracts tables from subqueries found in expressions (e.g., EXISTS, IN subqueries).
|
|
51
|
-
*/
|
|
52
|
-
private extractColumnReferences;
|
|
53
|
-
/**
|
|
54
|
-
* Fallback regex-based extraction for when SQL parsing fails.
|
|
55
|
-
*/
|
|
56
|
-
private extractEntityMetadataFromSQLRegex;
|
|
57
35
|
private syncQueryParameters;
|
|
58
36
|
private removeAllQueryParameters;
|
|
59
37
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryEntity.server.d.ts","sourceRoot":"","sources":["../../src/custom/QueryEntity.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,YAAY,EAAE,iBAAiB,EAAyC,eAAe,EAAE,cAAc,EAAE,kBAAkB,EAAE,mBAAmB,EAAW,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACpO,OAAO,EAAE,WAAW,EAA6D,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"QueryEntity.server.d.ts","sourceRoot":"","sources":["../../src/custom/QueryEntity.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,YAAY,EAAE,iBAAiB,EAAyC,eAAe,EAAE,cAAc,EAAE,kBAAkB,EAAE,mBAAmB,EAAW,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACpO,OAAO,EAAE,WAAW,EAA6D,MAAM,+BAA+B,CAAC;AAsCvH,qBACa,mBAAoB,SAAQ,WAAW;IAChD,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,iBAAiB,CAA6B;IAEtD,IAAW,aAAa,IAAI,eAAe,EAAE,CAE5C;IAED,IAAW,WAAW,IAAI,cAAc,EAAE,CAEzC;IAED,IAAW,eAAe,IAAI,kBAAkB,EAAE,CAEjD;IAED,IAAW,gBAAgB,IAAI,mBAAmB,EAAE,CAEnD;IAED;;;;OAIG;cACsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAI7E,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IA4CnD,MAAM,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAqBpE;;;OAGG;YACW,uBAAuB;IAuBrC;;OAEG;YACW,sBAAsB;YAkBtB,kBAAkB;IA+FhC;;;OAGG;YACW,4BAA4B;YA0E5B,mBAAmB;YAoJnB,wBAAwB;IA8BtC;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;YAqDd,eAAe;YA0Kf,iBAAiB;YAsFjB,oBAAoB;YA4BpB,sBAAsB;IA4BrB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,yBAAyB,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAMxE,SAAS,CAAC,YAAY,EAAE,YAAY,EAAE,yBAAyB,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAM7F,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,iBAAiB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAMrF;;;;;OAKG;IACU,sBAAsB,CAAC,aAAa,EAAE,OAAO;CAgB7D"}
|
|
@@ -11,9 +11,7 @@ import { AIEngine } from "@memberjunction/aiengine";
|
|
|
11
11
|
import { AIPromptRunner } from "@memberjunction/ai-prompts";
|
|
12
12
|
import { AIPromptParams } from "@memberjunction/ai-core-plus";
|
|
13
13
|
import { EmbedTextLocalHelper } from "./util.js";
|
|
14
|
-
import
|
|
15
|
-
const { Parser } = NodeSqlParser;
|
|
16
|
-
import * as nunjucks from 'nunjucks';
|
|
14
|
+
import { SQLParser } from "./sql-parser.js";
|
|
17
15
|
let QueryEntityExtended = class QueryEntityExtended extends QueryEntity {
|
|
18
16
|
constructor() {
|
|
19
17
|
super(...arguments);
|
|
@@ -237,69 +235,41 @@ let QueryEntityExtended = class QueryEntityExtended extends QueryEntity {
|
|
|
237
235
|
if (!this.SQL)
|
|
238
236
|
return results;
|
|
239
237
|
try {
|
|
240
|
-
//
|
|
241
|
-
const
|
|
242
|
-
//
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
catch (parseError) {
|
|
249
|
-
// If parsing fails, fall back to regex-based extraction
|
|
250
|
-
console.warn(`SQL parsing failed, falling back to regex: ${parseError.message}`);
|
|
251
|
-
return this.extractEntityMetadataFromSQLRegex();
|
|
252
|
-
}
|
|
253
|
-
// Extract table references and column references from AST
|
|
254
|
-
const tableAliasMap = new Map();
|
|
255
|
-
const referencedColumns = new Set();
|
|
256
|
-
// Process AST (handle both single statement and array of statements)
|
|
257
|
-
const statements = Array.isArray(ast) ? ast : [ast];
|
|
258
|
-
for (const statement of statements) {
|
|
259
|
-
this.extractFromAST(statement, tableAliasMap, referencedColumns);
|
|
260
|
-
}
|
|
261
|
-
// Build entity metadata with only referenced fields
|
|
262
|
-
const processedEntities = new Set();
|
|
263
|
-
for (const [alias, tableInfo] of tableAliasMap) {
|
|
264
|
-
const schemaName = tableInfo.schemaName || 'dbo';
|
|
265
|
-
const tableName = tableInfo.tableName;
|
|
266
|
-
const key = `${schemaName.toLowerCase()}.${tableName.toLowerCase()}`;
|
|
267
|
-
if (processedEntities.has(key))
|
|
268
|
-
continue;
|
|
269
|
-
processedEntities.add(key);
|
|
270
|
-
// Find matching entity in metadata
|
|
271
|
-
const matchingEntity = md.Entities.find(e => (e.BaseView.toLowerCase() === tableName.toLowerCase() ||
|
|
272
|
-
e.BaseTable.toLowerCase() === tableName.toLowerCase()) &&
|
|
273
|
-
e.SchemaName.toLowerCase() === schemaName.toLowerCase());
|
|
238
|
+
// Use the shared SQLParser with Nunjucks preprocessing
|
|
239
|
+
const parseResult = SQLParser.ParseWithTemplatePreprocessing(this.SQL);
|
|
240
|
+
// Cross-reference parsed tables against entity metadata
|
|
241
|
+
for (const tableRef of parseResult.Tables) {
|
|
242
|
+
const matchingEntity = md.Entities.find(e => (e.BaseView.toLowerCase() === tableRef.TableName.toLowerCase() ||
|
|
243
|
+
e.BaseTable.toLowerCase() === tableRef.TableName.toLowerCase()) &&
|
|
244
|
+
e.SchemaName.toLowerCase() === tableRef.SchemaName.toLowerCase());
|
|
274
245
|
if (matchingEntity) {
|
|
275
|
-
// Get fields from the entity's Fields property
|
|
276
|
-
const entityFields = matchingEntity.Fields;
|
|
277
246
|
// Filter to fields that are actually referenced in the SQL
|
|
278
|
-
|
|
279
|
-
const relevantFields = entityFields
|
|
247
|
+
const relevantFields = matchingEntity.Fields
|
|
280
248
|
.filter(f => {
|
|
281
249
|
const fieldLower = f.Name.toLowerCase();
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
// Match: fieldName, alias.fieldName, tableName.fieldName
|
|
286
|
-
if (colLower === fieldLower ||
|
|
287
|
-
colLower === `${alias.toLowerCase()}.${fieldLower}` ||
|
|
288
|
-
colLower === `${tableName.toLowerCase()}.${fieldLower}` ||
|
|
289
|
-
colLower.endsWith(`.${fieldLower}`)) {
|
|
250
|
+
for (const colRef of parseResult.Columns) {
|
|
251
|
+
const colLower = colRef.ColumnName.toLowerCase();
|
|
252
|
+
if (colLower === fieldLower)
|
|
290
253
|
return true;
|
|
254
|
+
// Check if column qualifier matches table alias or name
|
|
255
|
+
if (colRef.TableQualifier) {
|
|
256
|
+
const qualLower = colRef.TableQualifier.toLowerCase();
|
|
257
|
+
if ((qualLower === tableRef.Alias.toLowerCase() ||
|
|
258
|
+
qualLower === tableRef.TableName.toLowerCase()) &&
|
|
259
|
+
colLower === fieldLower) {
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
291
262
|
}
|
|
292
263
|
}
|
|
293
264
|
// Also include primary keys as they're always useful context
|
|
294
265
|
return f.IsPrimaryKey;
|
|
295
266
|
})
|
|
296
|
-
.slice(0, 20)
|
|
267
|
+
.slice(0, 20)
|
|
297
268
|
.map(f => ({
|
|
298
269
|
name: f.Name,
|
|
299
270
|
type: f.Type,
|
|
300
271
|
isPrimaryKey: f.IsPrimaryKey
|
|
301
272
|
}));
|
|
302
|
-
// Only include entity if we found relevant fields
|
|
303
273
|
if (relevantFields.length > 0) {
|
|
304
274
|
results.push({
|
|
305
275
|
name: matchingEntity.Name,
|
|
@@ -313,225 +283,9 @@ let QueryEntityExtended = class QueryEntityExtended extends QueryEntity {
|
|
|
313
283
|
return results;
|
|
314
284
|
}
|
|
315
285
|
catch (error) {
|
|
316
|
-
console.warn(`Error in extractEntityMetadataFromSQL: ${error
|
|
317
|
-
return this.extractEntityMetadataFromSQLRegex();
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Pre-processes Nunjucks templates in SQL to create valid SQL for parsing.
|
|
322
|
-
* Replaces Nunjucks syntax with placeholder values.
|
|
323
|
-
*/
|
|
324
|
-
preProcessNunjucksForParsing(sql) {
|
|
325
|
-
// Create a Nunjucks environment that won't throw on undefined
|
|
326
|
-
const env = new nunjucks.Environment(null, {
|
|
327
|
-
autoescape: false,
|
|
328
|
-
throwOnUndefined: false
|
|
329
|
-
});
|
|
330
|
-
// Add placeholder filters that return safe SQL values
|
|
331
|
-
env.addFilter('sqlString', () => "'placeholder'");
|
|
332
|
-
env.addFilter('sqlNumber', () => '0');
|
|
333
|
-
env.addFilter('sqlDate', () => "'2000-01-01'");
|
|
334
|
-
env.addFilter('sqlIn', () => "('placeholder')");
|
|
335
|
-
env.addFilter('sqlIdentifier', (val) => val || 'placeholder');
|
|
336
|
-
env.addFilter('sqlNoKeywordsExpression', (val) => val || 'placeholder');
|
|
337
|
-
env.addFilter('default', (val, defaultVal) => val || defaultVal || 'placeholder');
|
|
338
|
-
env.addFilter('safe', (val) => val || 'placeholder');
|
|
339
|
-
env.addFilter('dump', (val) => JSON.stringify(val || {}));
|
|
340
|
-
try {
|
|
341
|
-
// Try to render the template with placeholder data
|
|
342
|
-
// This handles most Nunjucks constructs
|
|
343
|
-
const rendered = env.renderString(sql, {});
|
|
344
|
-
return rendered;
|
|
345
|
-
}
|
|
346
|
-
catch (e) {
|
|
347
|
-
// If rendering fails, do manual regex replacement
|
|
348
|
-
let processed = sql;
|
|
349
|
-
// Replace {{ variable | filter }} patterns
|
|
350
|
-
processed = processed.replace(/\{\{\s*[\w.]+\s*\|\s*sqlString\s*\}\}/g, "'placeholder'");
|
|
351
|
-
processed = processed.replace(/\{\{\s*[\w.]+\s*\|\s*sqlNumber\s*\}\}/g, '0');
|
|
352
|
-
processed = processed.replace(/\{\{\s*[\w.]+\s*\|\s*sqlDate\s*\}\}/g, "'2000-01-01'");
|
|
353
|
-
processed = processed.replace(/\{\{\s*[\w.]+\s*\|\s*sqlIn\s*\}\}/g, "('placeholder')");
|
|
354
|
-
processed = processed.replace(/\{\{\s*[\w.]+\s*\|\s*sqlIdentifier\s*\}\}/g, 'placeholder');
|
|
355
|
-
processed = processed.replace(/\{\{\s*[\w.]+\s*[^}]*\}\}/g, "'placeholder'");
|
|
356
|
-
// Remove {% if %}, {% endif %}, {% for %}, {% endfor %} blocks
|
|
357
|
-
// Keep the content between them
|
|
358
|
-
processed = processed.replace(/\{%\s*if\s+[^%]+%\}/g, '');
|
|
359
|
-
processed = processed.replace(/\{%\s*endif\s*%\}/g, '');
|
|
360
|
-
processed = processed.replace(/\{%\s*else\s*%\}/g, '');
|
|
361
|
-
processed = processed.replace(/\{%\s*elif\s+[^%]+%\}/g, '');
|
|
362
|
-
processed = processed.replace(/\{%\s*for\s+[^%]+%\}/g, '');
|
|
363
|
-
processed = processed.replace(/\{%\s*endfor\s*%\}/g, '');
|
|
364
|
-
processed = processed.replace(/\{%\s*set\s+[^%]+%\}/g, '');
|
|
365
|
-
processed = processed.replace(/\{#[^#]*#\}/g, ''); // Comments
|
|
366
|
-
return processed;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Recursively extracts table references and column references from SQL AST.
|
|
371
|
-
*/
|
|
372
|
-
extractFromAST(node, tableAliasMap, referencedColumns) {
|
|
373
|
-
if (!node || typeof node !== 'object')
|
|
374
|
-
return;
|
|
375
|
-
// Handle CTEs (WITH clause) - process these first as they define tables used later
|
|
376
|
-
if (node.with) {
|
|
377
|
-
for (const cte of Array.isArray(node.with) ? node.with : [node.with]) {
|
|
378
|
-
// CTE structure can vary - check multiple possible locations
|
|
379
|
-
if (cte.stmt) {
|
|
380
|
-
// stmt might be the AST directly or contain ast property
|
|
381
|
-
const cteAst = cte.stmt.ast || cte.stmt;
|
|
382
|
-
this.extractFromAST(cteAst, tableAliasMap, referencedColumns);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
// Extract FROM clause tables (including JOINs)
|
|
387
|
-
if (node.from) {
|
|
388
|
-
for (const fromItem of Array.isArray(node.from) ? node.from : [node.from]) {
|
|
389
|
-
this.extractTableFromItem(fromItem, tableAliasMap, referencedColumns);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
// Extract column references from SELECT
|
|
393
|
-
if (node.columns) {
|
|
394
|
-
for (const col of Array.isArray(node.columns) ? node.columns : [node.columns]) {
|
|
395
|
-
if (col === '*')
|
|
396
|
-
continue;
|
|
397
|
-
if (col.expr) {
|
|
398
|
-
this.extractColumnReferences(col.expr, referencedColumns, tableAliasMap);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
// Extract column references from WHERE (and tables from subqueries like EXISTS, IN)
|
|
403
|
-
if (node.where) {
|
|
404
|
-
this.extractColumnReferences(node.where, referencedColumns, tableAliasMap);
|
|
405
|
-
}
|
|
406
|
-
// Extract column references from GROUP BY
|
|
407
|
-
if (node.groupby) {
|
|
408
|
-
const groupItems = node.groupby.columns || node.groupby;
|
|
409
|
-
for (const group of Array.isArray(groupItems) ? groupItems : [groupItems]) {
|
|
410
|
-
this.extractColumnReferences(group, referencedColumns, tableAliasMap);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
// Extract column references from ORDER BY
|
|
414
|
-
if (node.orderby) {
|
|
415
|
-
for (const order of Array.isArray(node.orderby) ? node.orderby : [node.orderby]) {
|
|
416
|
-
this.extractColumnReferences(order.expr || order, referencedColumns, tableAliasMap);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
// Handle UNION/INTERSECT/EXCEPT - the next query is in _next
|
|
420
|
-
if (node._next) {
|
|
421
|
-
this.extractFromAST(node._next, tableAliasMap, referencedColumns);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* Extracts table information from a FROM clause item, handling tables and JOINs.
|
|
426
|
-
*/
|
|
427
|
-
extractTableFromItem(fromItem, tableAliasMap, referencedColumns) {
|
|
428
|
-
if (!fromItem)
|
|
429
|
-
return;
|
|
430
|
-
// Direct table reference
|
|
431
|
-
if (fromItem.table) {
|
|
432
|
-
const alias = fromItem.as || fromItem.table;
|
|
433
|
-
tableAliasMap.set(alias, {
|
|
434
|
-
schemaName: fromItem.db || 'dbo',
|
|
435
|
-
tableName: fromItem.table
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
// Handle subqueries in FROM (derived tables)
|
|
439
|
-
if (fromItem.expr) {
|
|
440
|
-
// The subquery AST is inside expr.ast
|
|
441
|
-
const subqueryAst = fromItem.expr.ast || fromItem.expr;
|
|
442
|
-
this.extractFromAST(subqueryAst, tableAliasMap, referencedColumns);
|
|
443
|
-
}
|
|
444
|
-
// Note: In node-sql-parser, JOINs are represented as separate items in the from array
|
|
445
|
-
// with a 'join' property that's a string (e.g., "INNER JOIN", "LEFT JOIN")
|
|
446
|
-
// So no need to recurse into join - each table is already in the from array
|
|
447
|
-
// Extract column references from ON conditions
|
|
448
|
-
if (fromItem.on) {
|
|
449
|
-
this.extractColumnReferences(fromItem.on, referencedColumns, tableAliasMap);
|
|
450
|
-
}
|
|
451
|
-
// Some parsers use 'using' for join conditions
|
|
452
|
-
if (fromItem.using) {
|
|
453
|
-
for (const col of Array.isArray(fromItem.using) ? fromItem.using : [fromItem.using]) {
|
|
454
|
-
if (typeof col === 'string') {
|
|
455
|
-
referencedColumns.add(col);
|
|
456
|
-
}
|
|
457
|
-
else if (col.column) {
|
|
458
|
-
referencedColumns.add(col.column);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
/**
|
|
464
|
-
* Extracts column references from an expression node.
|
|
465
|
-
* Also extracts tables from subqueries found in expressions (e.g., EXISTS, IN subqueries).
|
|
466
|
-
*/
|
|
467
|
-
extractColumnReferences(expr, referencedColumns, tableAliasMap) {
|
|
468
|
-
if (!expr || typeof expr !== 'object')
|
|
469
|
-
return;
|
|
470
|
-
if (expr.type === 'column_ref') {
|
|
471
|
-
const colName = expr.table ? `${expr.table}.${expr.column}` : expr.column;
|
|
472
|
-
referencedColumns.add(colName);
|
|
473
|
-
}
|
|
474
|
-
// Handle subqueries in expressions (EXISTS, IN, scalar subqueries)
|
|
475
|
-
if (expr.ast && tableAliasMap) {
|
|
476
|
-
this.extractFromAST(expr.ast, tableAliasMap, referencedColumns);
|
|
477
|
-
}
|
|
478
|
-
// Recursively process nested expressions
|
|
479
|
-
if (expr.left)
|
|
480
|
-
this.extractColumnReferences(expr.left, referencedColumns, tableAliasMap);
|
|
481
|
-
if (expr.right)
|
|
482
|
-
this.extractColumnReferences(expr.right, referencedColumns, tableAliasMap);
|
|
483
|
-
if (expr.args) {
|
|
484
|
-
const args = expr.args.value || expr.args;
|
|
485
|
-
for (const arg of Array.isArray(args) ? args : [args]) {
|
|
486
|
-
this.extractColumnReferences(arg, referencedColumns, tableAliasMap);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
if (expr.expr)
|
|
490
|
-
this.extractColumnReferences(expr.expr, referencedColumns, tableAliasMap);
|
|
491
|
-
}
|
|
492
|
-
/**
|
|
493
|
-
* Fallback regex-based extraction for when SQL parsing fails.
|
|
494
|
-
*/
|
|
495
|
-
extractEntityMetadataFromSQLRegex() {
|
|
496
|
-
const md = this.ProviderToUse;
|
|
497
|
-
const results = [];
|
|
498
|
-
if (!this.SQL)
|
|
286
|
+
console.warn(`Error in extractEntityMetadataFromSQL: ${error}`);
|
|
499
287
|
return results;
|
|
500
|
-
// Simple regex to find schema.table or schema.view references in SQL
|
|
501
|
-
const tablePattern = /(?:FROM|JOIN|INTO)\s+(?:\[?(\w+)\]?\.)?\[?(\w+)\]?(?:\s+(?:AS\s+)?(\w+))?/gi;
|
|
502
|
-
const matches = [...this.SQL.matchAll(tablePattern)];
|
|
503
|
-
const processedViews = new Set();
|
|
504
|
-
for (const match of matches) {
|
|
505
|
-
const schemaName = match[1] || 'dbo';
|
|
506
|
-
const viewOrTable = match[2];
|
|
507
|
-
const key = `${schemaName.toLowerCase()}.${viewOrTable.toLowerCase()}`;
|
|
508
|
-
if (processedViews.has(key))
|
|
509
|
-
continue;
|
|
510
|
-
processedViews.add(key);
|
|
511
|
-
const matchingEntity = md.Entities.find(e => (e.BaseView.toLowerCase() === viewOrTable.toLowerCase() ||
|
|
512
|
-
e.BaseTable.toLowerCase() === viewOrTable.toLowerCase()) &&
|
|
513
|
-
e.SchemaName.toLowerCase() === schemaName.toLowerCase());
|
|
514
|
-
if (matchingEntity) {
|
|
515
|
-
// Get fields from the entity's Fields property
|
|
516
|
-
const entityFields = matchingEntity.Fields;
|
|
517
|
-
// Include primary keys and fields ending in ID for fallback
|
|
518
|
-
const relevantFields = entityFields
|
|
519
|
-
.filter(f => f.IsPrimaryKey || f.Name.endsWith('ID'))
|
|
520
|
-
.slice(0, 15)
|
|
521
|
-
.map(f => ({
|
|
522
|
-
name: f.Name,
|
|
523
|
-
type: f.Type,
|
|
524
|
-
isPrimaryKey: f.IsPrimaryKey
|
|
525
|
-
}));
|
|
526
|
-
results.push({
|
|
527
|
-
name: matchingEntity.Name,
|
|
528
|
-
schemaName: matchingEntity.SchemaName,
|
|
529
|
-
baseView: matchingEntity.BaseView,
|
|
530
|
-
fields: relevantFields
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
288
|
}
|
|
534
|
-
return results;
|
|
535
289
|
}
|
|
536
290
|
async syncQueryParameters(extractedParams) {
|
|
537
291
|
// Use the entity's provider instead of creating new Metadata instance
|