@memberjunction/query-gen 0.0.1 → 2.126.1

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 (138) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/CHANGELOG.md +34 -0
  3. package/COORDINATOR.md +768 -0
  4. package/IMPLEMENTATION_PLAN.md +1753 -0
  5. package/LLM_ENTITY_GROUPING_PLAN.md +977 -0
  6. package/README.md +675 -29
  7. package/dist/cli/commands/export.d.ts +15 -0
  8. package/dist/cli/commands/export.d.ts.map +1 -0
  9. package/dist/cli/commands/export.js +178 -0
  10. package/dist/cli/commands/export.js.map +1 -0
  11. package/dist/cli/commands/generate.d.ts +19 -0
  12. package/dist/cli/commands/generate.d.ts.map +1 -0
  13. package/dist/cli/commands/generate.js +282 -0
  14. package/dist/cli/commands/generate.js.map +1 -0
  15. package/dist/cli/commands/validate.d.ts +17 -0
  16. package/dist/cli/commands/validate.d.ts.map +1 -0
  17. package/dist/cli/commands/validate.js +193 -0
  18. package/dist/cli/commands/validate.js.map +1 -0
  19. package/dist/cli/config.d.ts +51 -0
  20. package/dist/cli/config.d.ts.map +1 -0
  21. package/dist/cli/config.js +142 -0
  22. package/dist/cli/config.js.map +1 -0
  23. package/dist/cli/index.d.ts +13 -0
  24. package/dist/cli/index.d.ts.map +1 -0
  25. package/dist/cli/index.js +57 -0
  26. package/dist/cli/index.js.map +1 -0
  27. package/dist/core/EntityGrouper.d.ts +74 -0
  28. package/dist/core/EntityGrouper.d.ts.map +1 -0
  29. package/dist/core/EntityGrouper.js +246 -0
  30. package/dist/core/EntityGrouper.js.map +1 -0
  31. package/dist/core/MetadataExporter.d.ts +59 -0
  32. package/dist/core/MetadataExporter.d.ts.map +1 -0
  33. package/dist/core/MetadataExporter.js +151 -0
  34. package/dist/core/MetadataExporter.js.map +1 -0
  35. package/dist/core/QueryDatabaseWriter.d.ts +50 -0
  36. package/dist/core/QueryDatabaseWriter.d.ts.map +1 -0
  37. package/dist/core/QueryDatabaseWriter.js +152 -0
  38. package/dist/core/QueryDatabaseWriter.js.map +1 -0
  39. package/dist/core/QueryFixer.d.ts +48 -0
  40. package/dist/core/QueryFixer.d.ts.map +1 -0
  41. package/dist/core/QueryFixer.js +115 -0
  42. package/dist/core/QueryFixer.js.map +1 -0
  43. package/dist/core/QueryRefiner.d.ts +94 -0
  44. package/dist/core/QueryRefiner.d.ts.map +1 -0
  45. package/dist/core/QueryRefiner.js +267 -0
  46. package/dist/core/QueryRefiner.js.map +1 -0
  47. package/dist/core/QueryTester.d.ts +70 -0
  48. package/dist/core/QueryTester.d.ts.map +1 -0
  49. package/dist/core/QueryTester.js +243 -0
  50. package/dist/core/QueryTester.js.map +1 -0
  51. package/dist/core/QueryWriter.d.ts +57 -0
  52. package/dist/core/QueryWriter.d.ts.map +1 -0
  53. package/dist/core/QueryWriter.js +184 -0
  54. package/dist/core/QueryWriter.js.map +1 -0
  55. package/dist/core/QuestionGenerator.d.ts +58 -0
  56. package/dist/core/QuestionGenerator.d.ts.map +1 -0
  57. package/dist/core/QuestionGenerator.js +145 -0
  58. package/dist/core/QuestionGenerator.js.map +1 -0
  59. package/dist/data/schema.d.ts +230 -0
  60. package/dist/data/schema.d.ts.map +1 -0
  61. package/dist/data/schema.js +6 -0
  62. package/dist/data/schema.js.map +1 -0
  63. package/dist/index.d.ts +28 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +77 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/prompts/PromptNames.d.ts +32 -0
  68. package/dist/prompts/PromptNames.d.ts.map +1 -0
  69. package/dist/prompts/PromptNames.js +35 -0
  70. package/dist/prompts/PromptNames.js.map +1 -0
  71. package/dist/utils/category-builder.d.ts +28 -0
  72. package/dist/utils/category-builder.d.ts.map +1 -0
  73. package/dist/utils/category-builder.js +90 -0
  74. package/dist/utils/category-builder.js.map +1 -0
  75. package/dist/utils/entity-helpers.d.ts +49 -0
  76. package/dist/utils/entity-helpers.d.ts.map +1 -0
  77. package/dist/utils/entity-helpers.js +189 -0
  78. package/dist/utils/entity-helpers.js.map +1 -0
  79. package/dist/utils/error-handlers.d.ts +19 -0
  80. package/dist/utils/error-handlers.d.ts.map +1 -0
  81. package/dist/utils/error-handlers.js +41 -0
  82. package/dist/utils/error-handlers.js.map +1 -0
  83. package/dist/utils/graph-helpers.d.ts +51 -0
  84. package/dist/utils/graph-helpers.d.ts.map +1 -0
  85. package/dist/utils/graph-helpers.js +82 -0
  86. package/dist/utils/graph-helpers.js.map +1 -0
  87. package/dist/utils/prompt-helpers.d.ts +25 -0
  88. package/dist/utils/prompt-helpers.d.ts.map +1 -0
  89. package/dist/utils/prompt-helpers.js +66 -0
  90. package/dist/utils/prompt-helpers.js.map +1 -0
  91. package/dist/utils/query-helpers.d.ts +23 -0
  92. package/dist/utils/query-helpers.d.ts.map +1 -0
  93. package/dist/utils/query-helpers.js +34 -0
  94. package/dist/utils/query-helpers.js.map +1 -0
  95. package/dist/utils/user-helpers.d.ts +15 -0
  96. package/dist/utils/user-helpers.d.ts.map +1 -0
  97. package/dist/utils/user-helpers.js +32 -0
  98. package/dist/utils/user-helpers.js.map +1 -0
  99. package/dist/vectors/EmbeddingService.d.ts +58 -0
  100. package/dist/vectors/EmbeddingService.d.ts.map +1 -0
  101. package/dist/vectors/EmbeddingService.js +90 -0
  102. package/dist/vectors/EmbeddingService.js.map +1 -0
  103. package/dist/vectors/SimilaritySearch.d.ts +51 -0
  104. package/dist/vectors/SimilaritySearch.d.ts.map +1 -0
  105. package/dist/vectors/SimilaritySearch.js +85 -0
  106. package/dist/vectors/SimilaritySearch.js.map +1 -0
  107. package/docs/API.md +1040 -0
  108. package/docs/ARCHITECTURE.md +1120 -0
  109. package/examples/advanced-usage.ts +401 -0
  110. package/examples/basic-usage.ts +285 -0
  111. package/package.json +48 -6
  112. package/src/cli/commands/export.ts +173 -0
  113. package/src/cli/commands/generate.ts +330 -0
  114. package/src/cli/commands/validate.ts +185 -0
  115. package/src/cli/config.ts +203 -0
  116. package/src/cli/index.ts +63 -0
  117. package/src/core/EntityGrouper.ts +318 -0
  118. package/src/core/MetadataExporter.ts +148 -0
  119. package/src/core/QueryDatabaseWriter.ts +187 -0
  120. package/src/core/QueryFixer.ts +153 -0
  121. package/src/core/QueryRefiner.ts +382 -0
  122. package/src/core/QueryTester.ts +264 -0
  123. package/src/core/QueryWriter.ts +239 -0
  124. package/src/core/QuestionGenerator.ts +199 -0
  125. package/src/data/golden-queries.json +1371 -0
  126. package/src/data/schema.ts +252 -0
  127. package/src/index.ts +49 -0
  128. package/src/prompts/PromptNames.ts +36 -0
  129. package/src/utils/category-builder.ts +97 -0
  130. package/src/utils/entity-helpers.ts +203 -0
  131. package/src/utils/error-handlers.ts +41 -0
  132. package/src/utils/graph-helpers.ts +99 -0
  133. package/src/utils/prompt-helpers.ts +79 -0
  134. package/src/utils/query-helpers.ts +32 -0
  135. package/src/utils/user-helpers.ts +39 -0
  136. package/src/vectors/EmbeddingService.ts +109 -0
  137. package/src/vectors/SimilaritySearch.ts +108 -0
  138. package/tsconfig.json +39 -0
