forge-sql-orm 2.1.12 → 2.1.14

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.
Files changed (79) hide show
  1. package/README.md +922 -549
  2. package/dist/core/ForgeSQLAnalyseOperations.d.ts.map +1 -1
  3. package/dist/core/ForgeSQLAnalyseOperations.js +257 -0
  4. package/dist/core/ForgeSQLAnalyseOperations.js.map +1 -0
  5. package/dist/core/ForgeSQLCacheOperations.js +172 -0
  6. package/dist/core/ForgeSQLCacheOperations.js.map +1 -0
  7. package/dist/core/ForgeSQLCrudOperations.js +349 -0
  8. package/dist/core/ForgeSQLCrudOperations.js.map +1 -0
  9. package/dist/core/ForgeSQLORM.d.ts +29 -1
  10. package/dist/core/ForgeSQLORM.d.ts.map +1 -1
  11. package/dist/core/ForgeSQLORM.js +1252 -0
  12. package/dist/core/ForgeSQLORM.js.map +1 -0
  13. package/dist/core/ForgeSQLQueryBuilder.d.ts +179 -1
  14. package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
  15. package/dist/core/ForgeSQLQueryBuilder.js +77 -0
  16. package/dist/core/ForgeSQLQueryBuilder.js.map +1 -0
  17. package/dist/core/ForgeSQLSelectOperations.js +81 -0
  18. package/dist/core/ForgeSQLSelectOperations.js.map +1 -0
  19. package/dist/core/Rovo.d.ts +116 -0
  20. package/dist/core/Rovo.d.ts.map +1 -0
  21. package/dist/core/Rovo.js +647 -0
  22. package/dist/core/Rovo.js.map +1 -0
  23. package/dist/core/SystemTables.js +258 -0
  24. package/dist/core/SystemTables.js.map +1 -0
  25. package/dist/index.js +30 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -1
  28. package/dist/lib/drizzle/extensions/additionalActions.js +527 -0
  29. package/dist/lib/drizzle/extensions/additionalActions.js.map +1 -0
  30. package/dist/utils/cacheContextUtils.d.ts.map +1 -1
  31. package/dist/utils/cacheContextUtils.js +198 -0
  32. package/dist/utils/cacheContextUtils.js.map +1 -0
  33. package/dist/utils/cacheUtils.d.ts.map +1 -1
  34. package/dist/utils/cacheUtils.js +383 -0
  35. package/dist/utils/cacheUtils.js.map +1 -0
  36. package/dist/utils/forgeDriver.d.ts.map +1 -1
  37. package/dist/utils/forgeDriver.js +139 -0
  38. package/dist/utils/forgeDriver.js.map +1 -0
  39. package/dist/utils/forgeDriverProxy.js +68 -0
  40. package/dist/utils/forgeDriverProxy.js.map +1 -0
  41. package/dist/utils/metadataContextUtils.d.ts.map +1 -1
  42. package/dist/utils/metadataContextUtils.js +26 -0
  43. package/dist/utils/metadataContextUtils.js.map +1 -0
  44. package/dist/utils/requestTypeContextUtils.js +10 -0
  45. package/dist/utils/requestTypeContextUtils.js.map +1 -0
  46. package/dist/utils/sqlHints.js +52 -0
  47. package/dist/utils/sqlHints.js.map +1 -0
  48. package/dist/utils/sqlUtils.d.ts.map +1 -1
  49. package/dist/utils/sqlUtils.js +590 -0
  50. package/dist/utils/sqlUtils.js.map +1 -0
  51. package/dist/webtriggers/applyMigrationsWebTrigger.js +77 -0
  52. package/dist/webtriggers/applyMigrationsWebTrigger.js.map +1 -0
  53. package/dist/webtriggers/clearCacheSchedulerTrigger.js +83 -0
  54. package/dist/webtriggers/clearCacheSchedulerTrigger.js.map +1 -0
  55. package/dist/webtriggers/dropMigrationWebTrigger.js +54 -0
  56. package/dist/webtriggers/dropMigrationWebTrigger.js.map +1 -0
  57. package/dist/webtriggers/dropTablesMigrationWebTrigger.js +54 -0
  58. package/dist/webtriggers/dropTablesMigrationWebTrigger.js.map +1 -0
  59. package/dist/webtriggers/fetchSchemaWebTrigger.js +82 -0
  60. package/dist/webtriggers/fetchSchemaWebTrigger.js.map +1 -0
  61. package/dist/webtriggers/index.js +40 -0
  62. package/dist/webtriggers/index.js.map +1 -0
  63. package/dist/webtriggers/slowQuerySchedulerTrigger.js +80 -0
  64. package/dist/webtriggers/slowQuerySchedulerTrigger.js.map +1 -0
  65. package/package.json +31 -25
  66. package/src/core/ForgeSQLAnalyseOperations.ts +3 -2
  67. package/src/core/ForgeSQLORM.ts +64 -0
  68. package/src/core/ForgeSQLQueryBuilder.ts +200 -1
  69. package/src/core/Rovo.ts +765 -0
  70. package/src/lib/drizzle/extensions/additionalActions.ts +11 -0
  71. package/src/utils/cacheContextUtils.ts +9 -6
  72. package/src/utils/cacheUtils.ts +6 -4
  73. package/src/utils/forgeDriver.ts +3 -7
  74. package/src/utils/metadataContextUtils.ts +1 -3
  75. package/src/utils/sqlUtils.ts +33 -34
  76. package/dist/ForgeSQLORM.js +0 -3922
  77. package/dist/ForgeSQLORM.js.map +0 -1
  78. package/dist/ForgeSQLORM.mjs +0 -3905
  79. package/dist/ForgeSQLORM.mjs.map +0 -1
