@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.
- package/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +34 -0
- package/COORDINATOR.md +768 -0
- package/IMPLEMENTATION_PLAN.md +1753 -0
- package/LLM_ENTITY_GROUPING_PLAN.md +977 -0
- package/README.md +675 -29
- package/dist/cli/commands/export.d.ts +15 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +178 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +19 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +282 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +17 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +193 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/config.d.ts +51 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +142 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +57 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/EntityGrouper.d.ts +74 -0
- package/dist/core/EntityGrouper.d.ts.map +1 -0
- package/dist/core/EntityGrouper.js +246 -0
- package/dist/core/EntityGrouper.js.map +1 -0
- package/dist/core/MetadataExporter.d.ts +59 -0
- package/dist/core/MetadataExporter.d.ts.map +1 -0
- package/dist/core/MetadataExporter.js +151 -0
- package/dist/core/MetadataExporter.js.map +1 -0
- package/dist/core/QueryDatabaseWriter.d.ts +50 -0
- package/dist/core/QueryDatabaseWriter.d.ts.map +1 -0
- package/dist/core/QueryDatabaseWriter.js +152 -0
- package/dist/core/QueryDatabaseWriter.js.map +1 -0
- package/dist/core/QueryFixer.d.ts +48 -0
- package/dist/core/QueryFixer.d.ts.map +1 -0
- package/dist/core/QueryFixer.js +115 -0
- package/dist/core/QueryFixer.js.map +1 -0
- package/dist/core/QueryRefiner.d.ts +94 -0
- package/dist/core/QueryRefiner.d.ts.map +1 -0
- package/dist/core/QueryRefiner.js +267 -0
- package/dist/core/QueryRefiner.js.map +1 -0
- package/dist/core/QueryTester.d.ts +70 -0
- package/dist/core/QueryTester.d.ts.map +1 -0
- package/dist/core/QueryTester.js +243 -0
- package/dist/core/QueryTester.js.map +1 -0
- package/dist/core/QueryWriter.d.ts +57 -0
- package/dist/core/QueryWriter.d.ts.map +1 -0
- package/dist/core/QueryWriter.js +184 -0
- package/dist/core/QueryWriter.js.map +1 -0
- package/dist/core/QuestionGenerator.d.ts +58 -0
- package/dist/core/QuestionGenerator.d.ts.map +1 -0
- package/dist/core/QuestionGenerator.js +145 -0
- package/dist/core/QuestionGenerator.js.map +1 -0
- package/dist/data/schema.d.ts +230 -0
- package/dist/data/schema.d.ts.map +1 -0
- package/dist/data/schema.js +6 -0
- package/dist/data/schema.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +77 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/PromptNames.d.ts +32 -0
- package/dist/prompts/PromptNames.d.ts.map +1 -0
- package/dist/prompts/PromptNames.js +35 -0
- package/dist/prompts/PromptNames.js.map +1 -0
- package/dist/utils/category-builder.d.ts +28 -0
- package/dist/utils/category-builder.d.ts.map +1 -0
- package/dist/utils/category-builder.js +90 -0
- package/dist/utils/category-builder.js.map +1 -0
- package/dist/utils/entity-helpers.d.ts +49 -0
- package/dist/utils/entity-helpers.d.ts.map +1 -0
- package/dist/utils/entity-helpers.js +189 -0
- package/dist/utils/entity-helpers.js.map +1 -0
- package/dist/utils/error-handlers.d.ts +19 -0
- package/dist/utils/error-handlers.d.ts.map +1 -0
- package/dist/utils/error-handlers.js +41 -0
- package/dist/utils/error-handlers.js.map +1 -0
- package/dist/utils/graph-helpers.d.ts +51 -0
- package/dist/utils/graph-helpers.d.ts.map +1 -0
- package/dist/utils/graph-helpers.js +82 -0
- package/dist/utils/graph-helpers.js.map +1 -0
- package/dist/utils/prompt-helpers.d.ts +25 -0
- package/dist/utils/prompt-helpers.d.ts.map +1 -0
- package/dist/utils/prompt-helpers.js +66 -0
- package/dist/utils/prompt-helpers.js.map +1 -0
- package/dist/utils/query-helpers.d.ts +23 -0
- package/dist/utils/query-helpers.d.ts.map +1 -0
- package/dist/utils/query-helpers.js +34 -0
- package/dist/utils/query-helpers.js.map +1 -0
- package/dist/utils/user-helpers.d.ts +15 -0
- package/dist/utils/user-helpers.d.ts.map +1 -0
- package/dist/utils/user-helpers.js +32 -0
- package/dist/utils/user-helpers.js.map +1 -0
- package/dist/vectors/EmbeddingService.d.ts +58 -0
- package/dist/vectors/EmbeddingService.d.ts.map +1 -0
- package/dist/vectors/EmbeddingService.js +90 -0
- package/dist/vectors/EmbeddingService.js.map +1 -0
- package/dist/vectors/SimilaritySearch.d.ts +51 -0
- package/dist/vectors/SimilaritySearch.d.ts.map +1 -0
- package/dist/vectors/SimilaritySearch.js +85 -0
- package/dist/vectors/SimilaritySearch.js.map +1 -0
- package/docs/API.md +1040 -0
- package/docs/ARCHITECTURE.md +1120 -0
- package/examples/advanced-usage.ts +401 -0
- package/examples/basic-usage.ts +285 -0
- package/package.json +48 -6
- package/src/cli/commands/export.ts +173 -0
- package/src/cli/commands/generate.ts +330 -0
- package/src/cli/commands/validate.ts +185 -0
- package/src/cli/config.ts +203 -0
- package/src/cli/index.ts +63 -0
- package/src/core/EntityGrouper.ts +318 -0
- package/src/core/MetadataExporter.ts +148 -0
- package/src/core/QueryDatabaseWriter.ts +187 -0
- package/src/core/QueryFixer.ts +153 -0
- package/src/core/QueryRefiner.ts +382 -0
- package/src/core/QueryTester.ts +264 -0
- package/src/core/QueryWriter.ts +239 -0
- package/src/core/QuestionGenerator.ts +199 -0
- package/src/data/golden-queries.json +1371 -0
- package/src/data/schema.ts +252 -0
- package/src/index.ts +49 -0
- package/src/prompts/PromptNames.ts +36 -0
- package/src/utils/category-builder.ts +97 -0
- package/src/utils/entity-helpers.ts +203 -0
- package/src/utils/error-handlers.ts +41 -0
- package/src/utils/graph-helpers.ts +99 -0
- package/src/utils/prompt-helpers.ts +79 -0
- package/src/utils/query-helpers.ts +32 -0
- package/src/utils/user-helpers.ts +39 -0
- package/src/vectors/EmbeddingService.ts +109 -0
- package/src/vectors/SimilaritySearch.ts +108 -0
- package/tsconfig.json +39 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced Usage Example for QueryGen
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates advanced features:
|
|
5
|
+
* 1. Vector similarity search with golden queries
|
|
6
|
+
* 2. Query refinement with evaluation
|
|
7
|
+
* 3. Batch processing multiple entities
|
|
8
|
+
* 4. Custom configuration
|
|
9
|
+
* 5. Database export
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
EntityGrouper,
|
|
14
|
+
QuestionGenerator,
|
|
15
|
+
QueryWriter,
|
|
16
|
+
QueryTester,
|
|
17
|
+
QueryRefiner,
|
|
18
|
+
MetadataExporter,
|
|
19
|
+
QueryDatabaseWriter,
|
|
20
|
+
EmbeddingService,
|
|
21
|
+
SimilaritySearch,
|
|
22
|
+
formatEntityMetadataForPrompt,
|
|
23
|
+
extractErrorMessage,
|
|
24
|
+
ValidatedQuery,
|
|
25
|
+
GoldenQuery,
|
|
26
|
+
QueryGenConfig
|
|
27
|
+
} from '@memberjunction/query-gen';
|
|
28
|
+
import { Metadata, UserInfo, DatabaseProviderBase } from '@memberjunction/core';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Example golden queries for few-shot learning
|
|
32
|
+
* In production, these would be loaded from database or metadata files
|
|
33
|
+
*/
|
|
34
|
+
const GOLDEN_QUERIES: GoldenQuery[] = [
|
|
35
|
+
{
|
|
36
|
+
name: 'Top Customers By Revenue',
|
|
37
|
+
userQuestion: 'What are the top 10 customers by total revenue?',
|
|
38
|
+
description: 'Identify highest-value customers based on order revenue',
|
|
39
|
+
technicalDescription: 'Sum order totals per customer, sort descending, limit 10',
|
|
40
|
+
sql: `
|
|
41
|
+
SELECT TOP 10
|
|
42
|
+
c.Name as CustomerName,
|
|
43
|
+
c.Email as CustomerEmail,
|
|
44
|
+
COUNT(o.ID) as OrderCount,
|
|
45
|
+
COALESCE(SUM(o.Total), 0) as TotalRevenue
|
|
46
|
+
FROM [dbo].[vwCustomers] c
|
|
47
|
+
LEFT JOIN [sales].[vwOrders] o ON o.CustomerID = c.ID
|
|
48
|
+
GROUP BY c.Name, c.Email
|
|
49
|
+
ORDER BY TotalRevenue DESC
|
|
50
|
+
`,
|
|
51
|
+
parameters: [],
|
|
52
|
+
selectClause: [
|
|
53
|
+
{ name: 'CustomerName', description: 'Customer name', type: 'string', optional: false },
|
|
54
|
+
{ name: 'CustomerEmail', description: 'Customer email', type: 'string', optional: false },
|
|
55
|
+
{ name: 'OrderCount', description: 'Number of orders', type: 'number', optional: false },
|
|
56
|
+
{ name: 'TotalRevenue', description: 'Sum of order totals', type: 'number', optional: false }
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'Recent Orders By Status',
|
|
61
|
+
userQuestion: 'Show me recent orders grouped by status',
|
|
62
|
+
description: 'Count orders in each status for the last 30 days',
|
|
63
|
+
technicalDescription: 'Count orders grouped by status, filtered by date range',
|
|
64
|
+
sql: `
|
|
65
|
+
SELECT
|
|
66
|
+
o.Status,
|
|
67
|
+
COUNT(o.ID) as OrderCount,
|
|
68
|
+
COALESCE(SUM(o.Total), 0) as TotalRevenue
|
|
69
|
+
FROM [sales].[vwOrders] o
|
|
70
|
+
WHERE o.OrderDate >= DATEADD(DAY, -30, GETDATE())
|
|
71
|
+
GROUP BY o.Status
|
|
72
|
+
ORDER BY OrderCount DESC
|
|
73
|
+
`,
|
|
74
|
+
parameters: [],
|
|
75
|
+
selectClause: [
|
|
76
|
+
{ name: 'Status', description: 'Order status', type: 'string', optional: false },
|
|
77
|
+
{ name: 'OrderCount', description: 'Number of orders', type: 'number', optional: false },
|
|
78
|
+
{ name: 'TotalRevenue', description: 'Total revenue', type: 'number', optional: false }
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Custom configuration for this example
|
|
85
|
+
*/
|
|
86
|
+
const CUSTOM_CONFIG: Partial<QueryGenConfig> = {
|
|
87
|
+
maxEntitiesPerGroup: 2,
|
|
88
|
+
minEntitiesPerGroup: 1,
|
|
89
|
+
questionsPerGroup: 2,
|
|
90
|
+
maxRefinementIterations: 3,
|
|
91
|
+
maxFixingIterations: 5,
|
|
92
|
+
topSimilarQueries: 3, // Use top 3 golden queries
|
|
93
|
+
embeddingModel: 'text-embedding-3-small',
|
|
94
|
+
verbose: true
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Generate queries for a single entity with full workflow
|
|
99
|
+
*/
|
|
100
|
+
async function generateQueriesForEntity(
|
|
101
|
+
entityName: string,
|
|
102
|
+
contextUser: UserInfo,
|
|
103
|
+
goldenQueries: GoldenQuery[]
|
|
104
|
+
): Promise<ValidatedQuery[]> {
|
|
105
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
106
|
+
console.log(`Processing Entity: ${entityName}`);
|
|
107
|
+
console.log('='.repeat(80));
|
|
108
|
+
|
|
109
|
+
const validatedQueries: ValidatedQuery[] = [];
|
|
110
|
+
|
|
111
|
+
// Load entity
|
|
112
|
+
const md = new Metadata();
|
|
113
|
+
const entity = md.Entities.find(e => e.Name === entityName);
|
|
114
|
+
if (!entity) {
|
|
115
|
+
console.error(`✗ Entity '${entityName}' not found`);
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log(`✓ Entity loaded: ${entity.Name}`);
|
|
120
|
+
|
|
121
|
+
// Create entity groups
|
|
122
|
+
const grouper = new EntityGrouper();
|
|
123
|
+
const groups = await grouper.generateEntityGroups(
|
|
124
|
+
[entity],
|
|
125
|
+
CUSTOM_CONFIG.minEntitiesPerGroup!,
|
|
126
|
+
CUSTOM_CONFIG.maxEntitiesPerGroup!
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
console.log(`✓ Created ${groups.length} entity group(s)`);
|
|
130
|
+
|
|
131
|
+
// Process first group for this example
|
|
132
|
+
const entityGroup = groups[0];
|
|
133
|
+
|
|
134
|
+
// Generate business questions
|
|
135
|
+
const questionGen = new QuestionGenerator(contextUser);
|
|
136
|
+
const questions = await questionGen.generateQuestions(entityGroup);
|
|
137
|
+
|
|
138
|
+
console.log(`✓ Generated ${questions.length} business question(s)`);
|
|
139
|
+
|
|
140
|
+
// Initialize services
|
|
141
|
+
const embeddingService = new EmbeddingService(CUSTOM_CONFIG.embeddingModel!);
|
|
142
|
+
const similaritySearch = new SimilaritySearch();
|
|
143
|
+
const dataProvider = Metadata.Provider.DatabaseConnection as DatabaseProviderBase;
|
|
144
|
+
|
|
145
|
+
// Embed golden queries once
|
|
146
|
+
console.log('⟳ Embedding golden queries...');
|
|
147
|
+
const embeddedGolden = await embeddingService.embedGoldenQueries(goldenQueries);
|
|
148
|
+
console.log(`✓ Embedded ${embeddedGolden.length} golden queries`);
|
|
149
|
+
|
|
150
|
+
// Process each question
|
|
151
|
+
for (let i = 0; i < questions.length; i++) {
|
|
152
|
+
const question = questions[i];
|
|
153
|
+
console.log(`\n${'─'.repeat(80)}`);
|
|
154
|
+
console.log(`Question ${i + 1}/${questions.length}: ${question.userQuestion}`);
|
|
155
|
+
console.log('─'.repeat(80));
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
// 1. Embed question for similarity search
|
|
159
|
+
console.log('⟳ Embedding question...');
|
|
160
|
+
const questionEmbeddings = await embeddingService.embedQuery({
|
|
161
|
+
name: '',
|
|
162
|
+
userQuestion: question.userQuestion,
|
|
163
|
+
description: question.description,
|
|
164
|
+
technicalDescription: question.technicalDescription
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// 2. Find similar golden queries
|
|
168
|
+
console.log('⟳ Finding similar golden queries...');
|
|
169
|
+
const fewShotResults = await similaritySearch.findSimilarQueries(
|
|
170
|
+
questionEmbeddings,
|
|
171
|
+
embeddedGolden,
|
|
172
|
+
CUSTOM_CONFIG.topSimilarQueries!
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
console.log(`✓ Found ${fewShotResults.length} similar queries:`);
|
|
176
|
+
fewShotResults.forEach((result, idx) => {
|
|
177
|
+
console.log(` ${idx + 1}. ${result.query.name} (similarity: ${result.similarity.toFixed(3)})`);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const fewShotExamples = fewShotResults.map(r => r.query);
|
|
181
|
+
|
|
182
|
+
// 3. Generate SQL query
|
|
183
|
+
console.log('⟳ Generating SQL query...');
|
|
184
|
+
const entityMetadata = entityGroup.entities.map(e =>
|
|
185
|
+
formatEntityMetadataForPrompt(e, entityGroup.entities)
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const queryWriter = new QueryWriter(contextUser);
|
|
189
|
+
const generatedQuery = await queryWriter.generateQuery(
|
|
190
|
+
question,
|
|
191
|
+
entityMetadata,
|
|
192
|
+
fewShotExamples
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
console.log('✓ Query generated');
|
|
196
|
+
console.log(` Parameters: ${generatedQuery.parameters.length}`);
|
|
197
|
+
console.log(` Output fields: ${generatedQuery.selectClause.length}`);
|
|
198
|
+
|
|
199
|
+
// 4. Test and fix query
|
|
200
|
+
console.log('⟳ Testing query...');
|
|
201
|
+
const tester = new QueryTester(
|
|
202
|
+
dataProvider,
|
|
203
|
+
entityMetadata,
|
|
204
|
+
question,
|
|
205
|
+
contextUser
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const testResult = await tester.testQuery(
|
|
209
|
+
generatedQuery,
|
|
210
|
+
CUSTOM_CONFIG.maxFixingIterations!
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
if (!testResult.success) {
|
|
214
|
+
console.error(`✗ Query test failed: ${testResult.error}`);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
console.log(`✓ Query test passed (${testResult.attempts} attempt(s))`);
|
|
219
|
+
console.log(` Rows returned: ${testResult.rowCount}`);
|
|
220
|
+
|
|
221
|
+
// 5. Refine query with evaluation
|
|
222
|
+
console.log('⟳ Refining query...');
|
|
223
|
+
const refiner = new QueryRefiner(tester, contextUser);
|
|
224
|
+
|
|
225
|
+
const refined = await refiner.refineQuery(
|
|
226
|
+
generatedQuery,
|
|
227
|
+
question,
|
|
228
|
+
entityMetadata,
|
|
229
|
+
CUSTOM_CONFIG.maxRefinementIterations!
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
console.log(`✓ Query refined (${refined.refinementCount} iteration(s))`);
|
|
233
|
+
console.log(' Evaluation:');
|
|
234
|
+
console.log(` Answers question: ${refined.evaluation.answersQuestion}`);
|
|
235
|
+
console.log(` Confidence: ${refined.evaluation.confidence}`);
|
|
236
|
+
console.log(` Needs refinement: ${refined.evaluation.needsRefinement}`);
|
|
237
|
+
|
|
238
|
+
if (refined.evaluation.suggestions.length > 0) {
|
|
239
|
+
console.log(' Suggestions:');
|
|
240
|
+
refined.evaluation.suggestions.forEach(s => {
|
|
241
|
+
console.log(` - ${s}`);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Add to validated queries
|
|
246
|
+
validatedQueries.push({
|
|
247
|
+
businessQuestion: question,
|
|
248
|
+
query: refined.query,
|
|
249
|
+
testResult: refined.testResult,
|
|
250
|
+
evaluation: refined.evaluation,
|
|
251
|
+
entityGroup
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
console.log(`✓ Query validated and added to export list`);
|
|
255
|
+
|
|
256
|
+
} catch (error: unknown) {
|
|
257
|
+
console.error(`✗ Error processing question: ${extractErrorMessage(error, 'Question Processing')}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return validatedQueries;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Main function demonstrating advanced QueryGen usage
|
|
266
|
+
*/
|
|
267
|
+
async function main() {
|
|
268
|
+
console.log('QueryGen Advanced Usage Example\n');
|
|
269
|
+
|
|
270
|
+
// ========================================
|
|
271
|
+
// Setup
|
|
272
|
+
// ========================================
|
|
273
|
+
|
|
274
|
+
const contextUser = new UserInfo();
|
|
275
|
+
contextUser.Email = 'system@example.com';
|
|
276
|
+
contextUser.Name = 'System User';
|
|
277
|
+
contextUser.FirstName = 'System';
|
|
278
|
+
contextUser.LastName = 'User';
|
|
279
|
+
|
|
280
|
+
if (!Metadata.Provider) {
|
|
281
|
+
console.error('ERROR: Metadata provider not configured');
|
|
282
|
+
process.exit(1);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// ========================================
|
|
286
|
+
// Batch Processing Multiple Entities
|
|
287
|
+
// ========================================
|
|
288
|
+
|
|
289
|
+
const targetEntities = ['Customers', 'Orders']; // Customize as needed
|
|
290
|
+
const allValidatedQueries: ValidatedQuery[] = [];
|
|
291
|
+
|
|
292
|
+
console.log('Configuration:');
|
|
293
|
+
console.log(JSON.stringify(CUSTOM_CONFIG, null, 2));
|
|
294
|
+
|
|
295
|
+
for (const entityName of targetEntities) {
|
|
296
|
+
try {
|
|
297
|
+
const queries = await generateQueriesForEntity(
|
|
298
|
+
entityName,
|
|
299
|
+
contextUser,
|
|
300
|
+
GOLDEN_QUERIES
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
allValidatedQueries.push(...queries);
|
|
304
|
+
console.log(`\n✓ ${entityName}: Generated ${queries.length} validated query/queries`);
|
|
305
|
+
|
|
306
|
+
} catch (error: unknown) {
|
|
307
|
+
console.error(`✗ ${entityName}: ${extractErrorMessage(error, 'Entity Processing')}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// ========================================
|
|
312
|
+
// Export Results
|
|
313
|
+
// ========================================
|
|
314
|
+
|
|
315
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
316
|
+
console.log('Exporting Results');
|
|
317
|
+
console.log('='.repeat(80));
|
|
318
|
+
|
|
319
|
+
if (allValidatedQueries.length === 0) {
|
|
320
|
+
console.log('⚠ No queries to export');
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// 1. Export to metadata files
|
|
325
|
+
console.log('\n1. Exporting to metadata files...');
|
|
326
|
+
const exporter = new MetadataExporter();
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
const exportResult = await exporter.exportQueries(
|
|
330
|
+
allValidatedQueries,
|
|
331
|
+
'./examples/output'
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
console.log(`✓ Metadata export complete`);
|
|
335
|
+
console.log(` Output path: ${exportResult.outputPath}`);
|
|
336
|
+
console.log(` Query count: ${exportResult.queryCount}`);
|
|
337
|
+
} catch (error: unknown) {
|
|
338
|
+
console.error(`✗ Metadata export failed: ${extractErrorMessage(error, 'Metadata Export')}`);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// 2. Export to database
|
|
342
|
+
console.log('\n2. Exporting to database...');
|
|
343
|
+
const dbWriter = new QueryDatabaseWriter();
|
|
344
|
+
|
|
345
|
+
try {
|
|
346
|
+
await dbWriter.writeQueriesToDatabase(allValidatedQueries, contextUser);
|
|
347
|
+
console.log(`✓ Database export complete`);
|
|
348
|
+
console.log(` Query count: ${allValidatedQueries.length}`);
|
|
349
|
+
} catch (error: unknown) {
|
|
350
|
+
console.error(`✗ Database export failed: ${extractErrorMessage(error, 'Database Export')}`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ========================================
|
|
354
|
+
// Summary
|
|
355
|
+
// ========================================
|
|
356
|
+
|
|
357
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
358
|
+
console.log('Advanced QueryGen Workflow Complete!');
|
|
359
|
+
console.log('='.repeat(80));
|
|
360
|
+
console.log();
|
|
361
|
+
console.log('Summary:');
|
|
362
|
+
console.log(` Entities Processed: ${targetEntities.length}`);
|
|
363
|
+
console.log(` Total Queries Generated: ${allValidatedQueries.length}`);
|
|
364
|
+
console.log(` Golden Queries Used: ${GOLDEN_QUERIES.length}`);
|
|
365
|
+
console.log(` Max Entities Per Group: ${CUSTOM_CONFIG.maxEntitiesPerGroup}`);
|
|
366
|
+
console.log(` Max Refinement Iterations: ${CUSTOM_CONFIG.maxRefinementIterations}`);
|
|
367
|
+
console.log();
|
|
368
|
+
|
|
369
|
+
// Show query breakdown
|
|
370
|
+
if (allValidatedQueries.length > 0) {
|
|
371
|
+
console.log('Query Breakdown:');
|
|
372
|
+
allValidatedQueries.forEach((vq, i) => {
|
|
373
|
+
console.log(` ${i + 1}. ${vq.businessQuestion.userQuestion}`);
|
|
374
|
+
console.log(` Entities: ${vq.entityGroup.entities.map(e => e.Name).join(', ')}`);
|
|
375
|
+
console.log(` Test: ${vq.testResult.success ? 'Passed' : 'Failed'}`);
|
|
376
|
+
console.log(` Evaluation: ${vq.evaluation.answersQuestion ? 'Passed' : 'Failed'} (confidence: ${vq.evaluation.confidence})`);
|
|
377
|
+
});
|
|
378
|
+
console.log();
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
console.log('Features Demonstrated:');
|
|
382
|
+
console.log(' ✓ Vector similarity search with golden queries');
|
|
383
|
+
console.log(' ✓ Few-shot learning with similar examples');
|
|
384
|
+
console.log(' ✓ Automatic query testing and error fixing');
|
|
385
|
+
console.log(' ✓ AI-powered query evaluation and refinement');
|
|
386
|
+
console.log(' ✓ Batch processing of multiple entities');
|
|
387
|
+
console.log(' ✓ Export to both metadata files and database');
|
|
388
|
+
console.log(' ✓ Custom configuration');
|
|
389
|
+
console.log();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Run main function
|
|
393
|
+
main()
|
|
394
|
+
.then(() => {
|
|
395
|
+
console.log('✓ Example completed successfully');
|
|
396
|
+
process.exit(0);
|
|
397
|
+
})
|
|
398
|
+
.catch((error: unknown) => {
|
|
399
|
+
console.error('✗ Example failed:', extractErrorMessage(error, 'Advanced Usage Example'));
|
|
400
|
+
process.exit(1);
|
|
401
|
+
});
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Basic Usage Example for QueryGen
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates the fundamental workflow:
|
|
5
|
+
* 1. Load entities
|
|
6
|
+
* 2. Create entity groups
|
|
7
|
+
* 3. Generate business questions
|
|
8
|
+
* 4. Generate SQL queries
|
|
9
|
+
* 5. Test queries
|
|
10
|
+
* 6. Export results
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
EntityGrouper,
|
|
15
|
+
QuestionGenerator,
|
|
16
|
+
QueryWriter,
|
|
17
|
+
QueryTester,
|
|
18
|
+
MetadataExporter,
|
|
19
|
+
formatEntityMetadataForPrompt,
|
|
20
|
+
extractErrorMessage,
|
|
21
|
+
ValidatedQuery
|
|
22
|
+
} from '@memberjunction/query-gen';
|
|
23
|
+
import { Metadata, UserInfo, DatabaseProviderBase } from '@memberjunction/core';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Main function demonstrating basic QueryGen usage
|
|
27
|
+
*/
|
|
28
|
+
async function main() {
|
|
29
|
+
console.log('QueryGen Basic Usage Example\n');
|
|
30
|
+
|
|
31
|
+
// ========================================
|
|
32
|
+
// Step 1: Setup
|
|
33
|
+
// ========================================
|
|
34
|
+
|
|
35
|
+
// Create context user for server-side operations
|
|
36
|
+
const contextUser = new UserInfo();
|
|
37
|
+
contextUser.Email = 'system@example.com';
|
|
38
|
+
contextUser.Name = 'System User';
|
|
39
|
+
contextUser.FirstName = 'System';
|
|
40
|
+
contextUser.LastName = 'User';
|
|
41
|
+
|
|
42
|
+
// Ensure metadata provider is configured
|
|
43
|
+
if (!Metadata.Provider) {
|
|
44
|
+
console.error('ERROR: Metadata provider not configured');
|
|
45
|
+
console.error('Please configure database connection before running this example');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ========================================
|
|
50
|
+
// Step 2: Load Entities
|
|
51
|
+
// ========================================
|
|
52
|
+
|
|
53
|
+
console.log('Step 1: Loading entities...');
|
|
54
|
+
const md = new Metadata();
|
|
55
|
+
|
|
56
|
+
// Filter to specific entity for this example
|
|
57
|
+
const targetEntityName = 'Customers'; // Change this to test with different entities
|
|
58
|
+
const entity = md.Entities.find(e => e.Name === targetEntityName);
|
|
59
|
+
|
|
60
|
+
if (!entity) {
|
|
61
|
+
console.error(`ERROR: Entity '${targetEntityName}' not found`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log(`✓ Found entity: ${entity.Name}\n`);
|
|
66
|
+
|
|
67
|
+
// ========================================
|
|
68
|
+
// Step 3: Create Entity Groups
|
|
69
|
+
// ========================================
|
|
70
|
+
|
|
71
|
+
console.log('Step 2: Creating entity groups...');
|
|
72
|
+
const grouper = new EntityGrouper();
|
|
73
|
+
|
|
74
|
+
// Create groups of 1-2 entities
|
|
75
|
+
const groups = await grouper.generateEntityGroups([entity], 1, 2);
|
|
76
|
+
|
|
77
|
+
console.log(`✓ Created ${groups.length} entity group(s)\n`);
|
|
78
|
+
|
|
79
|
+
// Show first group
|
|
80
|
+
const entityGroup = groups[0];
|
|
81
|
+
console.log('Entity group:', {
|
|
82
|
+
entities: entityGroup.entities.map(e => e.Name),
|
|
83
|
+
relationshipType: entityGroup.relationshipType,
|
|
84
|
+
primaryEntity: entityGroup.primaryEntity.Name
|
|
85
|
+
});
|
|
86
|
+
console.log();
|
|
87
|
+
|
|
88
|
+
// ========================================
|
|
89
|
+
// Step 4: Generate Business Questions
|
|
90
|
+
// ========================================
|
|
91
|
+
|
|
92
|
+
console.log('Step 3: Generating business questions...');
|
|
93
|
+
const questionGen = new QuestionGenerator(contextUser);
|
|
94
|
+
|
|
95
|
+
let questions;
|
|
96
|
+
try {
|
|
97
|
+
questions = await questionGen.generateQuestions(entityGroup);
|
|
98
|
+
console.log(`✓ Generated ${questions.length} business question(s)\n`);
|
|
99
|
+
|
|
100
|
+
// Show questions
|
|
101
|
+
questions.forEach((q, i) => {
|
|
102
|
+
console.log(`Question ${i + 1}:`);
|
|
103
|
+
console.log(` User Question: ${q.userQuestion}`);
|
|
104
|
+
console.log(` Description: ${q.description}`);
|
|
105
|
+
console.log(` Complexity: ${q.complexity}`);
|
|
106
|
+
console.log(` Requires Aggregation: ${q.requiresAggregation}`);
|
|
107
|
+
console.log(` Requires Joins: ${q.requiresJoins}`);
|
|
108
|
+
console.log();
|
|
109
|
+
});
|
|
110
|
+
} catch (error: unknown) {
|
|
111
|
+
console.error('ERROR generating questions:', extractErrorMessage(error, 'Question Generation'));
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ========================================
|
|
116
|
+
// Step 5: Generate SQL Query
|
|
117
|
+
// ========================================
|
|
118
|
+
|
|
119
|
+
console.log('Step 4: Generating SQL query...');
|
|
120
|
+
|
|
121
|
+
// Format entity metadata for prompt
|
|
122
|
+
const entityMetadata = entityGroup.entities.map(e =>
|
|
123
|
+
formatEntityMetadataForPrompt(e, entityGroup.entities)
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
// Use first question for this example
|
|
127
|
+
const businessQuestion = questions[0];
|
|
128
|
+
|
|
129
|
+
// For this basic example, we'll skip few-shot learning (no golden queries)
|
|
130
|
+
const fewShotExamples: any[] = [];
|
|
131
|
+
|
|
132
|
+
const queryWriter = new QueryWriter(contextUser);
|
|
133
|
+
|
|
134
|
+
let generatedQuery;
|
|
135
|
+
try {
|
|
136
|
+
generatedQuery = await queryWriter.generateQuery(
|
|
137
|
+
businessQuestion,
|
|
138
|
+
entityMetadata,
|
|
139
|
+
fewShotExamples
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
console.log('✓ Generated SQL query\n');
|
|
143
|
+
console.log('SQL Template:');
|
|
144
|
+
console.log('─'.repeat(80));
|
|
145
|
+
console.log(generatedQuery.sql);
|
|
146
|
+
console.log('─'.repeat(80));
|
|
147
|
+
console.log();
|
|
148
|
+
|
|
149
|
+
console.log('Parameters:', generatedQuery.parameters.length);
|
|
150
|
+
generatedQuery.parameters.forEach(param => {
|
|
151
|
+
console.log(` - ${param.name} (${param.type}): ${param.description}`);
|
|
152
|
+
});
|
|
153
|
+
console.log();
|
|
154
|
+
|
|
155
|
+
console.log('Output Fields:', generatedQuery.selectClause.length);
|
|
156
|
+
generatedQuery.selectClause.forEach(field => {
|
|
157
|
+
console.log(` - ${field.name} (${field.type}): ${field.description}`);
|
|
158
|
+
});
|
|
159
|
+
console.log();
|
|
160
|
+
} catch (error: unknown) {
|
|
161
|
+
console.error('ERROR generating query:', extractErrorMessage(error, 'Query Generation'));
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ========================================
|
|
166
|
+
// Step 6: Test Query
|
|
167
|
+
// ========================================
|
|
168
|
+
|
|
169
|
+
console.log('Step 5: Testing query...');
|
|
170
|
+
|
|
171
|
+
const dataProvider = Metadata.Provider.DatabaseConnection as DatabaseProviderBase;
|
|
172
|
+
const tester = new QueryTester(
|
|
173
|
+
dataProvider,
|
|
174
|
+
entityMetadata,
|
|
175
|
+
businessQuestion,
|
|
176
|
+
contextUser
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
let testResult;
|
|
180
|
+
try {
|
|
181
|
+
// Test with up to 5 error-fixing attempts
|
|
182
|
+
testResult = await tester.testQuery(generatedQuery, 5);
|
|
183
|
+
|
|
184
|
+
if (testResult.success) {
|
|
185
|
+
console.log(`✓ Query test passed in ${testResult.attempts} attempt(s)`);
|
|
186
|
+
console.log(` Rows returned: ${testResult.rowCount}`);
|
|
187
|
+
console.log();
|
|
188
|
+
|
|
189
|
+
// Show sample results (first 3 rows)
|
|
190
|
+
if (testResult.sampleRows && testResult.sampleRows.length > 0) {
|
|
191
|
+
console.log('Sample Results (first 3 rows):');
|
|
192
|
+
console.log('─'.repeat(80));
|
|
193
|
+
testResult.sampleRows.slice(0, 3).forEach((row, i) => {
|
|
194
|
+
console.log(`Row ${i + 1}:`, JSON.stringify(row, null, 2));
|
|
195
|
+
});
|
|
196
|
+
console.log('─'.repeat(80));
|
|
197
|
+
console.log();
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
console.error(`✗ Query test failed after ${testResult.attempts} attempt(s)`);
|
|
201
|
+
console.error(' Error:', testResult.error);
|
|
202
|
+
console.log();
|
|
203
|
+
console.log('Note: This example will continue with export despite test failure');
|
|
204
|
+
console.log();
|
|
205
|
+
}
|
|
206
|
+
} catch (error: unknown) {
|
|
207
|
+
console.error('ERROR testing query:', extractErrorMessage(error, 'Query Testing'));
|
|
208
|
+
console.log('Note: This example will continue with export despite test error');
|
|
209
|
+
console.log();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ========================================
|
|
213
|
+
// Step 7: Export Results
|
|
214
|
+
// ========================================
|
|
215
|
+
|
|
216
|
+
console.log('Step 6: Exporting query...');
|
|
217
|
+
|
|
218
|
+
// Create ValidatedQuery object
|
|
219
|
+
const validatedQuery: ValidatedQuery = {
|
|
220
|
+
businessQuestion,
|
|
221
|
+
query: generatedQuery,
|
|
222
|
+
testResult: testResult || {
|
|
223
|
+
success: false,
|
|
224
|
+
error: 'Test was skipped or failed',
|
|
225
|
+
attempts: 0
|
|
226
|
+
},
|
|
227
|
+
evaluation: {
|
|
228
|
+
answersQuestion: true,
|
|
229
|
+
confidence: 0.8,
|
|
230
|
+
reasoning: 'Basic example - no formal evaluation performed',
|
|
231
|
+
suggestions: [],
|
|
232
|
+
needsRefinement: false
|
|
233
|
+
},
|
|
234
|
+
entityGroup
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const exporter = new MetadataExporter();
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
const exportResult = await exporter.exportQueries(
|
|
241
|
+
[validatedQuery],
|
|
242
|
+
'./examples/output'
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
console.log(`✓ Query exported successfully`);
|
|
246
|
+
console.log(` Output path: ${exportResult.outputPath}`);
|
|
247
|
+
console.log(` Query count: ${exportResult.queryCount}`);
|
|
248
|
+
console.log();
|
|
249
|
+
} catch (error: unknown) {
|
|
250
|
+
console.error('ERROR exporting query:', extractErrorMessage(error, 'Query Export'));
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ========================================
|
|
255
|
+
// Summary
|
|
256
|
+
// ========================================
|
|
257
|
+
|
|
258
|
+
console.log('═'.repeat(80));
|
|
259
|
+
console.log('Basic QueryGen Workflow Complete!');
|
|
260
|
+
console.log('═'.repeat(80));
|
|
261
|
+
console.log();
|
|
262
|
+
console.log('Summary:');
|
|
263
|
+
console.log(` Entity: ${entity.Name}`);
|
|
264
|
+
console.log(` Questions Generated: ${questions.length}`);
|
|
265
|
+
console.log(` Query Generated: Yes`);
|
|
266
|
+
console.log(` Query Tested: ${testResult?.success ? 'Passed' : 'Failed/Skipped'}`);
|
|
267
|
+
console.log(` Query Exported: Yes`);
|
|
268
|
+
console.log();
|
|
269
|
+
console.log('Next Steps:');
|
|
270
|
+
console.log(' 1. Review the exported query metadata file');
|
|
271
|
+
console.log(' 2. Test the query with different parameter values');
|
|
272
|
+
console.log(' 3. Run the advanced-usage.ts example for refinement workflow');
|
|
273
|
+
console.log();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Run main function
|
|
277
|
+
main()
|
|
278
|
+
.then(() => {
|
|
279
|
+
console.log('✓ Example completed successfully');
|
|
280
|
+
process.exit(0);
|
|
281
|
+
})
|
|
282
|
+
.catch((error: unknown) => {
|
|
283
|
+
console.error('✗ Example failed:', extractErrorMessage(error, 'Basic Usage Example'));
|
|
284
|
+
process.exit(1);
|
|
285
|
+
});
|