@memberjunction/query-gen 0.0.1 → 2.126.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +20 -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
package/docs/API.md
ADDED
|
@@ -0,0 +1,1040 @@
|
|
|
1
|
+
# QueryGen API Documentation
|
|
2
|
+
|
|
3
|
+
This document provides comprehensive API documentation for programmatic usage of the QueryGen package.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Core Classes](#core-classes)
|
|
9
|
+
- [Usage Patterns](#usage-patterns)
|
|
10
|
+
- [TypeScript Types](#typescript-types)
|
|
11
|
+
- [Configuration](#configuration)
|
|
12
|
+
- [Examples](#examples)
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @memberjunction/query-gen
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Core Classes
|
|
21
|
+
|
|
22
|
+
### EntityGrouper
|
|
23
|
+
|
|
24
|
+
Analyzes entity relationships and creates logical groups for query generation.
|
|
25
|
+
|
|
26
|
+
#### Constructor
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
new EntityGrouper()
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
#### Methods
|
|
33
|
+
|
|
34
|
+
##### `generateEntityGroups()`
|
|
35
|
+
|
|
36
|
+
Generates entity groups from available entities based on foreign key relationships.
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
async generateEntityGroups(
|
|
40
|
+
entities: EntityInfo[],
|
|
41
|
+
minSize: number,
|
|
42
|
+
maxSize: number
|
|
43
|
+
): Promise<EntityGroup[]>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Parameters:**
|
|
47
|
+
- `entities` - Array of EntityInfo objects to analyze
|
|
48
|
+
- `minSize` - Minimum number of entities per group (usually 1)
|
|
49
|
+
- `maxSize` - Maximum number of entities per group (typically 3)
|
|
50
|
+
|
|
51
|
+
**Returns:** Array of EntityGroup objects with relationship metadata
|
|
52
|
+
|
|
53
|
+
**Example:**
|
|
54
|
+
```typescript
|
|
55
|
+
import { EntityGrouper } from '@memberjunction/query-gen';
|
|
56
|
+
import { Metadata } from '@memberjunction/core';
|
|
57
|
+
|
|
58
|
+
const md = new Metadata();
|
|
59
|
+
const entities = md.Entities.filter(e => e.SchemaName === 'dbo');
|
|
60
|
+
|
|
61
|
+
const grouper = new EntityGrouper();
|
|
62
|
+
const groups = await grouper.generateEntityGroups(entities, 1, 3);
|
|
63
|
+
|
|
64
|
+
console.log(`Generated ${groups.length} entity groups`);
|
|
65
|
+
// Output: Generated 42 entity groups
|
|
66
|
+
|
|
67
|
+
// Single entity group
|
|
68
|
+
console.log(groups[0]);
|
|
69
|
+
// {
|
|
70
|
+
// entities: [CustomersEntity],
|
|
71
|
+
// relationships: [],
|
|
72
|
+
// primaryEntity: CustomersEntity,
|
|
73
|
+
// relationshipType: 'single'
|
|
74
|
+
// }
|
|
75
|
+
|
|
76
|
+
// Multi-entity group
|
|
77
|
+
console.log(groups[1]);
|
|
78
|
+
// {
|
|
79
|
+
// entities: [CustomersEntity, OrdersEntity],
|
|
80
|
+
// relationships: [
|
|
81
|
+
// { from: 'Orders', to: 'Customers', via: 'CustomerID', type: 'many-to-one' }
|
|
82
|
+
// ],
|
|
83
|
+
// primaryEntity: OrdersEntity,
|
|
84
|
+
// relationshipType: 'parent-child'
|
|
85
|
+
// }
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### QuestionGenerator
|
|
91
|
+
|
|
92
|
+
Generates domain-specific business questions using AI.
|
|
93
|
+
|
|
94
|
+
#### Constructor
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
new QuestionGenerator(contextUser: UserInfo)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Parameters:**
|
|
101
|
+
- `contextUser` - User context for server-side operations
|
|
102
|
+
|
|
103
|
+
#### Methods
|
|
104
|
+
|
|
105
|
+
##### `generateQuestions()`
|
|
106
|
+
|
|
107
|
+
Generates 1-2 business questions for an entity group using AI.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
async generateQuestions(
|
|
111
|
+
entityGroup: EntityGroup
|
|
112
|
+
): Promise<BusinessQuestion[]>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Parameters:**
|
|
116
|
+
- `entityGroup` - Entity group to generate questions for
|
|
117
|
+
|
|
118
|
+
**Returns:** Array of BusinessQuestion objects
|
|
119
|
+
|
|
120
|
+
**Example:**
|
|
121
|
+
```typescript
|
|
122
|
+
import { QuestionGenerator } from '@memberjunction/query-gen';
|
|
123
|
+
import { UserInfo } from '@memberjunction/core';
|
|
124
|
+
|
|
125
|
+
const contextUser = new UserInfo();
|
|
126
|
+
contextUser.Email = 'user@example.com';
|
|
127
|
+
contextUser.Name = 'Test User';
|
|
128
|
+
|
|
129
|
+
const generator = new QuestionGenerator(contextUser);
|
|
130
|
+
const questions = await generator.generateQuestions(entityGroup);
|
|
131
|
+
|
|
132
|
+
console.log(questions);
|
|
133
|
+
// [
|
|
134
|
+
// {
|
|
135
|
+
// userQuestion: "What are the top customers by revenue?",
|
|
136
|
+
// description: "Identify high-value customers based on total order revenue",
|
|
137
|
+
// technicalDescription: "Sum order totals per customer, sort descending, limit to top 10",
|
|
138
|
+
// complexity: "medium",
|
|
139
|
+
// requiresAggregation: true,
|
|
140
|
+
// requiresJoins: true,
|
|
141
|
+
// entities: ["Customers", "Orders"]
|
|
142
|
+
// },
|
|
143
|
+
// {
|
|
144
|
+
// userQuestion: "How many orders does each customer have?",
|
|
145
|
+
// description: "Count number of orders per customer",
|
|
146
|
+
// technicalDescription: "Count orders grouped by customer",
|
|
147
|
+
// complexity: "simple",
|
|
148
|
+
// requiresAggregation: true,
|
|
149
|
+
// requiresJoins: true,
|
|
150
|
+
// entities: ["Customers", "Orders"]
|
|
151
|
+
// }
|
|
152
|
+
// ]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### QueryWriter
|
|
158
|
+
|
|
159
|
+
Generates SQL query templates using AI with few-shot learning.
|
|
160
|
+
|
|
161
|
+
#### Constructor
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
new QueryWriter(contextUser: UserInfo)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Parameters:**
|
|
168
|
+
- `contextUser` - User context for server-side operations
|
|
169
|
+
|
|
170
|
+
#### Methods
|
|
171
|
+
|
|
172
|
+
##### `generateQuery()`
|
|
173
|
+
|
|
174
|
+
Generates a Nunjucks SQL query template from a business question.
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
async generateQuery(
|
|
178
|
+
businessQuestion: BusinessQuestion,
|
|
179
|
+
entityMetadata: EntityMetadataForPrompt[],
|
|
180
|
+
fewShotExamples: GoldenQuery[]
|
|
181
|
+
): Promise<GeneratedQuery>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Parameters:**
|
|
185
|
+
- `businessQuestion` - The business question to answer
|
|
186
|
+
- `entityMetadata` - Formatted metadata for entities involved
|
|
187
|
+
- `fewShotExamples` - Similar golden queries for few-shot learning
|
|
188
|
+
|
|
189
|
+
**Returns:** GeneratedQuery object with SQL, parameters, and output fields
|
|
190
|
+
|
|
191
|
+
**Example:**
|
|
192
|
+
```typescript
|
|
193
|
+
import { QueryWriter, formatEntityMetadataForPrompt } from '@memberjunction/query-gen';
|
|
194
|
+
import { UserInfo } from '@memberjunction/core';
|
|
195
|
+
|
|
196
|
+
const contextUser = new UserInfo();
|
|
197
|
+
const writer = new QueryWriter(contextUser);
|
|
198
|
+
|
|
199
|
+
// Format entity metadata for prompt
|
|
200
|
+
const entityMetadata = entityGroup.entities.map(e =>
|
|
201
|
+
formatEntityMetadataForPrompt(e, entityGroup.entities)
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
// Find similar golden queries (from vector similarity search)
|
|
205
|
+
const fewShotExamples = []; // Array of GoldenQuery objects
|
|
206
|
+
|
|
207
|
+
// Generate query
|
|
208
|
+
const query = await writer.generateQuery(
|
|
209
|
+
businessQuestion,
|
|
210
|
+
entityMetadata,
|
|
211
|
+
fewShotExamples
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
console.log(query.sql);
|
|
215
|
+
// SELECT
|
|
216
|
+
// c.Name as CustomerName,
|
|
217
|
+
// COUNT(o.ID) as OrderCount,
|
|
218
|
+
// COALESCE(SUM(o.Total), 0) as TotalRevenue
|
|
219
|
+
// FROM [dbo].[vwCustomers] c
|
|
220
|
+
// LEFT JOIN [sales].[vwOrders] o ON o.CustomerID = c.ID
|
|
221
|
+
// WHERE c.Name LIKE {{ searchTerm | sqlString }}
|
|
222
|
+
// GROUP BY c.Name
|
|
223
|
+
// ORDER BY TotalRevenue DESC
|
|
224
|
+
|
|
225
|
+
console.log(query.parameters);
|
|
226
|
+
// [
|
|
227
|
+
// {
|
|
228
|
+
// name: 'searchTerm',
|
|
229
|
+
// type: 'string',
|
|
230
|
+
// isRequired: false,
|
|
231
|
+
// description: 'Customer name search term',
|
|
232
|
+
// usage: ['WHERE clause: c.Name LIKE searchTerm'],
|
|
233
|
+
// defaultValue: null,
|
|
234
|
+
// sampleValue: '%Smith%'
|
|
235
|
+
// }
|
|
236
|
+
// ]
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
### QueryTester
|
|
242
|
+
|
|
243
|
+
Tests generated queries by executing them against the database.
|
|
244
|
+
|
|
245
|
+
#### Constructor
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
new QueryTester(
|
|
249
|
+
dataProvider: DatabaseProviderBase,
|
|
250
|
+
entityMetadata: EntityMetadataForPrompt[],
|
|
251
|
+
businessQuestion: BusinessQuestion,
|
|
252
|
+
contextUser: UserInfo
|
|
253
|
+
)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Parameters:**
|
|
257
|
+
- `dataProvider` - Database provider for SQL execution
|
|
258
|
+
- `entityMetadata` - Entity metadata for error context
|
|
259
|
+
- `businessQuestion` - Business question for error context
|
|
260
|
+
- `contextUser` - User context for server-side operations
|
|
261
|
+
|
|
262
|
+
#### Methods
|
|
263
|
+
|
|
264
|
+
##### `testQuery()`
|
|
265
|
+
|
|
266
|
+
Tests a query by rendering and executing it. Automatically fixes errors up to maxAttempts.
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
async testQuery(
|
|
270
|
+
query: GeneratedQuery,
|
|
271
|
+
maxAttempts: number = 5
|
|
272
|
+
): Promise<QueryTestResult>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Parameters:**
|
|
276
|
+
- `query` - The query to test
|
|
277
|
+
- `maxAttempts` - Maximum error-fixing attempts (default: 5)
|
|
278
|
+
|
|
279
|
+
**Returns:** QueryTestResult with success status, rendered SQL, and sample rows
|
|
280
|
+
|
|
281
|
+
**Example:**
|
|
282
|
+
```typescript
|
|
283
|
+
import { QueryTester } from '@memberjunction/query-gen';
|
|
284
|
+
import { Metadata, UserInfo } from '@memberjunction/core';
|
|
285
|
+
|
|
286
|
+
const dataProvider = Metadata.Provider.DatabaseConnection as DatabaseProviderBase;
|
|
287
|
+
const contextUser = new UserInfo();
|
|
288
|
+
|
|
289
|
+
const tester = new QueryTester(
|
|
290
|
+
dataProvider,
|
|
291
|
+
entityMetadata,
|
|
292
|
+
businessQuestion,
|
|
293
|
+
contextUser
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
const result = await tester.testQuery(query, 5);
|
|
297
|
+
|
|
298
|
+
if (result.success) {
|
|
299
|
+
console.log(`Query returned ${result.rowCount} rows in ${result.attempts} attempt(s)`);
|
|
300
|
+
console.log('Sample rows:', result.sampleRows);
|
|
301
|
+
console.log('Rendered SQL:', result.renderedSQL);
|
|
302
|
+
} else {
|
|
303
|
+
console.error(`Query failed after ${result.attempts} attempts:`, result.error);
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
### QueryFixer
|
|
310
|
+
|
|
311
|
+
Fixes SQL errors using AI.
|
|
312
|
+
|
|
313
|
+
#### Constructor
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
new QueryFixer(
|
|
317
|
+
entityMetadata: EntityMetadataForPrompt[],
|
|
318
|
+
businessQuestion: BusinessQuestion,
|
|
319
|
+
contextUser: UserInfo
|
|
320
|
+
)
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Parameters:**
|
|
324
|
+
- `entityMetadata` - Entity metadata for error context
|
|
325
|
+
- `businessQuestion` - Business question for error context
|
|
326
|
+
- `contextUser` - User context for server-side operations
|
|
327
|
+
|
|
328
|
+
#### Methods
|
|
329
|
+
|
|
330
|
+
##### `fixQuery()`
|
|
331
|
+
|
|
332
|
+
Fixes a broken SQL query using AI analysis of the error message.
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
async fixQuery(
|
|
336
|
+
query: GeneratedQuery,
|
|
337
|
+
errorMessage: string
|
|
338
|
+
): Promise<GeneratedQuery>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Parameters:**
|
|
342
|
+
- `query` - The broken query
|
|
343
|
+
- `errorMessage` - SQL error message from database
|
|
344
|
+
|
|
345
|
+
**Returns:** Fixed GeneratedQuery
|
|
346
|
+
|
|
347
|
+
**Example:**
|
|
348
|
+
```typescript
|
|
349
|
+
import { QueryFixer } from '@memberjunction/query-gen';
|
|
350
|
+
import { UserInfo } from '@memberjunction/core';
|
|
351
|
+
|
|
352
|
+
const contextUser = new UserInfo();
|
|
353
|
+
const fixer = new QueryFixer(entityMetadata, businessQuestion, contextUser);
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
const result = await dataProvider.ExecuteSQL(renderedSQL);
|
|
357
|
+
} catch (error) {
|
|
358
|
+
// Fix the query
|
|
359
|
+
const errorMsg = extractErrorMessage(error, 'SQL Execution');
|
|
360
|
+
const fixedQuery = await fixer.fixQuery(query, errorMsg);
|
|
361
|
+
|
|
362
|
+
// Try again with fixed query
|
|
363
|
+
const fixedSQL = renderTemplate(fixedQuery);
|
|
364
|
+
const result = await dataProvider.ExecuteSQL(fixedSQL);
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
### QueryRefiner
|
|
371
|
+
|
|
372
|
+
Evaluates and refines queries iteratively using AI feedback.
|
|
373
|
+
|
|
374
|
+
#### Constructor
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
new QueryRefiner(
|
|
378
|
+
queryTester: QueryTester,
|
|
379
|
+
contextUser: UserInfo
|
|
380
|
+
)
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
**Parameters:**
|
|
384
|
+
- `queryTester` - QueryTester instance for executing queries
|
|
385
|
+
- `contextUser` - User context for server-side operations
|
|
386
|
+
|
|
387
|
+
#### Methods
|
|
388
|
+
|
|
389
|
+
##### `refineQuery()`
|
|
390
|
+
|
|
391
|
+
Evaluates and refines a query through iterative feedback loops.
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
async refineQuery(
|
|
395
|
+
query: GeneratedQuery,
|
|
396
|
+
businessQuestion: BusinessQuestion,
|
|
397
|
+
entityMetadata: EntityMetadataForPrompt[],
|
|
398
|
+
maxRefinements: number = 3
|
|
399
|
+
): Promise<RefinedQuery>
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**Parameters:**
|
|
403
|
+
- `query` - The query to refine
|
|
404
|
+
- `businessQuestion` - Business question for evaluation context
|
|
405
|
+
- `entityMetadata` - Entity metadata for refinement context
|
|
406
|
+
- `maxRefinements` - Maximum refinement iterations (default: 3)
|
|
407
|
+
|
|
408
|
+
**Returns:** RefinedQuery with final query, test results, and evaluation
|
|
409
|
+
|
|
410
|
+
**Example:**
|
|
411
|
+
```typescript
|
|
412
|
+
import { QueryRefiner } from '@memberjunction/query-gen';
|
|
413
|
+
import { UserInfo } from '@memberjunction/core';
|
|
414
|
+
|
|
415
|
+
const contextUser = new UserInfo();
|
|
416
|
+
const refiner = new QueryRefiner(queryTester, contextUser);
|
|
417
|
+
|
|
418
|
+
const refined = await refiner.refineQuery(
|
|
419
|
+
query,
|
|
420
|
+
businessQuestion,
|
|
421
|
+
entityMetadata,
|
|
422
|
+
3 // max 3 refinement cycles
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
console.log(`Refined in ${refined.refinementCount} iteration(s)`);
|
|
426
|
+
console.log('Evaluation:', refined.evaluation);
|
|
427
|
+
// {
|
|
428
|
+
// answersQuestion: true,
|
|
429
|
+
// confidence: 0.95,
|
|
430
|
+
// reasoning: "Query correctly aggregates...",
|
|
431
|
+
// suggestions: [],
|
|
432
|
+
// needsRefinement: false
|
|
433
|
+
// }
|
|
434
|
+
|
|
435
|
+
console.log('Final query:', refined.query.sql);
|
|
436
|
+
console.log('Test result:', refined.testResult);
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
### MetadataExporter
|
|
442
|
+
|
|
443
|
+
Exports validated queries to MemberJunction metadata format.
|
|
444
|
+
|
|
445
|
+
#### Constructor
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
new MetadataExporter()
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
#### Methods
|
|
452
|
+
|
|
453
|
+
##### `exportQueries()`
|
|
454
|
+
|
|
455
|
+
Exports queries to JSON metadata files.
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
async exportQueries(
|
|
459
|
+
validatedQueries: ValidatedQuery[],
|
|
460
|
+
outputDirectory: string
|
|
461
|
+
): Promise<ExportResult>
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
**Parameters:**
|
|
465
|
+
- `validatedQueries` - Array of validated queries to export
|
|
466
|
+
- `outputDirectory` - Directory path for output files
|
|
467
|
+
|
|
468
|
+
**Returns:** ExportResult with output path and query count
|
|
469
|
+
|
|
470
|
+
**Example:**
|
|
471
|
+
```typescript
|
|
472
|
+
import { MetadataExporter } from '@memberjunction/query-gen';
|
|
473
|
+
|
|
474
|
+
const exporter = new MetadataExporter();
|
|
475
|
+
const result = await exporter.exportQueries(
|
|
476
|
+
validatedQueries,
|
|
477
|
+
'./metadata/queries'
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
console.log(`Exported ${result.queryCount} queries to ${result.outputPath}`);
|
|
481
|
+
// Exported 15 queries to ./metadata/queries/queries-1234567890.json
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
### QueryDatabaseWriter
|
|
487
|
+
|
|
488
|
+
Writes queries directly to the database.
|
|
489
|
+
|
|
490
|
+
#### Constructor
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
new QueryDatabaseWriter()
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
#### Methods
|
|
497
|
+
|
|
498
|
+
##### `writeQueriesToDatabase()`
|
|
499
|
+
|
|
500
|
+
Inserts queries into Queries, Query Fields, and Query Params tables.
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
async writeQueriesToDatabase(
|
|
504
|
+
validatedQueries: ValidatedQuery[],
|
|
505
|
+
contextUser: UserInfo
|
|
506
|
+
): Promise<void>
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
**Parameters:**
|
|
510
|
+
- `validatedQueries` - Array of validated queries to write
|
|
511
|
+
- `contextUser` - User context for entity operations
|
|
512
|
+
|
|
513
|
+
**Example:**
|
|
514
|
+
```typescript
|
|
515
|
+
import { QueryDatabaseWriter } from '@memberjunction/query-gen';
|
|
516
|
+
import { UserInfo } from '@memberjunction/core';
|
|
517
|
+
|
|
518
|
+
const contextUser = new UserInfo();
|
|
519
|
+
const writer = new QueryDatabaseWriter();
|
|
520
|
+
|
|
521
|
+
await writer.writeQueriesToDatabase(validatedQueries, contextUser);
|
|
522
|
+
console.log(`Wrote ${validatedQueries.length} queries to database`);
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
### EmbeddingService
|
|
528
|
+
|
|
529
|
+
Generates vector embeddings for similarity search.
|
|
530
|
+
|
|
531
|
+
#### Constructor
|
|
532
|
+
|
|
533
|
+
```typescript
|
|
534
|
+
new EmbeddingService(modelName: string)
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
**Parameters:**
|
|
538
|
+
- `modelName` - Embedding model name (default: 'text-embedding-3-small')
|
|
539
|
+
|
|
540
|
+
#### Methods
|
|
541
|
+
|
|
542
|
+
##### `embedQuery()`
|
|
543
|
+
|
|
544
|
+
Embeds all fields of a query for similarity search.
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
async embedQuery(query: {
|
|
548
|
+
name: string;
|
|
549
|
+
userQuestion: string;
|
|
550
|
+
description: string;
|
|
551
|
+
technicalDescription: string;
|
|
552
|
+
}): Promise<{
|
|
553
|
+
name: number[];
|
|
554
|
+
userQuestion: number[];
|
|
555
|
+
description: number[];
|
|
556
|
+
technicalDescription: number[];
|
|
557
|
+
}>
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**Parameters:**
|
|
561
|
+
- `query` - Query object with fields to embed
|
|
562
|
+
|
|
563
|
+
**Returns:** Embeddings for each field
|
|
564
|
+
|
|
565
|
+
##### `embedGoldenQueries()`
|
|
566
|
+
|
|
567
|
+
Embeds all golden queries for similarity comparison.
|
|
568
|
+
|
|
569
|
+
```typescript
|
|
570
|
+
async embedGoldenQueries(
|
|
571
|
+
goldenQueries: GoldenQuery[]
|
|
572
|
+
): Promise<Array<{
|
|
573
|
+
query: GoldenQuery;
|
|
574
|
+
embeddings: {
|
|
575
|
+
name: number[];
|
|
576
|
+
userQuestion: number[];
|
|
577
|
+
description: number[];
|
|
578
|
+
technicalDescription: number[];
|
|
579
|
+
};
|
|
580
|
+
}>>
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
**Parameters:**
|
|
584
|
+
- `goldenQueries` - Array of golden queries to embed
|
|
585
|
+
|
|
586
|
+
**Returns:** Array of golden queries with their embeddings
|
|
587
|
+
|
|
588
|
+
**Example:**
|
|
589
|
+
```typescript
|
|
590
|
+
import { EmbeddingService } from '@memberjunction/query-gen';
|
|
591
|
+
|
|
592
|
+
const embeddingService = new EmbeddingService('text-embedding-3-small');
|
|
593
|
+
|
|
594
|
+
// Embed a question
|
|
595
|
+
const questionEmbeddings = await embeddingService.embedQuery({
|
|
596
|
+
name: '',
|
|
597
|
+
userQuestion: "What are the top customers by revenue?",
|
|
598
|
+
description: "Identify high-value customers",
|
|
599
|
+
technicalDescription: "Sum order totals per customer"
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
// Embed golden queries
|
|
603
|
+
const goldenQueries = loadGoldenQueries(); // Load from database/files
|
|
604
|
+
const embeddedGolden = await embeddingService.embedGoldenQueries(goldenQueries);
|
|
605
|
+
|
|
606
|
+
console.log(`Embedded ${embeddedGolden.length} golden queries`);
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
---
|
|
610
|
+
|
|
611
|
+
### SimilaritySearch
|
|
612
|
+
|
|
613
|
+
Finds similar queries using weighted cosine similarity.
|
|
614
|
+
|
|
615
|
+
#### Constructor
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
new SimilaritySearch(weights?: {
|
|
619
|
+
name: number;
|
|
620
|
+
userQuestion: number;
|
|
621
|
+
description: number;
|
|
622
|
+
technicalDescription: number;
|
|
623
|
+
})
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
**Parameters:**
|
|
627
|
+
- `weights` - Optional custom similarity weights (defaults to: name=0.1, userQuestion=0.2, description=0.35, technicalDescription=0.35)
|
|
628
|
+
|
|
629
|
+
#### Methods
|
|
630
|
+
|
|
631
|
+
##### `findSimilarQueries()`
|
|
632
|
+
|
|
633
|
+
Finds top-K most similar golden queries using weighted cosine similarity.
|
|
634
|
+
|
|
635
|
+
```typescript
|
|
636
|
+
async findSimilarQueries(
|
|
637
|
+
queryEmbeddings: {
|
|
638
|
+
name: number[];
|
|
639
|
+
userQuestion: number[];
|
|
640
|
+
description: number[];
|
|
641
|
+
technicalDescription: number[];
|
|
642
|
+
},
|
|
643
|
+
goldenEmbeddings: Array<{
|
|
644
|
+
query: GoldenQuery;
|
|
645
|
+
embeddings: { ... };
|
|
646
|
+
}>,
|
|
647
|
+
topK: number = 5
|
|
648
|
+
): Promise<SimilarQuery[]>
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
**Parameters:**
|
|
652
|
+
- `queryEmbeddings` - Embeddings for the target query
|
|
653
|
+
- `goldenEmbeddings` - Array of golden queries with embeddings
|
|
654
|
+
- `topK` - Number of top results to return (default: 5)
|
|
655
|
+
|
|
656
|
+
**Returns:** Array of SimilarQuery objects sorted by similarity descending
|
|
657
|
+
|
|
658
|
+
**Example:**
|
|
659
|
+
```typescript
|
|
660
|
+
import { SimilaritySearch } from '@memberjunction/query-gen';
|
|
661
|
+
|
|
662
|
+
const search = new SimilaritySearch();
|
|
663
|
+
|
|
664
|
+
const similar = await search.findSimilarQueries(
|
|
665
|
+
questionEmbeddings,
|
|
666
|
+
embeddedGolden,
|
|
667
|
+
5 // top 5
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
console.log('Top 5 similar golden queries:');
|
|
671
|
+
for (const result of similar) {
|
|
672
|
+
console.log(`- ${result.query.name} (similarity: ${result.similarity.toFixed(2)})`);
|
|
673
|
+
console.log(` Field scores:`, result.fieldScores);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// Output:
|
|
677
|
+
// Top 5 similar golden queries:
|
|
678
|
+
// - Top Customers By Order Count (similarity: 0.92)
|
|
679
|
+
// Field scores: { nameSim: 0.85, userQuestionSim: 0.94, descSim: 0.90, techDescSim: 0.95 }
|
|
680
|
+
// - Revenue By Customer Segment (similarity: 0.87)
|
|
681
|
+
// Field scores: { nameSim: 0.72, userQuestionSim: 0.88, descSim: 0.89, techDescSim: 0.91 }
|
|
682
|
+
// ...
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
---
|
|
686
|
+
|
|
687
|
+
## Usage Patterns
|
|
688
|
+
|
|
689
|
+
### Complete Query Generation Workflow
|
|
690
|
+
|
|
691
|
+
```typescript
|
|
692
|
+
import {
|
|
693
|
+
EntityGrouper,
|
|
694
|
+
QuestionGenerator,
|
|
695
|
+
QueryWriter,
|
|
696
|
+
QueryTester,
|
|
697
|
+
QueryRefiner,
|
|
698
|
+
MetadataExporter,
|
|
699
|
+
EmbeddingService,
|
|
700
|
+
SimilaritySearch,
|
|
701
|
+
formatEntityMetadataForPrompt
|
|
702
|
+
} from '@memberjunction/query-gen';
|
|
703
|
+
import { Metadata, UserInfo } from '@memberjunction/core';
|
|
704
|
+
|
|
705
|
+
async function generateQueriesForEntity(
|
|
706
|
+
entityName: string,
|
|
707
|
+
contextUser: UserInfo
|
|
708
|
+
): Promise<void> {
|
|
709
|
+
// 1. Load entity metadata
|
|
710
|
+
const md = new Metadata();
|
|
711
|
+
const entity = md.Entities.find(e => e.Name === entityName);
|
|
712
|
+
if (!entity) {
|
|
713
|
+
throw new Error(`Entity not found: ${entityName}`);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// 2. Create entity group
|
|
717
|
+
const grouper = new EntityGrouper();
|
|
718
|
+
const groups = await grouper.generateEntityGroups([entity], 1, 1);
|
|
719
|
+
const entityGroup = groups[0];
|
|
720
|
+
|
|
721
|
+
// 3. Generate business questions
|
|
722
|
+
const questionGen = new QuestionGenerator(contextUser);
|
|
723
|
+
const questions = await questionGen.generateQuestions(entityGroup);
|
|
724
|
+
|
|
725
|
+
// 4. Process each question
|
|
726
|
+
for (const question of questions) {
|
|
727
|
+
console.log(`\nGenerating query for: ${question.userQuestion}`);
|
|
728
|
+
|
|
729
|
+
// 5. Embed question for similarity search
|
|
730
|
+
const embeddingService = new EmbeddingService('text-embedding-3-small');
|
|
731
|
+
const questionEmbeddings = await embeddingService.embedQuery({
|
|
732
|
+
name: '',
|
|
733
|
+
userQuestion: question.userQuestion,
|
|
734
|
+
description: question.description,
|
|
735
|
+
technicalDescription: question.technicalDescription
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
// 6. Find similar golden queries
|
|
739
|
+
const goldenQueries = await loadGoldenQueries(); // Your implementation
|
|
740
|
+
const embeddedGolden = await embeddingService.embedGoldenQueries(goldenQueries);
|
|
741
|
+
|
|
742
|
+
const similaritySearch = new SimilaritySearch();
|
|
743
|
+
const fewShotResults = await similaritySearch.findSimilarQueries(
|
|
744
|
+
questionEmbeddings,
|
|
745
|
+
embeddedGolden,
|
|
746
|
+
5
|
|
747
|
+
);
|
|
748
|
+
const fewShotExamples = fewShotResults.map(r => r.query);
|
|
749
|
+
|
|
750
|
+
// 7. Generate SQL query
|
|
751
|
+
const entityMetadata = [entity].map(e =>
|
|
752
|
+
formatEntityMetadataForPrompt(e, [entity])
|
|
753
|
+
);
|
|
754
|
+
const queryWriter = new QueryWriter(contextUser);
|
|
755
|
+
const query = await queryWriter.generateQuery(
|
|
756
|
+
question,
|
|
757
|
+
entityMetadata,
|
|
758
|
+
fewShotExamples
|
|
759
|
+
);
|
|
760
|
+
|
|
761
|
+
console.log('Generated SQL:', query.sql.substring(0, 100) + '...');
|
|
762
|
+
|
|
763
|
+
// 8. Test query
|
|
764
|
+
const dataProvider = Metadata.Provider.DatabaseConnection;
|
|
765
|
+
const tester = new QueryTester(
|
|
766
|
+
dataProvider,
|
|
767
|
+
entityMetadata,
|
|
768
|
+
question,
|
|
769
|
+
contextUser
|
|
770
|
+
);
|
|
771
|
+
const testResult = await tester.testQuery(query, 5);
|
|
772
|
+
|
|
773
|
+
if (!testResult.success) {
|
|
774
|
+
console.error('Query test failed:', testResult.error);
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
console.log(`Query test passed: ${testResult.rowCount} rows returned`);
|
|
779
|
+
|
|
780
|
+
// 9. Refine query
|
|
781
|
+
const refiner = new QueryRefiner(tester, contextUser);
|
|
782
|
+
const refined = await refiner.refineQuery(query, question, entityMetadata, 3);
|
|
783
|
+
|
|
784
|
+
console.log(`Query refined in ${refined.refinementCount} iteration(s)`);
|
|
785
|
+
console.log('Evaluation confidence:', refined.evaluation.confidence);
|
|
786
|
+
|
|
787
|
+
// 10. Export query
|
|
788
|
+
const exporter = new MetadataExporter();
|
|
789
|
+
await exporter.exportQueries(
|
|
790
|
+
[{
|
|
791
|
+
businessQuestion: question,
|
|
792
|
+
query: refined.query,
|
|
793
|
+
testResult: refined.testResult,
|
|
794
|
+
evaluation: refined.evaluation,
|
|
795
|
+
entityGroup
|
|
796
|
+
}],
|
|
797
|
+
'./metadata/queries'
|
|
798
|
+
);
|
|
799
|
+
|
|
800
|
+
console.log('Query exported successfully!');
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// Usage
|
|
805
|
+
const contextUser = new UserInfo();
|
|
806
|
+
contextUser.Email = 'system@example.com';
|
|
807
|
+
contextUser.Name = 'System';
|
|
808
|
+
|
|
809
|
+
await generateQueriesForEntity('Customers', contextUser);
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
### Batch Query Generation
|
|
813
|
+
|
|
814
|
+
```typescript
|
|
815
|
+
async function generateQueriesForMultipleEntities(
|
|
816
|
+
entityNames: string[],
|
|
817
|
+
contextUser: UserInfo
|
|
818
|
+
): Promise<ValidatedQuery[]> {
|
|
819
|
+
const allValidatedQueries: ValidatedQuery[] = [];
|
|
820
|
+
|
|
821
|
+
for (const entityName of entityNames) {
|
|
822
|
+
console.log(`\nProcessing ${entityName}...`);
|
|
823
|
+
|
|
824
|
+
// Load entity
|
|
825
|
+
const md = new Metadata();
|
|
826
|
+
const entity = md.Entities.find(e => e.Name === entityName);
|
|
827
|
+
if (!entity) {
|
|
828
|
+
console.error(`Entity not found: ${entityName}`);
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// Generate queries (using workflow from previous example)
|
|
833
|
+
const queries = await generateQueriesForEntity(entityName, contextUser);
|
|
834
|
+
allValidatedQueries.push(...queries);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// Export all queries at once
|
|
838
|
+
const exporter = new MetadataExporter();
|
|
839
|
+
await exporter.exportQueries(allValidatedQueries, './metadata/queries');
|
|
840
|
+
|
|
841
|
+
console.log(`\nTotal queries generated: ${allValidatedQueries.length}`);
|
|
842
|
+
return allValidatedQueries;
|
|
843
|
+
}
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
### Query Validation
|
|
847
|
+
|
|
848
|
+
```typescript
|
|
849
|
+
async function validateQueryMetadataFile(
|
|
850
|
+
filePath: string,
|
|
851
|
+
contextUser: UserInfo
|
|
852
|
+
): Promise<{ passed: number; failed: number; errors: string[] }> {
|
|
853
|
+
const results = { passed: 0, failed: 0, errors: [] };
|
|
854
|
+
|
|
855
|
+
// Load queries from file
|
|
856
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
857
|
+
const data = JSON.parse(content);
|
|
858
|
+
const queries = Array.isArray(data) ? data : [data];
|
|
859
|
+
|
|
860
|
+
// Validate each query
|
|
861
|
+
for (const queryRecord of queries) {
|
|
862
|
+
const query = convertMetadataToGeneratedQuery(queryRecord);
|
|
863
|
+
|
|
864
|
+
// Create dummy context for testing
|
|
865
|
+
const dummyQuestion = {
|
|
866
|
+
userQuestion: queryRecord.fields.UserQuestion || 'Test query',
|
|
867
|
+
description: queryRecord.fields.Description || '',
|
|
868
|
+
technicalDescription: queryRecord.fields.TechnicalDescription || '',
|
|
869
|
+
complexity: 'medium' as const,
|
|
870
|
+
requiresAggregation: false,
|
|
871
|
+
requiresJoins: false,
|
|
872
|
+
entities: []
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
const dataProvider = Metadata.Provider.DatabaseConnection;
|
|
876
|
+
const tester = new QueryTester(dataProvider, [], dummyQuestion, contextUser);
|
|
877
|
+
|
|
878
|
+
try {
|
|
879
|
+
const testResult = await tester.testQuery(query, 1);
|
|
880
|
+
|
|
881
|
+
if (testResult.success) {
|
|
882
|
+
results.passed++;
|
|
883
|
+
console.log(`✓ ${queryRecord.fields.Name}`);
|
|
884
|
+
} else {
|
|
885
|
+
results.failed++;
|
|
886
|
+
results.errors.push(`${queryRecord.fields.Name}: ${testResult.error}`);
|
|
887
|
+
console.error(`✗ ${queryRecord.fields.Name}: ${testResult.error}`);
|
|
888
|
+
}
|
|
889
|
+
} catch (error) {
|
|
890
|
+
results.failed++;
|
|
891
|
+
const errorMsg = extractErrorMessage(error, 'Validation');
|
|
892
|
+
results.errors.push(`${queryRecord.fields.Name}: ${errorMsg}`);
|
|
893
|
+
console.error(`✗ ${queryRecord.fields.Name}: ${errorMsg}`);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
return results;
|
|
898
|
+
}
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
---
|
|
902
|
+
|
|
903
|
+
## TypeScript Types
|
|
904
|
+
|
|
905
|
+
### Core Types
|
|
906
|
+
|
|
907
|
+
```typescript
|
|
908
|
+
import type {
|
|
909
|
+
EntityGroup,
|
|
910
|
+
RelationshipInfo,
|
|
911
|
+
EntityMetadataForPrompt,
|
|
912
|
+
BusinessQuestion,
|
|
913
|
+
GeneratedQuery,
|
|
914
|
+
QueryParameter,
|
|
915
|
+
QueryOutputField,
|
|
916
|
+
GoldenQuery,
|
|
917
|
+
SimilarQuery,
|
|
918
|
+
QueryTestResult,
|
|
919
|
+
QueryEvaluation,
|
|
920
|
+
RefinedQuery,
|
|
921
|
+
ValidatedQuery,
|
|
922
|
+
QueryMetadataRecord
|
|
923
|
+
} from '@memberjunction/query-gen';
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
### Type Definitions
|
|
927
|
+
|
|
928
|
+
See [../src/data/schema.ts](../src/data/schema.ts) for complete type definitions.
|
|
929
|
+
|
|
930
|
+
---
|
|
931
|
+
|
|
932
|
+
## Configuration
|
|
933
|
+
|
|
934
|
+
### QueryGenConfig Type
|
|
935
|
+
|
|
936
|
+
```typescript
|
|
937
|
+
interface QueryGenConfig {
|
|
938
|
+
// Entity Filtering
|
|
939
|
+
includeEntities: string[];
|
|
940
|
+
excludeEntities: string[];
|
|
941
|
+
excludeSchemas: string[];
|
|
942
|
+
|
|
943
|
+
// Entity Grouping
|
|
944
|
+
maxEntitiesPerGroup: number;
|
|
945
|
+
minEntitiesPerGroup: number;
|
|
946
|
+
questionsPerGroup: number;
|
|
947
|
+
entityGroupStrategy: 'breadth' | 'depth';
|
|
948
|
+
|
|
949
|
+
// AI Configuration
|
|
950
|
+
modelOverride?: string;
|
|
951
|
+
vendorOverride?: string;
|
|
952
|
+
embeddingModel: string;
|
|
953
|
+
|
|
954
|
+
// Iteration Limits
|
|
955
|
+
maxRefinementIterations: number;
|
|
956
|
+
maxFixingIterations: number;
|
|
957
|
+
|
|
958
|
+
// Few-Shot Learning
|
|
959
|
+
topSimilarQueries: number;
|
|
960
|
+
similarityThreshold: number;
|
|
961
|
+
|
|
962
|
+
// Similarity Weighting
|
|
963
|
+
similarityWeights: {
|
|
964
|
+
name: number;
|
|
965
|
+
userQuestion: number;
|
|
966
|
+
description: number;
|
|
967
|
+
technicalDescription: number;
|
|
968
|
+
};
|
|
969
|
+
|
|
970
|
+
// Output Configuration
|
|
971
|
+
outputMode: 'metadata' | 'database' | 'both';
|
|
972
|
+
outputDirectory: string;
|
|
973
|
+
|
|
974
|
+
// Performance
|
|
975
|
+
parallelGenerations: number;
|
|
976
|
+
enableCaching: boolean;
|
|
977
|
+
|
|
978
|
+
// Validation
|
|
979
|
+
testWithSampleData: boolean;
|
|
980
|
+
requireMinRows: number;
|
|
981
|
+
maxRefinementRows: number;
|
|
982
|
+
|
|
983
|
+
// Verbose Logging
|
|
984
|
+
verbose: boolean;
|
|
985
|
+
}
|
|
986
|
+
```
|
|
987
|
+
|
|
988
|
+
### Loading Configuration
|
|
989
|
+
|
|
990
|
+
```typescript
|
|
991
|
+
import { loadConfig } from '@memberjunction/query-gen';
|
|
992
|
+
|
|
993
|
+
// Load from mj.config.cjs with CLI overrides
|
|
994
|
+
const config = loadConfig({
|
|
995
|
+
entities: ['Customers', 'Orders'],
|
|
996
|
+
maxEntities: 2,
|
|
997
|
+
verbose: true
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
// Use configuration
|
|
1001
|
+
console.log(config.maxEntitiesPerGroup); // 2
|
|
1002
|
+
console.log(config.verbose); // true
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
---
|
|
1006
|
+
|
|
1007
|
+
## Examples
|
|
1008
|
+
|
|
1009
|
+
See the [examples](../examples/) directory for complete working examples:
|
|
1010
|
+
|
|
1011
|
+
- [basic-usage.ts](../examples/basic-usage.ts) - Basic query generation workflow
|
|
1012
|
+
- [advanced-usage.ts](../examples/advanced-usage.ts) - Advanced patterns and customization
|
|
1013
|
+
|
|
1014
|
+
---
|
|
1015
|
+
|
|
1016
|
+
## Error Handling
|
|
1017
|
+
|
|
1018
|
+
All QueryGen functions use proper error handling:
|
|
1019
|
+
|
|
1020
|
+
```typescript
|
|
1021
|
+
import { extractErrorMessage } from '@memberjunction/query-gen';
|
|
1022
|
+
|
|
1023
|
+
try {
|
|
1024
|
+
const queries = await generateQueries();
|
|
1025
|
+
} catch (error: unknown) {
|
|
1026
|
+
const errorMsg = extractErrorMessage(error, 'Query Generation');
|
|
1027
|
+
console.error('Failed:', errorMsg);
|
|
1028
|
+
}
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
Never use `any` for error types - always use `unknown` and extract messages safely.
|
|
1032
|
+
|
|
1033
|
+
---
|
|
1034
|
+
|
|
1035
|
+
## Support
|
|
1036
|
+
|
|
1037
|
+
For issues or questions:
|
|
1038
|
+
- GitHub Issues: https://github.com/MemberJunction/MJ/issues
|
|
1039
|
+
- Documentation: https://docs.memberjunction.com
|
|
1040
|
+
- Community: https://community.memberjunction.com
|