@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,246 @@
1
+ "use strict";
2
+ /**
3
+ * LLM-based Entity Grouper
4
+ *
5
+ * Uses AI to generate semantically meaningful entity groupings based on
6
+ * business context and schema understanding, replacing the deterministic
7
+ * hub-and-spoke algorithm with intelligent semantic analysis.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.EntityGrouper = void 0;
11
+ const core_1 = require("@memberjunction/core");
12
+ const aiengine_1 = require("@memberjunction/aiengine");
13
+ const graph_helpers_1 = require("../utils/graph-helpers");
14
+ const error_handlers_1 = require("../utils/error-handlers");
15
+ const prompt_helpers_1 = require("../utils/prompt-helpers");
16
+ /**
17
+ * Generates entity groups using LLM-based semantic analysis
18
+ *
19
+ * This class replaces the deterministic hub-and-spoke algorithm with an
20
+ * intelligent approach that understands business context and generates
21
+ * meaningful entity combinations for query generation.
22
+ */
23
+ class EntityGrouper {
24
+ promptName = 'Entity Group Generator';
25
+ config;
26
+ constructor(config) {
27
+ this.config = config;
28
+ }
29
+ /**
30
+ * Generate semantically meaningful entity groups using LLM analysis
31
+ *
32
+ * Note: The LLM determines the optimal number and size of entity groups based on
33
+ * business domain understanding. Makes separate LLM calls for each schema to
34
+ * avoid mixing entities from different databases.
35
+ *
36
+ * @param entities - All entities to analyze
37
+ * @param contextUser - User context for server-side operations
38
+ * @returns Array of validated entity groups with business context
39
+ */
40
+ async generateEntityGroups(entities, contextUser) {
41
+ try {
42
+ // 1. Group entities by schema
43
+ const entitiesBySchema = this.groupEntitiesBySchema(entities);
44
+ // 2. Process each schema separately
45
+ const allGroups = [];
46
+ let schemaIndex = 0;
47
+ const totalSchemas = entitiesBySchema.size;
48
+ for (const [schemaName, schemaEntities] of entitiesBySchema.entries()) {
49
+ schemaIndex++;
50
+ if (this.config.verbose && totalSchemas > 1) {
51
+ (0, core_1.LogStatus)(`[${schemaIndex}/${totalSchemas}] Processing schema: ${schemaName} (${schemaEntities.length} entities)`);
52
+ }
53
+ // 2a. Prepare schema data for LLM
54
+ const schemaData = this.prepareSchemaData(schemaEntities, schemaName);
55
+ // 2b. Call LLM to generate groups for this schema
56
+ const llmResponse = await this.callLLMForGrouping(schemaData, contextUser);
57
+ // 2c. Validate and convert to EntityGroup objects
58
+ const validatedGroups = this.validateAndConvertGroups(llmResponse, schemaEntities);
59
+ if (this.config.verbose && totalSchemas > 1) {
60
+ (0, core_1.LogStatus)(`[${schemaIndex}/${totalSchemas}] Generated ${validatedGroups.length} groups for schema: ${schemaName}`);
61
+ }
62
+ allGroups.push(...validatedGroups);
63
+ }
64
+ // 3. Deduplicate any similar groups across all schemas
65
+ const deduplicatedGroups = this.deduplicateGroups(allGroups);
66
+ return deduplicatedGroups;
67
+ }
68
+ catch (error) {
69
+ throw new Error((0, error_handlers_1.extractErrorMessage)(error, 'EntityGrouper.generateEntityGroups'));
70
+ }
71
+ }
72
+ /**
73
+ * Group entities by schema name
74
+ */
75
+ groupEntitiesBySchema(entities) {
76
+ const schemaMap = new Map();
77
+ for (const entity of entities) {
78
+ const schemaName = entity.SchemaName || 'Unknown';
79
+ const schemaEntities = schemaMap.get(schemaName) || [];
80
+ schemaEntities.push(entity);
81
+ schemaMap.set(schemaName, schemaEntities);
82
+ }
83
+ return schemaMap;
84
+ }
85
+ /**
86
+ * Prepare schema data for LLM prompt
87
+ *
88
+ * Note: The LLM will determine appropriate group count based on business
89
+ * domain understanding and schema complexity. We provide the full entity
90
+ * schema and relationship graph for intelligent analysis.
91
+ *
92
+ * @param entities - Entities within a single schema
93
+ * @param schemaName - Name of the schema being processed
94
+ */
95
+ prepareSchemaData(entities, schemaName) {
96
+ const formattedEntities = (0, graph_helpers_1.formatEntitiesForPrompt)(entities);
97
+ const relationshipGraph = (0, graph_helpers_1.generateRelationshipGraph)(entities);
98
+ return {
99
+ schemaName,
100
+ entities: formattedEntities,
101
+ relationshipGraph,
102
+ minGroupSize: this.config.minGroupSize,
103
+ maxGroupSize: this.config.maxGroupSize
104
+ };
105
+ }
106
+ /**
107
+ * Call LLM via AIPromptRunner to generate entity groups
108
+ */
109
+ async callLLMForGrouping(schemaData, contextUser) {
110
+ // Get prompt entity from AIEngine
111
+ const prompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name === this.promptName);
112
+ if (!prompt) {
113
+ throw new Error(`Prompt "${this.promptName}" not found. Ensure metadata has been synced to database.`);
114
+ }
115
+ // Execute with model/vendor overrides if specified in config
116
+ const result = await (0, prompt_helpers_1.executePromptWithOverrides)(prompt, schemaData, contextUser, this.config);
117
+ if (!result.success) {
118
+ throw new Error(`LLM grouping failed: ${result.errorMessage || 'Unknown error'}`);
119
+ }
120
+ if (!result.result) {
121
+ throw new Error('LLM did not return structured data');
122
+ }
123
+ return result.result;
124
+ }
125
+ /**
126
+ * Validate LLM output and convert to EntityGroup objects
127
+ */
128
+ validateAndConvertGroups(llmResponse, entities) {
129
+ const entityMap = new Map(entities.map(e => [e.Name, e]));
130
+ const validGroups = [];
131
+ for (const llmGroup of llmResponse.groups) {
132
+ try {
133
+ // Validate all entity names exist
134
+ const groupEntities = llmGroup.entities
135
+ .map(name => entityMap.get(name))
136
+ .filter((e) => e !== undefined);
137
+ if (groupEntities.length !== llmGroup.entities.length) {
138
+ // Skip logging - verbose debug info that clutters output
139
+ continue;
140
+ }
141
+ // Validate primary entity exists
142
+ const primaryEntity = entityMap.get(llmGroup.primaryEntity);
143
+ if (!primaryEntity) {
144
+ // Skip logging - verbose debug info that clutters output
145
+ continue;
146
+ }
147
+ // Build relationships array (collect all relationships between entities in the group)
148
+ const relationships = this.extractRelationships(groupEntities);
149
+ // Validate connectivity (all entities must be reachable from primary)
150
+ if (groupEntities.length > 1 && !this.isConnected(groupEntities, relationships)) {
151
+ // Skip logging - verbose debug info that clutters output
152
+ continue;
153
+ }
154
+ // Create EntityGroup with LLM metadata
155
+ validGroups.push({
156
+ entities: groupEntities,
157
+ relationships,
158
+ primaryEntity,
159
+ relationshipType: llmGroup.relationshipType,
160
+ businessDomain: llmGroup.businessDomain,
161
+ businessRationale: llmGroup.businessRationale,
162
+ expectedQuestionTypes: llmGroup.expectedQuestionTypes
163
+ });
164
+ }
165
+ catch (error) {
166
+ // Skip logging - verbose debug info that clutters output
167
+ }
168
+ }
169
+ if (validGroups.length === 0) {
170
+ throw new Error('No valid entity groups generated by LLM');
171
+ }
172
+ return validGroups;
173
+ }
174
+ /**
175
+ * Extract relationships between entities in a group
176
+ */
177
+ extractRelationships(entities) {
178
+ const entityNames = new Set(entities.map(e => e.Name));
179
+ const relationships = [];
180
+ for (const entity of entities) {
181
+ for (const rel of entity.RelatedEntities) {
182
+ if (entityNames.has(rel.RelatedEntity)) {
183
+ relationships.push(rel);
184
+ }
185
+ }
186
+ }
187
+ return relationships;
188
+ }
189
+ /**
190
+ * Check if all entities in a group are connected by relationships
191
+ *
192
+ * Uses BFS to verify all entities are reachable from the first entity
193
+ */
194
+ isConnected(entities, relationships) {
195
+ if (entities.length <= 1)
196
+ return true;
197
+ // Build adjacency map
198
+ const adjacency = new Map();
199
+ for (const entity of entities) {
200
+ adjacency.set(entity.Name, new Set());
201
+ }
202
+ for (const rel of relationships) {
203
+ const entityName = entities.find(e => e.RelatedEntities.includes(rel))?.Name;
204
+ if (entityName) {
205
+ adjacency.get(entityName)?.add(rel.RelatedEntity);
206
+ adjacency.get(rel.RelatedEntity)?.add(entityName); // Bidirectional
207
+ }
208
+ }
209
+ // BFS from first entity
210
+ const visited = new Set();
211
+ const queue = [entities[0].Name];
212
+ visited.add(entities[0].Name);
213
+ while (queue.length > 0) {
214
+ const current = queue.shift();
215
+ const neighbors = adjacency.get(current) || new Set();
216
+ for (const neighbor of neighbors) {
217
+ if (!visited.has(neighbor)) {
218
+ visited.add(neighbor);
219
+ queue.push(neighbor);
220
+ }
221
+ }
222
+ }
223
+ // All entities should be visited
224
+ return visited.size === entities.length;
225
+ }
226
+ /**
227
+ * Remove duplicate or highly similar groups
228
+ *
229
+ * Groups are considered duplicates if they contain the exact same set of entities
230
+ */
231
+ deduplicateGroups(groups) {
232
+ const seen = new Set();
233
+ const unique = [];
234
+ for (const group of groups) {
235
+ // Create normalized key (sorted entity names)
236
+ const key = group.entities.map(e => e.Name).sort().join('|');
237
+ if (!seen.has(key)) {
238
+ seen.add(key);
239
+ unique.push(group);
240
+ }
241
+ }
242
+ return unique;
243
+ }
244
+ }
245
+ exports.EntityGrouper = EntityGrouper;
246
+ //# sourceMappingURL=EntityGrouper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityGrouper.js","sourceRoot":"","sources":["../../src/core/EntityGrouper.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,+CAA+F;AAC/F,uDAAoD;AAGpD,0DAA4F;AAC5F,4DAA8D;AAC9D,4DAAqE;AAgBrE;;;;;;GAMG;AACH,MAAa,aAAa;IACP,UAAU,GAAG,wBAAwB,CAAC;IACtC,MAAM,CAAiB;IAExC,YAAY,MAAsB;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,oBAAoB,CACxB,QAAsB,EACtB,WAAqB;QAErB,IAAI,CAAC;YACH,8BAA8B;YAC9B,MAAM,gBAAgB,GAAG,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;YAE9D,oCAAoC;YACpC,MAAM,SAAS,GAAkB,EAAE,CAAC;YACpC,IAAI,WAAW,GAAG,CAAC,CAAC;YACpB,MAAM,YAAY,GAAG,gBAAgB,CAAC,IAAI,CAAC;YAE3C,KAAK,MAAM,CAAC,UAAU,EAAE,cAAc,CAAC,IAAI,gBAAgB,CAAC,OAAO,EAAE,EAAE,CAAC;gBACtE,WAAW,EAAE,CAAC;gBAEd,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;oBAC5C,IAAA,gBAAS,EAAC,IAAI,WAAW,IAAI,YAAY,wBAAwB,UAAU,KAAK,cAAc,CAAC,MAAM,YAAY,CAAC,CAAC;gBACrH,CAAC;gBAED,kCAAkC;gBAClC,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;gBAEtE,kDAAkD;gBAClD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;gBAE3E,kDAAkD;gBAClD,MAAM,eAAe,GAAG,IAAI,CAAC,wBAAwB,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;gBAEnF,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;oBAC5C,IAAA,gBAAS,EAAC,IAAI,WAAW,IAAI,YAAY,eAAe,eAAe,CAAC,MAAM,uBAAuB,UAAU,EAAE,CAAC,CAAC;gBACrH,CAAC;gBAED,SAAS,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC;YACrC,CAAC;YAED,uDAAuD;YACvD,MAAM,kBAAkB,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;YAE7D,OAAO,kBAAkB,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,IAAA,oCAAmB,EAAC,KAAK,EAAE,oCAAoC,CAAC,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;IAED;;OAEG;IACK,qBAAqB,CAAC,QAAsB;QAClD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAwB,CAAC;QAElD,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,SAAS,CAAC;YAClD,MAAM,cAAc,GAAG,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;YACvD,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC5B,SAAS,CAAC,GAAG,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QAC5C,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;;;;;OASG;IACK,iBAAiB,CAAC,QAAsB,EAAE,UAAkB;QAClE,MAAM,iBAAiB,GAAG,IAAA,uCAAuB,EAAC,QAAQ,CAAC,CAAC;QAC5D,MAAM,iBAAiB,GAAG,IAAA,yCAAyB,EAAC,QAAQ,CAAC,CAAC;QAE9D,OAAO;YACL,UAAU;YACV,QAAQ,EAAE,iBAAiB;YAC3B,iBAAiB;YACjB,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;YACtC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;SACvC,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,kBAAkB,CAC9B,UAAmC,EACnC,WAAqB;QAErB,kCAAkC;QAClC,MAAM,MAAM,GAAG,mBAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/E,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,UAAU,2DAA2D,CAAC,CAAC;QACzG,CAAC;QAED,6DAA6D;QAC7D,MAAM,MAAM,GAAG,MAAM,IAAA,2CAA0B,EAC7C,MAAM,EACN,UAAU,EACV,WAAW,EACX,IAAI,CAAC,MAAM,CACZ,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,CAAC,YAAY,IAAI,eAAe,EAAE,CAAC,CAAC;QACpF,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACK,wBAAwB,CAC9B,WAAmC,EACnC,QAAsB;QAEtB,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,MAAM,WAAW,GAAkB,EAAE,CAAC;QAEtC,KAAK,MAAM,QAAQ,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;YAC1C,IAAI,CAAC;gBACH,kCAAkC;gBAClC,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ;qBACpC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;qBAChC,MAAM,CAAC,CAAC,CAAC,EAAmB,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;gBAEnD,IAAI,aAAa,CAAC,MAAM,KAAK,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;oBACtD,yDAAyD;oBACzD,SAAS;gBACX,CAAC;gBAED,iCAAiC;gBACjC,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;gBAC5D,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnB,yDAAyD;oBACzD,SAAS;gBACX,CAAC;gBAED,sFAAsF;gBACtF,MAAM,aAAa,GAAG,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC;gBAE/D,sEAAsE;gBACtE,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,aAAa,CAAC,EAAE,CAAC;oBAChF,yDAAyD;oBACzD,SAAS;gBACX,CAAC;gBAED,uCAAuC;gBACvC,WAAW,CAAC,IAAI,CAAC;oBACf,QAAQ,EAAE,aAAa;oBACvB,aAAa;oBACb,aAAa;oBACb,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;oBAC3C,cAAc,EAAE,QAAQ,CAAC,cAAc;oBACvC,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;oBAC7C,qBAAqB,EAAE,QAAQ,CAAC,qBAAqB;iBACtD,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACxB,yDAAyD;YAC3D,CAAC;QACH,CAAC;QAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;OAEG;IACK,oBAAoB,CAAC,QAAsB;QACjD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACvD,MAAM,aAAa,GAA6B,EAAE,CAAC;QAEnD,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;gBACzC,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;oBACvC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,aAAa,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACK,WAAW,CAAC,QAAsB,EAAE,aAAuC;QACjF,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAEtC,sBAAsB;QACtB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuB,CAAC;QACjD,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QACxC,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;YAChC,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACnC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,GAAG,CAAC,CAChC,EAAE,IAAI,CAAC;YAER,IAAI,UAAU,EAAE,CAAC;gBACf,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBAClD,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,gBAAgB;YACrE,CAAC;QACH,CAAC;QAED,wBAAwB;QACxB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;QAClC,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAE9B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;YAC/B,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;YAEtD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC3B,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;oBACtB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;QACH,CAAC;QAED,iCAAiC;QACjC,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,MAAM,CAAC;IAC1C,CAAC;IAED;;;;OAIG;IACK,iBAAiB,CAAC,MAAqB;QAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,MAAM,MAAM,GAAkB,EAAE,CAAC;QAEjC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,8CAA8C;YAC9C,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAE7D,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACd,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAxRD,sCAwRC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * MetadataExporter - Exports validated queries to MJ metadata format
3
+ *
4
+ * Transforms validated queries into MemberJunction metadata JSON files
5
+ * that can be synced to the database using mj-sync.
6
+ */
7
+ import { ValidatedQuery, ExportResult, QueryCategoryInfo } from '../data/schema';
8
+ /**
9
+ * MetadataExporter class
10
+ * Exports validated queries to MJ metadata JSON format
11
+ */
12
+ export declare class MetadataExporter {
13
+ /**
14
+ * Export queries to metadata JSON files
15
+ *
16
+ * Transforms validated queries into MemberJunction metadata format
17
+ * and writes them to timestamped JSON files:
18
+ * - .query-categories-{timestamp}.json for the categories
19
+ * - .queries-{timestamp}.json for the queries
20
+ *
21
+ * @param validatedQueries - Array of validated queries to export
22
+ * @param uniqueCategories - Pre-built unique categories for all queries
23
+ * @param outputDirectory - Directory to write the queries file
24
+ * @param outputCategoryDirectory - Optional directory for categories file (defaults to outputDirectory)
25
+ * @returns Export result with file path and query count
26
+ */
27
+ exportQueries(validatedQueries: ValidatedQuery[], uniqueCategories: QueryCategoryInfo[], outputDirectory: string, outputCategoryDirectory?: string): Promise<ExportResult>;
28
+ /**
29
+ * Transform a validated query into MJ metadata format
30
+ *
31
+ * Note: This method only creates the Query record.
32
+ * QueryFields and QueryParameters are automatically extracted
33
+ * by QueryEntity.server.ts using AI analysis of the SQL template.
34
+ * This happens asynchronously during the Save() operation.
35
+ *
36
+ * @param query - Validated query to transform
37
+ * @returns Query metadata record
38
+ */
39
+ private toQueryMetadata;
40
+ /**
41
+ * Transform a QueryCategoryInfo into MJ metadata format
42
+ *
43
+ * @param category - Category information
44
+ * @returns Category metadata record
45
+ */
46
+ private toCategoryMetadata;
47
+ /**
48
+ * Build category lookup string for metadata
49
+ * Uses multi-field lookup to uniquely identify categories in hierarchies
50
+ *
51
+ * For root categories: Name=X&ParentID=null
52
+ * For child categories: Name=X&Parent=Y (where Parent is the parent category name)
53
+ *
54
+ * @param category - Category information
55
+ * @returns Lookup string for CategoryID field
56
+ */
57
+ private buildCategoryLookup;
58
+ }
59
+ //# sourceMappingURL=MetadataExporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetadataExporter.d.ts","sourceRoot":"","sources":["../../src/core/MetadataExporter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAuB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGtG;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B;;;;;;;;;;;;;OAaG;IACG,aAAa,CACjB,gBAAgB,EAAE,cAAc,EAAE,EAClC,gBAAgB,EAAE,iBAAiB,EAAE,EACrC,eAAe,EAAE,MAAM,EACvB,uBAAuB,CAAC,EAAE,MAAM,GAC/B,OAAO,CAAC,YAAY,CAAC;IA0CxB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,eAAe;IAoBvB;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;;;;;;;;OASG;IACH,OAAO,CAAC,mBAAmB;CAS5B"}
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ /**
3
+ * MetadataExporter - Exports validated queries to MJ metadata format
4
+ *
5
+ * Transforms validated queries into MemberJunction metadata JSON files
6
+ * that can be synced to the database using mj-sync.
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.MetadataExporter = void 0;
33
+ const fs_1 = require("fs");
34
+ const path = __importStar(require("path"));
35
+ const query_helpers_1 = require("../utils/query-helpers");
36
+ /**
37
+ * MetadataExporter class
38
+ * Exports validated queries to MJ metadata JSON format
39
+ */
40
+ class MetadataExporter {
41
+ /**
42
+ * Export queries to metadata JSON files
43
+ *
44
+ * Transforms validated queries into MemberJunction metadata format
45
+ * and writes them to timestamped JSON files:
46
+ * - .query-categories-{timestamp}.json for the categories
47
+ * - .queries-{timestamp}.json for the queries
48
+ *
49
+ * @param validatedQueries - Array of validated queries to export
50
+ * @param uniqueCategories - Pre-built unique categories for all queries
51
+ * @param outputDirectory - Directory to write the queries file
52
+ * @param outputCategoryDirectory - Optional directory for categories file (defaults to outputDirectory)
53
+ * @returns Export result with file path and query count
54
+ */
55
+ async exportQueries(validatedQueries, uniqueCategories, outputDirectory, outputCategoryDirectory) {
56
+ // Generate shared timestamp for both files
57
+ const timestamp = Date.now();
58
+ // Use category directory if provided, otherwise use queries directory
59
+ const categoryDir = outputCategoryDirectory || outputDirectory;
60
+ // 1. Transform to MJ metadata format
61
+ const queryMetadata = validatedQueries.map(q => this.toQueryMetadata(q));
62
+ const categoryMetadata = uniqueCategories.map(c => this.toCategoryMetadata(c));
63
+ // 2. Ensure output directories exist
64
+ await fs_1.promises.mkdir(outputDirectory, { recursive: true });
65
+ if (categoryDir !== outputDirectory) {
66
+ await fs_1.promises.mkdir(categoryDir, { recursive: true });
67
+ }
68
+ // 3. Write categories file (if categories exist)
69
+ if (categoryMetadata.length > 0) {
70
+ const categoriesPath = path.join(categoryDir, `.query-categories-${timestamp}.json`);
71
+ await fs_1.promises.writeFile(categoriesPath, JSON.stringify(categoryMetadata, null, 2), 'utf-8');
72
+ }
73
+ // 4. Write queries file
74
+ const outputPath = path.join(outputDirectory, `.queries-${timestamp}.json`);
75
+ await fs_1.promises.writeFile(outputPath, JSON.stringify(queryMetadata, null, 2), 'utf-8');
76
+ return {
77
+ success: true,
78
+ outputPath,
79
+ queryCount: queryMetadata.length
80
+ };
81
+ }
82
+ /**
83
+ * Transform a validated query into MJ metadata format
84
+ *
85
+ * Note: This method only creates the Query record.
86
+ * QueryFields and QueryParameters are automatically extracted
87
+ * by QueryEntity.server.ts using AI analysis of the SQL template.
88
+ * This happens asynchronously during the Save() operation.
89
+ *
90
+ * @param query - Validated query to transform
91
+ * @returns Query metadata record
92
+ */
93
+ toQueryMetadata(query) {
94
+ // Build category lookup path (e.g., "Golden-Queries/Members" becomes lookup filter)
95
+ const categoryLookup = this.buildCategoryLookup(query.category);
96
+ return {
97
+ fields: {
98
+ Name: (0, query_helpers_1.generateQueryName)(query.businessQuestion),
99
+ CategoryID: categoryLookup,
100
+ UserQuestion: query.businessQuestion.userQuestion,
101
+ Description: query.businessQuestion.description,
102
+ TechnicalDescription: query.businessQuestion.technicalDescription,
103
+ SQL: query.query.sql,
104
+ OriginalSQL: query.query.sql,
105
+ UsesTemplate: true,
106
+ Status: 'Pending'
107
+ }
108
+ // relatedEntities removed - QueryEntity.server.ts handles extraction automatically
109
+ };
110
+ }
111
+ /**
112
+ * Transform a QueryCategoryInfo into MJ metadata format
113
+ *
114
+ * @param category - Category information
115
+ * @returns Category metadata record
116
+ */
117
+ toCategoryMetadata(category) {
118
+ return {
119
+ fields: {
120
+ Name: category.name,
121
+ ParentID: category.parentName
122
+ ? `@lookup:Query Categories.Name=${category.parentName}`
123
+ : null,
124
+ Description: category.description,
125
+ UserID: '@lookup:Users.Name=System'
126
+ }
127
+ };
128
+ }
129
+ /**
130
+ * Build category lookup string for metadata
131
+ * Uses multi-field lookup to uniquely identify categories in hierarchies
132
+ *
133
+ * For root categories: Name=X&ParentID=null
134
+ * For child categories: Name=X&Parent=Y (where Parent is the parent category name)
135
+ *
136
+ * @param category - Category information
137
+ * @returns Lookup string for CategoryID field
138
+ */
139
+ buildCategoryLookup(category) {
140
+ if (category.parentName) {
141
+ // Child category - use Name and Parent field (view field showing parent name)
142
+ return `@lookup:Query Categories.Name=${category.name}&Parent=${category.parentName}`;
143
+ }
144
+ else {
145
+ // Root category - use Name and ParentID=null
146
+ return `@lookup:Query Categories.Name=${category.name}&ParentID=null`;
147
+ }
148
+ }
149
+ }
150
+ exports.MetadataExporter = MetadataExporter;
151
+ //# sourceMappingURL=MetadataExporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetadataExporter.js","sourceRoot":"","sources":["../../src/core/MetadataExporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * QueryDatabaseWriter - Write validated queries directly to the database
3
+ *
4
+ * Creates Query entities in the database. QueryFields and QueryParameters
5
+ * are automatically extracted by QueryEntity.server.ts using AI analysis
6
+ * of the SQL template during the Save() operation.
7
+ */
8
+ import { UserInfo } from '@memberjunction/core';
9
+ import { ValidatedQuery, WriteResult } from '../data/schema';
10
+ /**
11
+ * QueryDatabaseWriter class
12
+ * Writes validated queries directly to the database
13
+ */
14
+ export declare class QueryDatabaseWriter {
15
+ private categoryCache;
16
+ constructor();
17
+ /**
18
+ * Write validated queries to the database
19
+ *
20
+ * Creates Query entities. QueryFields and QueryParameters are automatically
21
+ * extracted by QueryEntity.server.ts using AI analysis of the SQL template.
22
+ * This happens asynchronously during the Save() operation.
23
+ *
24
+ * Errors for individual queries are logged but don't stop the batch process.
25
+ *
26
+ * @param validatedQueries - Array of validated queries to write
27
+ * @param contextUser - User context for entity operations
28
+ * @returns Write result with success status and per-query results
29
+ */
30
+ writeQueriesToDatabase(validatedQueries: ValidatedQuery[], contextUser: UserInfo): Promise<WriteResult>;
31
+ /**
32
+ * Get or create category ID from QueryCategoryInfo
33
+ * Uses caching to avoid repeated lookups/creations
34
+ * Ensures parent categories exist before creating children
35
+ */
36
+ private getCategoryId;
37
+ /**
38
+ * Find or create a query category
39
+ *
40
+ * Searches for an existing category with the given name and parent, or creates it if not found.
41
+ *
42
+ * @param categoryName - Name of the category to find or create
43
+ * @param parentCategoryId - Parent category ID (null for root categories)
44
+ * @param description - Description for new categories
45
+ * @param contextUser - User context for entity operations
46
+ * @returns Category ID
47
+ */
48
+ private findOrCreateCategory;
49
+ }
50
+ //# sourceMappingURL=QueryDatabaseWriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryDatabaseWriter.d.ts","sourceRoot":"","sources":["../../src/core/QueryDatabaseWriter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAqB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAKnE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAI7D;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,aAAa,CAAkC;;IAKvD;;;;;;;;;;;;OAYG;IACG,sBAAsB,CAC1B,gBAAgB,EAAE,cAAc,EAAE,EAClC,WAAW,EAAE,QAAQ,GACpB,OAAO,CAAC,WAAW,CAAC;IA8CvB;;;;OAIG;YACW,aAAa;IAmC3B;;;;;;;;;;OAUG;YACW,oBAAoB;CA8CnC"}