@@ -0,0 +1,647 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Rovo = void 0;
4
+ const sql_1 = require("@forge/sql");
5
+ const node_sql_parser_1 = require("node-sql-parser");
6
+ const table_1 = require("drizzle-orm/table");
7
+ /**
8
+ * Implementation of RovoIntegrationSetting interface.
9
+ * Stores configuration for Rovo query execution including user context, table name, and RLS settings.
10
+ *
11
+ * @class RovoIntegrationSettingImpl
12
+ * @implements {RovoIntegrationSetting}
13
+ */
14
+ class RovoIntegrationSettingImpl {
15
+ accountId;
16
+ tableName;
17
+ contextParam;
18
+ rls;
19
+ rlsFields;
20
+ rlsWherePart;
21
+ /**
22
+ * Creates a new RovoIntegrationSettingImpl instance.
23
+ *
24
+ * @param {string} accountId - The account ID of the active user
25
+ * @param {string} tableName - The name of the table to query
26
+ * @param {Record<string, string>} contextParam - Context parameters for query substitution
27
+ * @param {boolean} rls - Whether Row-Level Security is enabled
28
+ * @param {string[]} rlsFields - Array of field names required for RLS validation
29
+ * @param {(alias: string) => string} rlsWherePart - Function that generates WHERE clause for RLS
30
+ */
31
+ constructor(accountId, tableName, contextParam, rls, rlsFields, rlsWherePart) {
32
+ this.accountId = accountId;
33
+ this.tableName = tableName;
34
+ this.contextParam = contextParam;
35
+ this.rls = rls;
36
+ this.rlsFields = rlsFields;
37
+ this.rlsWherePart = rlsWherePart;
38
+ }
39
+ /**
40
+ * Gets the account ID of the active user.
41
+ *
42
+ * @returns {string} The account ID of the active user
43
+ */
44
+ getActiveUser() {
45
+ return this.accountId;
46
+ }
47
+ /**
48
+ * Gets the context parameters for query substitution.
49
+ *
50
+ * @returns {Record<string, string>} Map of parameter names to their values
51
+ */
52
+ getParameters() {
53
+ return this.contextParam;
54
+ }
55
+ /**
56
+ * Gets the name of the table to query.
57
+ *
58
+ * @returns {string} The table name
59
+ */
60
+ getTableName() {
61
+ return this.tableName;
62
+ }
63
+ /**
64
+ * Checks if Row-Level Security is enabled.
65
+ *
66
+ * @returns {boolean} True if RLS is enabled, false otherwise
67
+ */
68
+ isUseRLS() {
69
+ return this.rls;
70
+ }
71
+ /**
72
+ * Gets the list of field names required for RLS validation.
73
+ *
74
+ * @returns {string[]} Array of field names that must be present in SELECT clause for RLS
75
+ */
76
+ userScopeFields() {
77
+ return this.rlsFields;
78
+ }
79
+ /**
80
+ * Generates the WHERE clause for Row-Level Security filtering.
81
+ *
82
+ * @param {string} alias - The table alias to use in the WHERE clause
83
+ * @returns {string} SQL WHERE clause condition for RLS filtering
84
+ */
85
+ userScopeWhere(alias) {
86
+ return this.rlsWherePart(alias);
87
+ }
88
+ }
89
+ /**
90
+ * Builder class for creating RovoIntegrationSetting instances.
91
+ * Provides a fluent API for configuring Rovo query settings including context parameters and RLS.
92
+ *
93
+ * @class RovoIntegrationSettingCreatorImpl
94
+ * @implements {RovoIntegrationSettingCreator}
95
+ */
96
+ class RovoIntegrationSettingCreatorImpl {
97
+ tableName;
98
+ accountId;
99
+ contextParam = {};
100
+ rlsFields = [];
101
+ isUseRls = false;
102
+ isUseRlsConditional = async () => true;
103
+ wherePart = () => "";
104
+ /**
105
+ * Creates a new RovoIntegrationSettingCreatorImpl instance.
106
+ *
107
+ * @param {string} tableName - The name of the table to query
108
+ * @param {string} accountId - The account ID of the active user
109
+ */
110
+ constructor(tableName, accountId) {
111
+ this.tableName = tableName;
112
+ this.accountId = accountId;
113
+ }
114
+ /**
115
+ * Adds a context parameter for query substitution.
116
+ * Context parameters are replaced in the SQL query before execution.
117
+ *
118
+ * @param {string} parameterName - The parameter name to replace in the query
119
+ * @param {string} value - The value to substitute for the parameter
120
+ * @returns {RovoIntegrationSettingCreator} This builder instance for method chaining
121
+ *
122
+ * @example
123
+ * ```typescript
124
+ * builder.addContextParameter('{{projectKey}}', 'PROJ-123');
125
+ * ```
126
+ */
127
+ addContextParameter(parameterName, value) {
128
+ this.contextParam[parameterName] = value;
129
+ return this;
130
+ }
131
+ /**
132
+ * Enables Row-Level Security (RLS) for the query.
133
+ * Returns a RlsSettings builder for configuring RLS options.
134
+ *
135
+ * @returns {RlsSettings} RLS settings builder for configuring security options
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * builder.useRLS()
140
+ * .addRlsColumn(usersTable.id)
141
+ * .addRlsWherePart((alias) => `${alias}.id = '${accountId}'`)
142
+ * .finish();
143
+ * ```
144
+ */
145
+ useRLS() {
146
+ const _this = this;
147
+ /**
148
+ * Internal implementation of RlsSettings interface.
149
+ * Provides fluent API for configuring Row-Level Security settings.
150
+ *
151
+ * @class RlsSettingsImpl
152
+ * @implements {RlsSettings}
153
+ */
154
+ return new (class RlsSettingsImpl {
155
+ isUseRlsConditionalSettings = async () => true;
156
+ rlsFieldsSettings = [];
157
+ wherePartSettings = () => "";
158
+ /**
159
+ * Sets a conditional function to determine if RLS should be applied.
160
+ *
161
+ * @param {() => Promise<boolean>} condition - Async function that returns true if RLS should be enabled
162
+ * @returns {RlsSettings} This builder instance for method chaining
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * .addRlsCondition(async () => {
167
+ * const user = await getUser();
168
+ * return !user.isAdmin;
169
+ * })
170
+ * ```
171
+ */
172
+ addRlsCondition(condition) {
173
+ this.isUseRlsConditionalSettings = condition;
174
+ return this;
175
+ }
176
+ /**
177
+ * Adds a column name that must be present in the SELECT clause for RLS validation.
178
+ *
179
+ * @param {string} columnName - The name of the column to require
180
+ * @returns {RlsSettings} This builder instance for method chaining
181
+ *
182
+ * @example
183
+ * ```typescript
184
+ * .addRlsColumnName('userId')
185
+ * ```
186
+ */
187
+ addRlsColumnName(columnName) {
188
+ this.rlsFieldsSettings.push(columnName);
189
+ return this;
190
+ }
191
+ /**
192
+ * Adds a Drizzle column that must be present in the SELECT clause for RLS validation.
193
+ *
194
+ * @param {MySqlColumn} column - The Drizzle column object
195
+ * @returns {RlsSettings} This builder instance for method chaining
196
+ *
197
+ * @example
198
+ * ```typescript
199
+ * .addRlsColumn(usersTable.userId)
200
+ * ```
201
+ */
202
+ addRlsColumn(column) {
203
+ this.rlsFieldsSettings.push(column.name);
204
+ return this;
205
+ }
206
+ /**
207
+ * Sets the WHERE clause function for RLS filtering.
208
+ * The function receives a table alias and should return a SQL WHERE condition.
209
+ *
210
+ * @param {(alias: string) => string} wherePart - Function that generates WHERE clause
211
+ * @returns {RlsSettings} This builder instance for method chaining
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * .addRlsWherePart((alias) => `${alias}.userId = '${accountId}'`)
216
+ * ```
217
+ */
218
+ addRlsWherePart(wherePart) {
219
+ this.wherePartSettings = wherePart;
220
+ return this;
221
+ }
222
+ /**
223
+ * Finishes RLS configuration and returns to the settings builder.
224
+ *
225
+ * @returns {RovoIntegrationSettingCreator} The parent settings builder
226
+ */
227
+ finish() {
228
+ _this.isUseRls = true;
229
+ this.rlsFieldsSettings.forEach((columnName) => _this.rlsFields.push(columnName));
230
+ _this.wherePart = this.wherePartSettings;
231
+ _this.isUseRlsConditional = this.isUseRlsConditionalSettings;
232
+ return _this;
233
+ }
234
+ })();
235
+ }
236
+ /**
237
+ * Builds and returns the RovoIntegrationSetting instance.
238
+ * Evaluates the RLS condition if RLS is enabled.
239
+ *
240
+ * @returns {Promise<RovoIntegrationSetting>} The configured RovoIntegrationSetting instance
241
+ *
242
+ * @example
243
+ * ```typescript
244
+ * const settings = await builder
245
+ * .addContextParameter('{{projectKey}}', 'PROJ-123')
246
+ * .useRLS()
247
+ * .addRlsColumn(usersTable.id)
248
+ * .addRlsWherePart((alias) => `${alias}.id = '${accountId}'`)
249
+ * .finish()
250
+ * .build();
251
+ * ```
252
+ */
253
+ async build() {
254
+ const useRls = this.isUseRls ? await this.isUseRlsConditional() : false;
255
+ return new RovoIntegrationSettingImpl(this.accountId, this.tableName, this.contextParam, useRls, this.rlsFields, this.wherePart);
256
+ }
257
+ }
258
+ /**
259
+ * Main class for Rovo integration - a secure pattern for natural-language analytics in Forge apps.
260
+ *
261
+ * Rovo provides a secure way to execute dynamic SQL queries with comprehensive security validations:
262
+ * - Only SELECT queries are allowed
263
+ * - Queries are restricted to a single table
264
+ * - JOINs, subqueries, and window functions are blocked
265
+ * - Row-Level Security (RLS) support for data isolation
266
+ * - Post-execution validation of query results
267
+ *
268
+ * @class Rovo
269
+ * @implements {RovoIntegration}
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * const rovo = forgeSQL.rovo();
274
+ * const settings = await rovo.rovoSettingBuilder(usersTable, accountId)
275
+ * .useRLS()
276
+ * .addRlsColumn(usersTable.id)
277
+ * .addRlsWherePart((alias) => `${alias}.id = '${accountId}'`)
278
+ * .finish()
279
+ * .build();
280
+ *
281
+ * const result = await rovo.dynamicIsolatedQuery(
282
+ * "SELECT id, name FROM users WHERE status = 'active'",
283
+ * settings
284
+ * );
285
+ * ```
286
+ */
287
+ class Rovo {
288
+ forgeOperations;
289
+ options;
290
+ /**
291
+ * Creates a new Rovo instance.
292
+ *
293
+ * @param {ForgeSqlOperation} forgeSqlOperations - The ForgeSQL operations instance for query analysis
294
+ * @param options - Configuration options for the ORM
295
+ */
296
+ constructor(forgeSqlOperations, options) {
297
+ this.forgeOperations = forgeSqlOperations;
298
+ this.options = options;
299
+ }
300
+ /**
301
+ * Parses SQL query into AST and validates it's a single SELECT statement
302
+ * @param sqlQuery - Normalized SQL query string
303
+ * @returns Parsed AST of the SELECT statement
304
+ * @throws Error if parsing fails or query is not a single SELECT statement
305
+ */
306
+ parseSqlQuery(sqlQuery) {
307
+ const parser = new node_sql_parser_1.Parser();
308
+ let ast;
309
+ try {
310
+ ast = parser.astify(sqlQuery);
311
+ }
312
+ catch (parseError) {
313
+ throw new Error(`SQL parsing error: ${parseError.message || "Invalid SQL syntax"}. Please check your query syntax.`);
314
+ }
315
+ // Validate that query is a SELECT statement
316
+ // Parser can return either an object (single statement) or an array (multiple statements)
317
+ if (Array.isArray(ast)) {
318
+ if (ast.length !== 1 || ast[0].type !== "select") {
319
+ throw new Error("Only a single SELECT query is allowed. Multiple statements or non-SELECT statements are not permitted.");
320
+ }
321
+ return ast[0];
322
+ }
323
+ else if (ast && ast.type === "select") {
324
+ return ast;
325
+ }
326
+ else {
327
+ throw new Error("Only SELECT queries are allowed.");
328
+ }
329
+ }
330
+ /**
331
+ * Recursively extracts all table names from SQL AST node
332
+ * @param node - AST node to extract tables from
333
+ * @returns Array of table names (uppercase)
334
+ */
335
+ extractTables(node) {
336
+ const tables = [];
337
+ if (node.type === "table" || node.type === "dual") {
338
+ if (node.table) {
339
+ const tableName = node.table === "dual" ? "dual" : node.table.name || node.table;
340
+ if (tableName && tableName !== "dual") {
341
+ tables.push(tableName.toUpperCase());
342
+ }
343
+ }
344
+ }
345
+ if (node.from) {
346
+ if (Array.isArray(node.from)) {
347
+ node.from.forEach((fromItem) => {
348
+ tables.push(...this.extractTables(fromItem));
349
+ });
350
+ }
351
+ else {
352
+ tables.push(...this.extractTables(node.from));
353
+ }
354
+ }
355
+ if (node.join) {
356
+ if (Array.isArray(node.join)) {
357
+ node.join.forEach((joinItem) => {
358
+ tables.push(...this.extractTables(joinItem));
359
+ });
360
+ }
361
+ else {
362
+ tables.push(...this.extractTables(node.join));
363
+ }
364
+ }
365
+ return tables;
366
+ }
367
+ /**
368
+ * Recursively checks if AST node contains scalar subqueries
369
+ * @param node - AST node to check
370
+ * @returns true if node contains scalar subquery, false otherwise
371
+ */
372
+ hasScalarSubquery(node) {
373
+ if (!node)
374
+ return false;
375
+ if (node.type === "subquery" || (node.ast && node.ast.type === "select")) {
376
+ return true;
377
+ }
378
+ if (Array.isArray(node)) {
379
+ return node.some((item) => this.hasScalarSubquery(item));
380
+ }
381
+ if (typeof node === "object") {
382
+ return Object.values(node).some((value) => this.hasScalarSubquery(value));
383
+ }
384
+ return false;
385
+ }
386
+ /**
387
+ * Creates a settings builder for Rovo queries using a raw table name.
388
+ *
389
+ * @param {string} tableName - The name of the table to query
390
+ * @param {string} accountId - The account ID of the active user
391
+ * @returns {RovoIntegrationSettingCreator} Builder for configuring Rovo query settings
392
+ *
393
+ * @example
394
+ * ```typescript
395
+ * const builder = rovo.rovoRawSettingBuilder('users', accountId);
396
+ * ```
397
+ */
398
+ rovoRawSettingBuilder(tableName, accountId) {
399
+ return new RovoIntegrationSettingCreatorImpl(tableName, accountId);
400
+ }
401
+ /**
402
+ * Creates a settings builder for Rovo queries using a Drizzle table object.
403
+ *
404
+ * @param {AnyMySqlTable} table - The Drizzle table object
405
+ * @param {string} accountId - The account ID of the active user
406
+ * @returns {RovoIntegrationSettingCreator} Builder for configuring Rovo query settings
407
+ *
408
+ * @example
409
+ * ```typescript
410
+ * const builder = rovo.rovoSettingBuilder(usersTable, accountId);
411
+ * ```
412
+ */
413
+ rovoSettingBuilder(table, accountId) {
414
+ return this.rovoRawSettingBuilder((0, table_1.getTableName)(table), accountId);
415
+ }
416
+ /**
417
+ * Executes a dynamic SQL query with comprehensive security validations.
418
+ *
419
+ * This method performs multiple security checks:
420
+ * 1. Validates that the query is a SELECT statement
421
+ * 2. Ensures the query targets only the specified table
422
+ * 3. Blocks JOINs, subqueries, and window functions
423
+ * 4. Applies Row-Level Security filtering if enabled
424
+ * 5. Validates query results to ensure security fields are present
425
+ *
426
+ * @param {string} dynamicSql - The SQL query to execute (must be a SELECT statement)
427
+ * @param {RovoIntegrationSetting} settings - Configuration settings for the query
428
+ * @returns {Promise<Result<unknown>>} Query execution result with metadata
429
+ * @throws {Error} If the query violates security restrictions
430
+ *
431
+ * @example
432
+ * ```typescript
433
+ * const result = await rovo.dynamicIsolatedQuery(
434
+ * "SELECT id, name, email FROM users WHERE status = 'active' ORDER BY name",
435
+ * settings
436
+ * );
437
+ *
438
+ * console.log(result.rows); // Query results
439
+ * console.log(result.metadata); // Query metadata
440
+ * ```
441
+ */
442
+ async dynamicIsolatedQuery(dynamicSql, settings) {
443
+ const query = dynamicSql;
444
+ const tableName = settings.getTableName();
445
+ const accountId = settings.getActiveUser();
446
+ const parameters = settings.getParameters();
447
+ if (!query || !query.trim()) {
448
+ throw new Error("SQL query is required. Please provide a valid SELECT query.");
449
+ }
450
+ if (!tableName) {
451
+ throw new Error("Table Name is required. Please provide a valid Table Name.");
452
+ }
453
+ // Quick validation: check if query starts with SELECT (case-insensitive)
454
+ // This allows us to fail fast for non-SELECT queries before normalization
455
+ const trimmedQuery = query.trim();
456
+ const quickUpper = trimmedQuery.toUpperCase();
457
+ if (!quickUpper.startsWith("SELECT")) {
458
+ throw new Error("Only SELECT queries are allowed. Data modification operations (INSERT, UPDATE, DELETE, etc.) are not permitted.");
459
+ }
460
+ /**
461
+ * Normalizes SQL query using AST parsing and stringification.
462
+ * This approach is safer than regex-based normalization as it:
463
+ * - Avoids regex backtracking vulnerabilities
464
+ * - Preserves SQL semantics correctly
465
+ * - Handles complex SQL structures properly
466
+ *
467
+ * @param sql - SQL query string to normalize (must be a valid SELECT query)
468
+ * @returns Normalized SQL string
469
+ * @throws Error if parsing fails or query is invalid
470
+ */
471
+ const normalizeSqlString = (sql) => {
472
+ try {
473
+ const parser = new node_sql_parser_1.Parser();
474
+ // Parse SQL to AST
475
+ const ast = parser.astify(sql.trim());
476
+ // Validate it's a SELECT query before normalizing
477
+ if (Array.isArray(ast)) {
478
+ if (ast.length !== 1 || ast[0].type !== "select") {
479
+ throw new Error("Only a single SELECT query is allowed. Multiple statements or non-SELECT statements are not permitted.");
480
+ }
481
+ }
482
+ else if (ast && ast.type !== "select") {
483
+ throw new Error("Only SELECT queries are allowed.");
484
+ }
485
+ // Convert AST back to SQL (this normalizes formatting)
486
+ const normalized = parser.sqlify(Array.isArray(ast) ? ast[0] : ast);
487
+ // trim
488
+ return normalized.trim();
489
+ }
490
+ catch (error) {
491
+ // If it's a validation error we threw, re-throw it
492
+ if (error.message &&
493
+ (error.message.includes("Only") || error.message.includes("single SELECT"))) {
494
+ throw error;
495
+ }
496
+ // For parsing errors, wrap them in a more user-friendly message
497
+ // Check if error is already wrapped to avoid double wrapping
498
+ if (error.message && error.message.includes("SQL parsing error")) {
499
+ throw error;
500
+ }
501
+ throw new Error(`SQL parsing error: ${error.message || "Invalid SQL syntax"}. Please check your query syntax.`);
502
+ }
503
+ };
504
+ let normalized;
505
+ try {
506
+ normalized = normalizeSqlString(trimmedQuery);
507
+ }
508
+ catch (error) {
509
+ // Re-throw validation errors as-is
510
+ if (error.message &&
511
+ (error.message.includes("Only") || error.message.includes("single SELECT"))) {
512
+ throw error;
513
+ }
514
+ // Check if error is already wrapped to avoid double wrapping
515
+ if (error.message && error.message.includes("SQL parsing error")) {
516
+ throw error;
517
+ }
518
+ // For other errors, wrap them
519
+ throw new Error(`SQL parsing error: ${error.message || "Invalid SQL syntax"}. Please check your query syntax.`);
520
+ }
521
+ const upperTableName = tableName.toUpperCase();
522
+ // Validate table name
523
+ // sqlify may add backticks, so we check for both formats: FROM table_name and FROM `table_name`
524
+ const tableNamePattern = new RegExp(`FROM\\s+[\`]?${upperTableName}[\`]?`, "i");
525
+ if (!tableNamePattern.test(normalized)) {
526
+ throw new Error("Queries must target the '" +
527
+ upperTableName +
528
+ "' table only. Other tables are not accessible.");
529
+ }
530
+ if (!accountId) {
531
+ throw new Error("Authentication error: User account ID is missing. Please ensure you are logged in.");
532
+ }
533
+ normalized = normalized.replaceAll("ari:cloud:identity::user/", "");
534
+ Object.entries(parameters).forEach(([key, value]) => {
535
+ normalized = normalized.replaceAll(key, value);
536
+ });
537
+ // Parse SQL query to validate structure before execution
538
+ const selectAst = this.parseSqlQuery(normalized);
539
+ // Extract all tables from the query
540
+ const tablesInQuery = this.extractTables(selectAst);
541
+ const uniqueTables = [...new Set(tablesInQuery)];
542
+ // Check that only table is used
543
+ const invalidTables = uniqueTables.filter((table) => table !== upperTableName);
544
+ if (invalidTables.length > 0) {
545
+ throw new Error(`Security violation: Query references table(s) other than '${tableName}': ${invalidTables.join(", ")}. ` +
546
+ `Only queries against the ${tableName} table are allowed. ` +
547
+ "JOINs, subqueries, or references to other tables are not permitted for security reasons.");
548
+ }
549
+ // Check for scalar subqueries in SELECT columns
550
+ if (selectAst.columns && Array.isArray(selectAst.columns)) {
551
+ const hasSubqueryInColumns = selectAst.columns.some((col) => {
552
+ if (col.expr) {
553
+ return this.hasScalarSubquery(col.expr);
554
+ }
555
+ return this.hasScalarSubquery(col);
556
+ });
557
+ if (hasSubqueryInColumns) {
558
+ throw new Error("Security violation: Scalar subqueries in SELECT columns are not allowed. " +
559
+ "Subqueries can be used to access data from other tables or bypass security restrictions. " +
560
+ "Please rewrite your query without using subqueries in the SELECT clause.");
561
+ }
562
+ }
563
+ // Check for JOIN operations using EXPLAIN
564
+ const explainRows = await this.forgeOperations.analyze().explainRaw(normalized, []);
565
+ const hasJoin = explainRows.some((row) => {
566
+ const info = (row.operatorInfo ?? "").toUpperCase();
567
+ return (info.includes("JOIN") ||
568
+ info.includes("CARTESIAN") ||
569
+ info.includes("NESTED LOOP") ||
570
+ info.includes("HASH JOIN"));
571
+ });
572
+ if (hasJoin) {
573
+ throw new Error("Security violation: JOIN operations are not allowed. " +
574
+ `For security reasons, Rovo analytics only supports queries over the ${tableName} table without joins, subqueries, or references to other tables. ` +
575
+ `Please rewrite your query to use only the ${tableName} table.`);
576
+ }
577
+ // Detect window functions (e.g., COUNT(*) OVER(...), ROW_NUMBER() OVER(...))
578
+ // Window functions are not allowed for security
579
+ // Users should use regular aggregate functions with GROUP BY instead
580
+ const hasWindow = explainRows.some((row) => {
581
+ const id = row.id.toUpperCase();
582
+ const info = (row.operatorInfo ?? "").toUpperCase();
583
+ return id.includes("WINDOW") || info.includes(" OVER(") || info.includes(" OVER()");
584
+ });
585
+ if (hasWindow) {
586
+ throw new Error("Window functions (for example COUNT(*) OVER(...)) are not allowed in Rovo SQL for this app. " +
587
+ "Please rephrase your question so that it uses regular aggregates instead of window functions.");
588
+ }
589
+ // Check for references to other tables in the query execution plan
590
+ // This detects JOINs, subqueries, or any other references to tables other than expected
591
+ const tablesInPlan = explainRows.filter((row) => row.accessObject?.startsWith("table:") &&
592
+ row.accessObject?.toLowerCase() !== "table:" + tableName.toLowerCase());
593
+ if (tablesInPlan.length > 0) {
594
+ throw new Error(`Security violation: Query execution plan detected references to tables other than '${tableName.toLowerCase()}'. ` +
595
+ `Only queries against the ${tableName.toLowerCase()} table are allowed. ` +
596
+ "JOINs, subqueries, or references to other tables are not permitted for security reasons.");
597
+ }
598
+ // row-level security protection
599
+ const isUseRLSFiltering = settings.isUseRLS();
600
+ if (isUseRLSFiltering) {
601
+ if (normalized.endsWith(";")) {
602
+ normalized = normalized.slice(0, -1);
603
+ }
604
+ normalized = `
605
+ SELECT *
606
+ FROM (
607
+ ${normalized}
608
+ ) AS t
609
+ WHERE (${settings.userScopeWhere("t")})
610
+ `;
611
+ }
612
+ if (this.options.logRawSqlQuery) {
613
+ // eslint-disable-next-line no-console
614
+ console.debug("Rovo query: " + normalized);
615
+ }
616
+ const result = await sql_1.sql.executeRaw(normalized);
617
+ // Post-execution validation for non-admin users
618
+ // Verify that required security fields exist and come from table
619
+ // Also ensure all fields with orgTable come from (no JOINs or subqueries)
620
+ if (isUseRLSFiltering && result?.metadata?.fields) {
621
+ const fields = result.metadata.fields;
622
+ settings.userScopeFields().forEach((field) => {
623
+ const actualFields = fields.filter((f) => f.name.toLowerCase() === field?.toLowerCase());
624
+ if (actualFields.length === 0) {
625
+ throw new Error(`Security validation failed: The query must include ${field} as a raw column in the SELECT statement. This field is required for row-level security enforcement.`);
626
+ }
627
+ const actualField = actualFields.find((f) => !f.orgTable || f.orgTable.toUpperCase() !== upperTableName);
628
+ if (actualField) {
629
+ throw new Error(`Security validation failed: '${field}' must come directly from the ${upperTableName} table. Joins, subqueries, or table aliases that change the origin of this column are not allowed.`);
630
+ }
631
+ });
632
+ // Check that all fields with orgTable come from table
633
+ // (This prevents JOINs or subqueries that reference other tables)
634
+ // Note: Fields without orgTable (empty/undefined) are allowed - these are computed/calculated fields
635
+ // We only check fields that have orgTable set - if orgTable exists, it must be table
636
+ const fieldsFromOtherTables = fields.filter((f) => f.orgTable && f.orgTable.toUpperCase() !== upperTableName);
637
+ if (fieldsFromOtherTables.length > 0) {
638
+ throw new Error(`Security validation failed: All fields must come from the ${upperTableName} table. ` +
639
+ "Fields from other tables detected, which indicates the use of JOINs, subqueries, or references to other tables. " +
640
+ "This is not allowed for security reasons.");
641
+ }
642
+ }
643
+ return result;
644
+ }
645
+ }
646
+ exports.Rovo = Rovo;
647
+ //# sourceMappingURL=Rovo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Rovo.js","sourceRoot":"","sources":["../../src/core/Rovo.ts"],"names":[],"mappings":"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"}