@@ -0,0 +1,267 @@
1
+ "use strict";
2
+ /**
3
+ * QueryRefiner - Iteratively improves queries based on evaluation feedback
4
+ *
5
+ * Uses evaluation and refinement AI prompts to assess if queries answer
6
+ * the business question correctly and improve them through iterations.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.QueryRefiner = void 0;
10
+ const aiengine_1 = require("@memberjunction/aiengine");
11
+ const core_1 = require("@memberjunction/core");
12
+ const error_handlers_1 = require("../utils/error-handlers");
13
+ const PromptNames_1 = require("../prompts/PromptNames");
14
+ const prompt_helpers_1 = require("../utils/prompt-helpers");
15
+ /**
16
+ * QueryRefiner class
17
+ * Iteratively refines queries based on evaluation feedback
18
+ */
19
+ class QueryRefiner {
20
+ tester;
21
+ contextUser;
22
+ config;
23
+ entityMetadata = [];
24
+ constructor(tester, contextUser, config) {
25
+ this.tester = tester;
26
+ this.contextUser = contextUser;
27
+ this.config = config;
28
+ }
29
+ /**
30
+ * Refine a query through evaluation and improvement iterations
31
+ *
32
+ * Loops up to maxRefinements times, testing and evaluating each iteration.
33
+ * Returns when query passes evaluation or max refinements reached.
34
+ *
35
+ * @param query - Initial generated query
36
+ * @param businessQuestion - Original business question
37
+ * @param entityMetadata - Entity metadata for refinement
38
+ * @param maxRefinements - Maximum refinement iterations (default: 3)
39
+ * @returns Refined query with test results and evaluation
40
+ */
41
+ async refineQuery(query, businessQuestion, entityMetadata, maxRefinements = 3) {
42
+ // Store entity metadata for use in evaluation
43
+ this.entityMetadata = entityMetadata;
44
+ let currentQuery = query;
45
+ let refinementCount = 0;
46
+ // Track the last successfully tested query and its results
47
+ let lastWorkingQuery = query;
48
+ let lastWorkingTestResult = null;
49
+ let lastWorkingEvaluation = null;
50
+ // Ensure AIEngine is configured
51
+ await this.configureAIEngine();
52
+ while (refinementCount < maxRefinements) {
53
+ // 1. Test the current query
54
+ let testResult;
55
+ try {
56
+ testResult = await this.testCurrentQuery(currentQuery);
57
+ // Success! Save this as our last working version
58
+ lastWorkingQuery = currentQuery;
59
+ lastWorkingTestResult = testResult;
60
+ }
61
+ catch (error) {
62
+ // Query broke during refinement - revert to last working version
63
+ if (this.config.verbose) {
64
+ (0, core_1.LogStatus)(`Refinement produced broken query: ${(0, error_handlers_1.extractErrorMessage)(error, 'Refinement Test')}. Reverting to last working version.`);
65
+ }
66
+ // If we have a previous working version, use that
67
+ if (lastWorkingTestResult && lastWorkingEvaluation) {
68
+ return this.buildSuccessResult(lastWorkingQuery, lastWorkingTestResult, lastWorkingEvaluation, refinementCount);
69
+ }
70
+ // No previous working version - throw the error
71
+ throw error;
72
+ }
73
+ // 2. Evaluate if it answers the question
74
+ const evaluation = await this.evaluateQuery(currentQuery, businessQuestion, testResult);
75
+ lastWorkingEvaluation = evaluation;
76
+ // 3. If evaluation passes, we're done!
77
+ if (this.shouldStopRefining(evaluation)) {
78
+ return this.buildSuccessResult(currentQuery, testResult, evaluation, refinementCount);
79
+ }
80
+ // 4. Refine the query based on suggestions
81
+ refinementCount++;
82
+ if (this.config.verbose) {
83
+ (0, core_1.LogStatus)(`Refinement iteration ${refinementCount}/${maxRefinements}`);
84
+ }
85
+ currentQuery = await this.performRefinement(currentQuery, businessQuestion, evaluation, entityMetadata);
86
+ }
87
+ // Reached max refinements - return best attempt
88
+ // Use the last successfully tested query
89
+ if (lastWorkingTestResult && lastWorkingEvaluation) {
90
+ return {
91
+ query: lastWorkingQuery,
92
+ testResult: lastWorkingTestResult,
93
+ evaluation: lastWorkingEvaluation,
94
+ refinementCount,
95
+ reachedMaxRefinements: true,
96
+ };
97
+ }
98
+ // Fallback: try to build final result with current query
99
+ return await this.buildFinalResult(currentQuery, businessQuestion, refinementCount);
100
+ }
101
+ /**
102
+ * Configure AIEngine for prompt execution
103
+ * Ensures engine is ready before running prompts
104
+ */
105
+ async configureAIEngine() {
106
+ try {
107
+ const aiEngine = aiengine_1.AIEngine.Instance;
108
+ await aiEngine.Config(false, this.contextUser);
109
+ }
110
+ catch (error) {
111
+ throw new Error((0, error_handlers_1.extractErrorMessage)(error, 'AIEngine Configuration'));
112
+ }
113
+ }
114
+ /**
115
+ * Test current query using QueryTester
116
+ * Throws if query testing fails
117
+ */
118
+ async testCurrentQuery(query) {
119
+ const testResult = await this.tester.testQuery(query);
120
+ if (!testResult.success) {
121
+ throw new Error(`Query testing failed after ${testResult.attempts} attempts: ${testResult.error}`);
122
+ }
123
+ return testResult;
124
+ }
125
+ /**
126
+ * Determine if refinement should stop based on evaluation
127
+ * Stops if query answers question and doesn't need refinement
128
+ */
129
+ shouldStopRefining(evaluation) {
130
+ return evaluation.answersQuestion && !evaluation.needsRefinement;
131
+ }
132
+ /**
133
+ * Build success result when refinement loop completes successfully
134
+ */
135
+ buildSuccessResult(query, testResult, evaluation, refinementCount) {
136
+ return {
137
+ query,
138
+ testResult,
139
+ evaluation,
140
+ refinementCount,
141
+ };
142
+ }
143
+ /**
144
+ * Build final result when max refinements reached
145
+ * Re-tests and re-evaluates final query
146
+ */
147
+ async buildFinalResult(query, businessQuestion, refinementCount) {
148
+ const testResult = await this.tester.testQuery(query);
149
+ const evaluation = await this.evaluateQuery(query, businessQuestion, testResult);
150
+ return {
151
+ query,
152
+ testResult,
153
+ evaluation,
154
+ refinementCount,
155
+ reachedMaxRefinements: true,
156
+ };
157
+ }
158
+ /**
159
+ * Evaluate if query answers the business question correctly
160
+ * Uses Query Result Evaluator AI prompt
161
+ *
162
+ * @param query - Query to evaluate
163
+ * @param businessQuestion - Original business question
164
+ * @param testResult - Test execution results with sample data
165
+ * @returns Evaluation with confidence and suggestions
166
+ */
167
+ async evaluateQuery(query, businessQuestion, testResult) {
168
+ try {
169
+ const aiEngine = aiengine_1.AIEngine.Instance;
170
+ const prompt = this.findPromptByName(aiEngine, PromptNames_1.PROMPT_QUERY_EVALUATOR);
171
+ // Limit sample results to first 10 rows for efficiency
172
+ const sampleResults = testResult.sampleRows?.slice(0, 10) || [];
173
+ const promptData = {
174
+ userQuestion: businessQuestion.userQuestion,
175
+ description: businessQuestion.description,
176
+ technicalDescription: businessQuestion.technicalDescription,
177
+ entityMetadata: this.entityMetadata,
178
+ generatedSQL: query.sql,
179
+ parameters: query.parameters,
180
+ sampleResults,
181
+ };
182
+ const evaluation = await this.executePrompt(prompt, promptData);
183
+ this.logEvaluation(evaluation);
184
+ return evaluation;
185
+ }
186
+ catch (error) {
187
+ throw new Error((0, error_handlers_1.extractErrorMessage)(error, 'QueryRefiner.evaluateQuery'));
188
+ }
189
+ }
190
+ /**
191
+ * Refine query based on evaluation feedback
192
+ * Uses Query Refiner AI prompt
193
+ *
194
+ * @param query - Current query to refine
195
+ * @param businessQuestion - Original business question
196
+ * @param evaluation - Evaluation feedback
197
+ * @param entityMetadata - Entity metadata for refinement
198
+ * @returns Refined query with improvements
199
+ */
200
+ async performRefinement(query, businessQuestion, evaluation, entityMetadata) {
201
+ try {
202
+ const aiEngine = aiengine_1.AIEngine.Instance;
203
+ const prompt = this.findPromptByName(aiEngine, PromptNames_1.PROMPT_QUERY_REFINER);
204
+ const promptData = {
205
+ userQuestion: businessQuestion.userQuestion,
206
+ description: businessQuestion.description,
207
+ currentSQL: query.sql,
208
+ evaluationFeedback: evaluation,
209
+ entityMetadata,
210
+ };
211
+ const refinedQuery = await this.executePrompt(prompt, promptData);
212
+ if (this.config.verbose) {
213
+ (0, core_1.LogStatus)(`Refinements applied: ${refinedQuery.improvementsSummary}`);
214
+ }
215
+ return {
216
+ sql: refinedQuery.sql,
217
+ parameters: refinedQuery.parameters,
218
+ };
219
+ }
220
+ catch (error) {
221
+ throw new Error((0, error_handlers_1.extractErrorMessage)(error, 'QueryRefiner.performRefinement'));
222
+ }
223
+ }
224
+ /**
225
+ * Find prompt by name in AIEngine cache
226
+ * Throws if prompt not found
227
+ */
228
+ findPromptByName(aiEngine, promptName) {
229
+ const prompt = aiEngine.Prompts.find((p) => p.Name === promptName);
230
+ if (!prompt) {
231
+ throw new Error(`Prompt '${promptName}' not found in AIEngine cache`);
232
+ }
233
+ return prompt;
234
+ }
235
+ /**
236
+ * Execute AI prompt and parse result
237
+ * Generic method for any prompt type
238
+ */
239
+ async executePrompt(prompt, promptData) {
240
+ const result = await (0, prompt_helpers_1.executePromptWithOverrides)(prompt, promptData, this.contextUser, this.config);
241
+ if (!result || !result.success) {
242
+ throw new Error(`AI prompt execution failed: ${result?.errorMessage || 'Unknown error'}`);
243
+ }
244
+ if (!result.result) {
245
+ throw new Error('AI prompt returned no result');
246
+ }
247
+ return result.result;
248
+ }
249
+ /**
250
+ * Log evaluation results for debugging
251
+ */
252
+ logEvaluation(evaluation) {
253
+ if (!this.config.verbose)
254
+ return;
255
+ (0, core_1.LogStatus)(`Evaluation: answersQuestion=${evaluation.answersQuestion}, ` +
256
+ `confidence=${evaluation.confidence}, ` +
257
+ `needsRefinement=${evaluation.needsRefinement}`);
258
+ if (evaluation.reasoning) {
259
+ (0, core_1.LogStatus)(`Reasoning: ${evaluation.reasoning}`);
260
+ }
261
+ if (evaluation.suggestions.length > 0) {
262
+ (0, core_1.LogStatus)(`Suggestions: ${evaluation.suggestions.join('; ')}`);
263
+ }
264
+ }
265
+ }
266
+ exports.QueryRefiner = QueryRefiner;
267
+ //# sourceMappingURL=QueryRefiner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryRefiner.js","sourceRoot":"","sources":["../../src/core/QueryRefiner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * QueryTester - Tests and validates SQL queries
3
+ *
4
+ * Renders Nunjucks templates with sample parameter values and executes
5
+ * queries against the database. Handles error fixing with retry loop.
6
+ */
7
+ import { DatabaseProviderBase, UserInfo } from '@memberjunction/core';
8
+ import { GeneratedQuery, QueryTestResult, EntityMetadataForPrompt, BusinessQuestion } from '../data/schema';
9
+ import { QueryGenConfig } from '../cli/config';
10
+ /**
11
+ * QueryTester class
12
+ * Tests SQL queries by rendering templates and executing against database
13
+ */
14
+ export declare class QueryTester {
15
+ private dataProvider;
16
+ private entityMetadata;
17
+ private businessQuestion;
18
+ private contextUser;
19
+ private config;
20
+ private nunjucksEnv;
21
+ constructor(dataProvider: DatabaseProviderBase, entityMetadata: EntityMetadataForPrompt[], businessQuestion: BusinessQuestion, contextUser: UserInfo, config: QueryGenConfig);
22
+ /**
23
+ * Test a query by rendering template with sample values and executing it
24
+ * Retries up to maxAttempts times, calling QueryFixer on failures
25
+ *
26
+ * @param query - Generated query to test
27
+ * @param maxAttempts - Maximum number of retry attempts (default: 5)
28
+ * @returns Test result with success status, SQL, and sample data
29
+ */
30
+ testQuery(query: GeneratedQuery, maxAttempts?: number): Promise<QueryTestResult>;
31
+ /**
32
+ * Render query template with sample parameter values
33
+ * Uses QueryParameterProcessor for proper type handling
34
+ *
35
+ * @param query - Generated query with parameters
36
+ * @returns Rendered SQL string ready for execution
37
+ */
38
+ private renderQueryTemplate;
39
+ /**
40
+ * Processes a raw parameter value based on its type, handling special cases like arrays.
41
+ * Follows Skip-Brain pattern for parameter processing.
42
+ * For array types, this function will:
43
+ * - Parse JSON arrays if the value is a JSON string
44
+ * - Split comma-separated strings as a fallback
45
+ * - Return as-is for sqlIn filter to handle
46
+ *
47
+ * @param rawValue - The raw parameter value (from sampleValue)
48
+ * @param paramType - The parameter type ('string', 'number', 'date', 'boolean', 'array')
49
+ * @returns Processed value ready for use in Nunjucks template
50
+ */
51
+ private processParameterValue;
52
+ /**
53
+ * Execute SQL query against database
54
+ * Uses DataProvider to run query with contextUser
55
+ *
56
+ * @param sql - Rendered SQL query
57
+ * @returns Array of result rows
58
+ */
59
+ private executeSQLQuery;
60
+ /**
61
+ * Fix a query that failed to execute
62
+ * Uses QueryFixer with AI to analyze error and generate correction
63
+ *
64
+ * @param query - Query that failed
65
+ * @param errorMessage - Error message from execution
66
+ * @returns Corrected query
67
+ */
68
+ private fixQuery;
69
+ }
70
+ //# sourceMappingURL=QueryTester.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryTester.d.ts","sourceRoot":"","sources":["../../src/core/QueryTester.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,oBAAoB,EAEpB,QAAQ,EAET,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,cAAc,EACd,eAAe,EACf,uBAAuB,EACvB,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C;;;GAGG;AACH,qBAAa,WAAW;IAIpB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,gBAAgB;IACxB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,MAAM;IAPhB,OAAO,CAAC,WAAW,CAAuB;gBAGhC,YAAY,EAAE,oBAAoB,EAClC,cAAc,EAAE,uBAAuB,EAAE,EACzC,gBAAgB,EAAE,gBAAgB,EAClC,WAAW,EAAE,QAAQ,EACrB,MAAM,EAAE,cAAc;IAqBhC;;;;;;;OAOG;IACG,SAAS,CACb,KAAK,EAAE,cAAc,EACrB,WAAW,GAAE,MAAU,GACtB,OAAO,CAAC,eAAe,CAAC;IAgD3B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IAsB3B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,qBAAqB;IA0D7B;;;;;;OAMG;YACW,eAAe;IAqB7B;;;;;;;OAOG;YACW,QAAQ;CAYvB"}
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ /**
3
+ * QueryTester - Tests and validates SQL queries
4
+ *
5
+ * Renders Nunjucks templates with sample parameter values and executes
6
+ * queries against the database. Handles error fixing with retry loop.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || function (mod) {
25
+ if (mod && mod.__esModule) return mod;
26
+ var result = {};
27
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
28
+ __setModuleDefault(result, mod);
29
+ return result;
30
+ };
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.QueryTester = void 0;
33
+ const nunjucks = __importStar(require("nunjucks"));
34
+ const core_1 = require("@memberjunction/core");
35
+ const error_handlers_1 = require("../utils/error-handlers");
36
+ const QueryFixer_1 = require("./QueryFixer");
37
+ /**
38
+ * QueryTester class
39
+ * Tests SQL queries by rendering templates and executing against database
40
+ */
41
+ class QueryTester {
42
+ dataProvider;
43
+ entityMetadata;
44
+ businessQuestion;
45
+ contextUser;
46
+ config;
47
+ nunjucksEnv;
48
+ constructor(dataProvider, entityMetadata, businessQuestion, contextUser, config) {
49
+ this.dataProvider = dataProvider;
50
+ this.entityMetadata = entityMetadata;
51
+ this.businessQuestion = businessQuestion;
52
+ this.contextUser = contextUser;
53
+ this.config = config;
54
+ // Initialize Nunjucks environment with SQL-safe filters
55
+ this.nunjucksEnv = new nunjucks.Environment(null, {
56
+ autoescape: false,
57
+ throwOnUndefined: true,
58
+ trimBlocks: true,
59
+ lstripBlocks: true,
60
+ });
61
+ // Add custom SQL-safe filters from RunQuerySQLFilterManager
62
+ const filterManager = core_1.RunQuerySQLFilterManager.Instance;
63
+ const filters = filterManager.getAllFilters();
64
+ for (const filter of filters) {
65
+ if (filter.implementation) {
66
+ this.nunjucksEnv.addFilter(filter.name, filter.implementation);
67
+ }
68
+ }
69
+ }
70
+ /**
71
+ * Test a query by rendering template with sample values and executing it
72
+ * Retries up to maxAttempts times, calling QueryFixer on failures
73
+ *
74
+ * @param query - Generated query to test
75
+ * @param maxAttempts - Maximum number of retry attempts (default: 5)
76
+ * @returns Test result with success status, SQL, and sample data
77
+ */
78
+ async testQuery(query, maxAttempts = 5) {
79
+ let attempt = 0;
80
+ let lastError;
81
+ let currentQuery = query;
82
+ while (attempt < maxAttempts) {
83
+ attempt++;
84
+ try {
85
+ // 1. Render template with sample parameter values
86
+ const renderedSQL = this.renderQueryTemplate(currentQuery);
87
+ // 2. Execute SQL on database
88
+ const results = await this.executeSQLQuery(renderedSQL);
89
+ // 3. Success! (Empty results are valid - query executed without errors)
90
+ // Note: We don't validate rowCount because:
91
+ // - Empty results may indicate no data in database (not a query error)
92
+ // - Query structure can be correct even with zero rows returned
93
+ // - Testing should focus on SQL syntax/execution, not data presence
94
+ return {
95
+ success: true,
96
+ renderedSQL,
97
+ rowCount: results.length,
98
+ sampleRows: results.slice(0, 10), // Return first 10 rows
99
+ attempts: attempt,
100
+ };
101
+ }
102
+ catch (error) {
103
+ lastError = (0, error_handlers_1.extractErrorMessage)(error, 'Query Testing');
104
+ if (this.config.verbose) {
105
+ (0, core_1.LogError)(`Attempt ${attempt}/${maxAttempts} failed: ${lastError}`);
106
+ }
107
+ // 5. If not last attempt, try to fix the query
108
+ if (attempt < maxAttempts) {
109
+ currentQuery = await this.fixQuery(currentQuery, lastError);
110
+ }
111
+ }
112
+ }
113
+ // Failed after max attempts
114
+ return {
115
+ success: false,
116
+ error: lastError,
117
+ attempts: maxAttempts,
118
+ };
119
+ }
120
+ /**
121
+ * Render query template with sample parameter values
122
+ * Uses QueryParameterProcessor for proper type handling
123
+ *
124
+ * @param query - Generated query with parameters
125
+ * @returns Rendered SQL string ready for execution
126
+ */
127
+ renderQueryTemplate(query) {
128
+ // Build parameter values object
129
+ const paramValues = {};
130
+ for (const param of query.parameters) {
131
+ const rawValue = param.sampleValue;
132
+ if (rawValue !== undefined && rawValue !== null) {
133
+ paramValues[param.name] = this.processParameterValue(rawValue, param.type);
134
+ }
135
+ }
136
+ try {
137
+ // Render template using Nunjucks with SQL-safe filters
138
+ const renderedSQL = this.nunjucksEnv.renderString(query.sql, paramValues);
139
+ return renderedSQL;
140
+ }
141
+ catch (error) {
142
+ throw new Error(`Template rendering failed: ${(0, error_handlers_1.extractErrorMessage)(error, 'Nunjucks')}`);
143
+ }
144
+ }
145
+ /**
146
+ * Processes a raw parameter value based on its type, handling special cases like arrays.
147
+ * Follows Skip-Brain pattern for parameter processing.
148
+ * For array types, this function will:
149
+ * - Parse JSON arrays if the value is a JSON string
150
+ * - Split comma-separated strings as a fallback
151
+ * - Return as-is for sqlIn filter to handle
152
+ *
153
+ * @param rawValue - The raw parameter value (from sampleValue)
154
+ * @param paramType - The parameter type ('string', 'number', 'date', 'boolean', 'array')
155
+ * @returns Processed value ready for use in Nunjucks template
156
+ */
157
+ processParameterValue(rawValue, paramType) {
158
+ if (rawValue === undefined || rawValue === null) {
159
+ return rawValue;
160
+ }
161
+ // For array type parameters, ensure value is compatible with sqlIn filter
162
+ if (paramType === 'array' && typeof rawValue === 'string') {
163
+ try {
164
+ // Try to parse as JSON array
165
+ const parsed = JSON.parse(rawValue);
166
+ if (Array.isArray(parsed)) {
167
+ return parsed;
168
+ }
169
+ }
170
+ catch {
171
+ // Not valid JSON - return as-is for sqlIn filter to handle comma-separated strings
172
+ }
173
+ // Return comma-separated string as-is - sqlIn filter handles this
174
+ return rawValue;
175
+ }
176
+ // For non-array types, convert as needed
177
+ switch (paramType) {
178
+ case 'number':
179
+ if (typeof rawValue === 'string') {
180
+ const num = Number(rawValue);
181
+ if (isNaN(num)) {
182
+ throw new Error(`Invalid number sample value: ${rawValue}`);
183
+ }
184
+ return num;
185
+ }
186
+ return rawValue;
187
+ case 'boolean':
188
+ if (typeof rawValue === 'string') {
189
+ const lower = rawValue.toLowerCase();
190
+ if (lower !== 'true' && lower !== 'false') {
191
+ throw new Error(`Invalid boolean sample value: ${rawValue}`);
192
+ }
193
+ return lower === 'true';
194
+ }
195
+ return rawValue;
196
+ case 'date':
197
+ if (typeof rawValue === 'string') {
198
+ const date = new Date(rawValue);
199
+ if (isNaN(date.getTime())) {
200
+ throw new Error(`Invalid date sample value: ${rawValue}`);
201
+ }
202
+ return date;
203
+ }
204
+ return rawValue;
205
+ case 'string':
206
+ default:
207
+ return rawValue;
208
+ }
209
+ }
210
+ /**
211
+ * Execute SQL query against database
212
+ * Uses DataProvider to run query with contextUser
213
+ *
214
+ * @param sql - Rendered SQL query
215
+ * @returns Array of result rows
216
+ */
217
+ async executeSQLQuery(sql) {
218
+ try {
219
+ const result = await this.dataProvider.ExecuteSQL(sql, undefined, undefined, this.contextUser);
220
+ if (!result || !Array.isArray(result)) {
221
+ throw new Error('ExecuteSQL returned invalid result format');
222
+ }
223
+ return result;
224
+ }
225
+ catch (error) {
226
+ throw new Error(`SQL execution failed: ${(0, error_handlers_1.extractErrorMessage)(error, 'Database')}`);
227
+ }
228
+ }
229
+ /**
230
+ * Fix a query that failed to execute
231
+ * Uses QueryFixer with AI to analyze error and generate correction
232
+ *
233
+ * @param query - Query that failed
234
+ * @param errorMessage - Error message from execution
235
+ * @returns Corrected query
236
+ */
237
+ async fixQuery(query, errorMessage) {
238
+ const fixer = new QueryFixer_1.QueryFixer(this.contextUser, this.config);
239
+ return await fixer.fixQuery(query, errorMessage, this.entityMetadata, this.businessQuestion);
240
+ }
241
+ }
242
+ exports.QueryTester = QueryTester;
243
+ //# sourceMappingURL=QueryTester.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryTester.js","sourceRoot":"","sources":["../../src/core/QueryTester.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * QueryWriter - Generates SQL query templates using AI with few-shot learning
3
+ *
4
+ * Uses the SQL Query Writer AI prompt to generate Nunjucks SQL templates
5
+ * based on business questions and similar golden query examples.
6
+ */
7
+ import { UserInfo } from '@memberjunction/core';
8
+ import { QueryGenConfig } from '../cli/config';
9
+ import { BusinessQuestion, GeneratedQuery, EntityMetadataForPrompt, GoldenQuery } from '../data/schema';
10
+ /**
11
+ * QueryWriter class
12
+ * Generates Nunjucks SQL query templates using AI with few-shot learning
13
+ */
14
+ export declare class QueryWriter {
15
+ private contextUser;
16
+ private config;
17
+ constructor(contextUser: UserInfo, config: QueryGenConfig);
18
+ /**
19
+ * Generate SQL query template for a business question
20
+ * Uses few-shot learning with similar golden query examples
21
+ *
22
+ * @param businessQuestion - Business question to answer with SQL
23
+ * @param entityMetadata - Available entity metadata for query
24
+ * @param fewShotExamples - Similar golden queries for few-shot learning
25
+ * @returns Generated SQL query with parameters and output schema
26
+ */
27
+ generateQuery(businessQuestion: BusinessQuestion, entityMetadata: EntityMetadataForPrompt[], fewShotExamples: GoldenQuery[]): Promise<GeneratedQuery>;
28
+ /**
29
+ * Find prompt by name in AIEngine cache
30
+ * Throws if prompt not found
31
+ */
32
+ private findPromptByName;
33
+ /**
34
+ * Execute the SQL Query Writer AI prompt with retry logic for validation failures
35
+ * Parses JSON response and validates structure, retrying with feedback if validation fails
36
+ */
37
+ private executePrompt;
38
+ /**
39
+ * Validate generated query structure
40
+ * Ensures query has proper SQL template syntax and valid metadata
41
+ *
42
+ * @param query - Generated query to validate
43
+ * @throws Error if query structure is invalid
44
+ */
45
+ private validateGeneratedQuery;
46
+ /**
47
+ * Check if SQL uses base views (vw* pattern)
48
+ * Basic heuristic: looks for view names in FROM and JOIN clauses
49
+ */
50
+ private usesBaseViews;
51
+ /**
52
+ * Validate a single query parameter
53
+ * Ensures all required fields are present and valid
54
+ */
55
+ private validateParameter;
56
+ }
57
+ //# sourceMappingURL=QueryWriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryWriter.d.ts","sourceRoot":"","sources":["../../src/core/QueryWriter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,QAAQ,EAAa,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGxG;;;GAGG;AACH,qBAAa,WAAW;IAEpB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,MAAM;gBADN,WAAW,EAAE,QAAQ,EACrB,MAAM,EAAE,cAAc;IAGhC;;;;;;;;OAQG;IACG,aAAa,CACjB,gBAAgB,EAAE,gBAAgB,EAClC,cAAc,EAAE,uBAAuB,EAAE,EACzC,eAAe,EAAE,WAAW,EAAE,GAC7B,OAAO,CAAC,cAAc,CAAC;IAgC1B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;;OAGG;YACW,aAAa;IAwE3B;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAsB9B;;;OAGG;IACH,OAAO,CAAC,aAAa;IAMrB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;CAiC1B"}