@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 CHANGED
@@ -1,19 +1,38 @@
1
- # MemberJunction Core Entities Server
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
- - Direct database access
9
- - File system operations
10
- - Server-side API integrations
11
- - Complex business logic that should only run on the server
12
- - Automatic creation/management of related entities
13
-
14
- ## Purpose
15
-
16
- While the base `@memberjunction/core-entities` package provides entity classes that work in any JavaScript environment (browser or server), some entity operations require server-specific capabilities. This package provides those extended implementations.
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;CA+ErE"}
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 max sequence for this user (client-side)
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
- let maxSequence = 0;
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 = maxSequence + 1;
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;AAwCvH,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;IA4G1C;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAkDpC;;OAEG;IACH,OAAO,CAAC,cAAc;IA8DtB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA4C5B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IA6B/B;;OAEG;IACH,OAAO,CAAC,iCAAiC;YA8D3B,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"}
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 NodeSqlParser from 'node-sql-parser';
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
- // Pre-process Nunjucks templates to get valid SQL for parsing
241
- const processedSQL = this.preProcessNunjucksForParsing(this.SQL);
242
- // Parse the SQL using node-sql-parser
243
- const parser = new Parser();
244
- let ast;
245
- try {
246
- ast = parser.astify(processedSQL, { database: 'TransactSQL' });
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
- // Check both the field name directly and with table alias prefix
279
- const relevantFields = entityFields
247
+ const relevantFields = matchingEntity.Fields
280
248
  .filter(f => {
281
249
  const fieldLower = f.Name.toLowerCase();
282
- // Check if this field is referenced directly or with any alias
283
- for (const colRef of referencedColumns) {
284
- const colLower = colRef.toLowerCase();
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) // Limit to 20 most relevant fields per entity
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.message}`);
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