@memberjunction/db-auto-doc 2.117.0 → 2.118.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.
Files changed (251) hide show
  1. package/README.md +652 -165
  2. package/bin/run.js +7 -0
  3. package/dist/api/DBAutoDocAPI.d.ts +252 -0
  4. package/dist/api/DBAutoDocAPI.d.ts.map +1 -0
  5. package/dist/api/DBAutoDocAPI.js +530 -0
  6. package/dist/api/DBAutoDocAPI.js.map +1 -0
  7. package/dist/api/index.d.ts +7 -0
  8. package/dist/api/index.d.ts.map +1 -0
  9. package/dist/api/index.js +10 -0
  10. package/dist/api/index.js.map +1 -0
  11. package/dist/commands/analyze.d.ts +6 -4
  12. package/dist/commands/analyze.d.ts.map +1 -1
  13. package/dist/commands/analyze.js +58 -71
  14. package/dist/commands/analyze.js.map +1 -1
  15. package/dist/commands/export.d.ts +14 -4
  16. package/dist/commands/export.d.ts.map +1 -1
  17. package/dist/commands/export.js +156 -61
  18. package/dist/commands/export.js.map +1 -1
  19. package/dist/commands/init.d.ts +3 -4
  20. package/dist/commands/init.d.ts.map +1 -1
  21. package/dist/commands/init.js +155 -146
  22. package/dist/commands/init.js.map +1 -1
  23. package/dist/commands/reset.d.ts +4 -1
  24. package/dist/commands/reset.d.ts.map +1 -1
  25. package/dist/commands/reset.js +33 -19
  26. package/dist/commands/reset.js.map +1 -1
  27. package/dist/commands/status.d.ts +10 -0
  28. package/dist/commands/status.d.ts.map +1 -0
  29. package/dist/commands/status.js +66 -0
  30. package/dist/commands/status.js.map +1 -0
  31. package/dist/core/AnalysisEngine.d.ts +108 -0
  32. package/dist/core/AnalysisEngine.d.ts.map +1 -0
  33. package/dist/core/AnalysisEngine.js +716 -0
  34. package/dist/core/AnalysisEngine.js.map +1 -0
  35. package/dist/core/AnalysisOrchestrator.d.ts +37 -0
  36. package/dist/core/AnalysisOrchestrator.d.ts.map +1 -0
  37. package/dist/core/AnalysisOrchestrator.js +294 -0
  38. package/dist/core/AnalysisOrchestrator.js.map +1 -0
  39. package/dist/core/BackpropagationEngine.d.ts +32 -0
  40. package/dist/core/BackpropagationEngine.d.ts.map +1 -0
  41. package/dist/core/BackpropagationEngine.js +121 -0
  42. package/dist/core/BackpropagationEngine.js.map +1 -0
  43. package/dist/core/ConvergenceDetector.d.ts +27 -0
  44. package/dist/core/ConvergenceDetector.d.ts.map +1 -0
  45. package/dist/core/ConvergenceDetector.js +92 -0
  46. package/dist/core/ConvergenceDetector.js.map +1 -0
  47. package/dist/core/GuardrailsManager.d.ts +78 -0
  48. package/dist/core/GuardrailsManager.d.ts.map +1 -0
  49. package/dist/core/GuardrailsManager.js +367 -0
  50. package/dist/core/GuardrailsManager.js.map +1 -0
  51. package/dist/core/index.d.ts +7 -0
  52. package/dist/core/index.d.ts.map +1 -0
  53. package/dist/core/index.js +13 -0
  54. package/dist/core/index.js.map +1 -0
  55. package/dist/database/Database.d.ts +56 -0
  56. package/dist/database/Database.d.ts.map +1 -0
  57. package/dist/database/Database.js +172 -0
  58. package/dist/database/Database.js.map +1 -0
  59. package/dist/database/TopologicalSorter.d.ts +25 -0
  60. package/dist/database/TopologicalSorter.d.ts.map +1 -0
  61. package/dist/database/TopologicalSorter.js +150 -0
  62. package/dist/database/TopologicalSorter.js.map +1 -0
  63. package/dist/database/index.d.ts +6 -0
  64. package/dist/database/index.d.ts.map +1 -0
  65. package/dist/database/index.js +14 -0
  66. package/dist/database/index.js.map +1 -0
  67. package/dist/discovery/ColumnStatsCache.d.ts +91 -0
  68. package/dist/discovery/ColumnStatsCache.d.ts.map +1 -0
  69. package/dist/discovery/ColumnStatsCache.js +231 -0
  70. package/dist/discovery/ColumnStatsCache.js.map +1 -0
  71. package/dist/discovery/DiscoveryEngine.d.ts +100 -0
  72. package/dist/discovery/DiscoveryEngine.d.ts.map +1 -0
  73. package/dist/discovery/DiscoveryEngine.js +726 -0
  74. package/dist/discovery/DiscoveryEngine.js.map +1 -0
  75. package/dist/discovery/DiscoveryTriggerAnalyzer.d.ts +57 -0
  76. package/dist/discovery/DiscoveryTriggerAnalyzer.d.ts.map +1 -0
  77. package/dist/discovery/DiscoveryTriggerAnalyzer.js +186 -0
  78. package/dist/discovery/DiscoveryTriggerAnalyzer.js.map +1 -0
  79. package/dist/discovery/FKDetector.d.ts +47 -0
  80. package/dist/discovery/FKDetector.d.ts.map +1 -0
  81. package/dist/discovery/FKDetector.js +317 -0
  82. package/dist/discovery/FKDetector.js.map +1 -0
  83. package/dist/discovery/LLMDiscoveryValidator.d.ts +64 -0
  84. package/dist/discovery/LLMDiscoveryValidator.d.ts.map +1 -0
  85. package/dist/discovery/LLMDiscoveryValidator.js +431 -0
  86. package/dist/discovery/LLMDiscoveryValidator.js.map +1 -0
  87. package/dist/discovery/LLMSanityChecker.d.ts +38 -0
  88. package/dist/discovery/LLMSanityChecker.d.ts.map +1 -0
  89. package/dist/discovery/LLMSanityChecker.js +156 -0
  90. package/dist/discovery/LLMSanityChecker.js.map +1 -0
  91. package/dist/discovery/PKDetector.d.ts +62 -0
  92. package/dist/discovery/PKDetector.d.ts.map +1 -0
  93. package/dist/discovery/PKDetector.js +436 -0
  94. package/dist/discovery/PKDetector.js.map +1 -0
  95. package/dist/discovery/index.d.ts +9 -0
  96. package/dist/discovery/index.d.ts.map +1 -0
  97. package/dist/discovery/index.js +25 -0
  98. package/dist/discovery/index.js.map +1 -0
  99. package/dist/drivers/BaseAutoDocDriver.d.ts +132 -0
  100. package/dist/drivers/BaseAutoDocDriver.d.ts.map +1 -0
  101. package/dist/drivers/BaseAutoDocDriver.js +121 -0
  102. package/dist/drivers/BaseAutoDocDriver.js.map +1 -0
  103. package/dist/drivers/MySQLDriver.d.ts +61 -0
  104. package/dist/drivers/MySQLDriver.d.ts.map +1 -0
  105. package/dist/drivers/MySQLDriver.js +668 -0
  106. package/dist/drivers/MySQLDriver.js.map +1 -0
  107. package/dist/drivers/PostgreSQLDriver.d.ts +65 -0
  108. package/dist/drivers/PostgreSQLDriver.d.ts.map +1 -0
  109. package/dist/drivers/PostgreSQLDriver.js +704 -0
  110. package/dist/drivers/PostgreSQLDriver.js.map +1 -0
  111. package/dist/drivers/SQLServerDriver.d.ts +61 -0
  112. package/dist/drivers/SQLServerDriver.d.ts.map +1 -0
  113. package/dist/drivers/SQLServerDriver.js +667 -0
  114. package/dist/drivers/SQLServerDriver.js.map +1 -0
  115. package/dist/generators/CSVGenerator.d.ts +35 -0
  116. package/dist/generators/CSVGenerator.d.ts.map +1 -0
  117. package/dist/generators/CSVGenerator.js +154 -0
  118. package/dist/generators/CSVGenerator.js.map +1 -0
  119. package/dist/generators/HTMLGenerator.d.ts +29 -0
  120. package/dist/generators/HTMLGenerator.d.ts.map +1 -0
  121. package/dist/generators/HTMLGenerator.js +710 -0
  122. package/dist/generators/HTMLGenerator.js.map +1 -0
  123. package/dist/generators/MarkdownGenerator.d.ts +27 -0
  124. package/dist/generators/MarkdownGenerator.d.ts.map +1 -0
  125. package/dist/generators/MarkdownGenerator.js +361 -0
  126. package/dist/generators/MarkdownGenerator.js.map +1 -0
  127. package/dist/generators/MermaidGenerator.d.ts +35 -0
  128. package/dist/generators/MermaidGenerator.d.ts.map +1 -0
  129. package/dist/generators/MermaidGenerator.js +321 -0
  130. package/dist/generators/MermaidGenerator.js.map +1 -0
  131. package/dist/generators/ReportGenerator.d.ts +22 -0
  132. package/dist/generators/ReportGenerator.d.ts.map +1 -0
  133. package/dist/generators/ReportGenerator.js +176 -0
  134. package/dist/generators/ReportGenerator.js.map +1 -0
  135. package/dist/generators/SQLGenerator.d.ts +31 -0
  136. package/dist/generators/SQLGenerator.d.ts.map +1 -0
  137. package/dist/generators/SQLGenerator.js +168 -0
  138. package/dist/generators/SQLGenerator.js.map +1 -0
  139. package/dist/generators/index.d.ts +10 -0
  140. package/dist/generators/index.d.ts.map +1 -0
  141. package/dist/generators/index.js +19 -0
  142. package/dist/generators/index.js.map +1 -0
  143. package/dist/index.d.ts +11 -20
  144. package/dist/index.d.ts.map +1 -1
  145. package/dist/index.js +19 -20
  146. package/dist/index.js.map +1 -1
  147. package/dist/prompts/PromptEngine.d.ts +65 -0
  148. package/dist/prompts/PromptEngine.d.ts.map +1 -0
  149. package/dist/prompts/PromptEngine.js +282 -0
  150. package/dist/prompts/PromptEngine.js.map +1 -0
  151. package/dist/prompts/PromptFileLoader.d.ts +21 -0
  152. package/dist/prompts/PromptFileLoader.d.ts.map +1 -0
  153. package/dist/prompts/PromptFileLoader.js +74 -0
  154. package/dist/prompts/PromptFileLoader.js.map +1 -0
  155. package/dist/prompts/index.d.ts +6 -0
  156. package/dist/prompts/index.d.ts.map +1 -0
  157. package/dist/prompts/index.js +11 -0
  158. package/dist/prompts/index.js.map +1 -0
  159. package/dist/state/IterationTracker.d.ts +64 -0
  160. package/dist/state/IterationTracker.d.ts.map +1 -0
  161. package/dist/state/IterationTracker.js +136 -0
  162. package/dist/state/IterationTracker.js.map +1 -0
  163. package/dist/state/StateManager.d.ts +79 -0
  164. package/dist/state/StateManager.d.ts.map +1 -0
  165. package/dist/state/StateManager.js +348 -0
  166. package/dist/state/StateManager.js.map +1 -0
  167. package/dist/state/StateValidator.d.ts +24 -0
  168. package/dist/state/StateValidator.d.ts.map +1 -0
  169. package/dist/state/StateValidator.js +147 -0
  170. package/dist/state/StateValidator.js.map +1 -0
  171. package/dist/state/index.d.ts +7 -0
  172. package/dist/state/index.d.ts.map +1 -0
  173. package/dist/state/index.js +13 -0
  174. package/dist/state/index.js.map +1 -0
  175. package/dist/types/analysis.d.ts +76 -0
  176. package/dist/types/analysis.d.ts.map +1 -0
  177. package/dist/types/analysis.js +6 -0
  178. package/dist/types/analysis.js.map +1 -0
  179. package/dist/types/config.d.ts +132 -0
  180. package/dist/types/config.d.ts.map +1 -0
  181. package/dist/types/config.js +7 -0
  182. package/dist/types/config.js.map +1 -0
  183. package/dist/types/discovery.d.ts +277 -0
  184. package/dist/types/discovery.d.ts.map +1 -0
  185. package/dist/types/discovery.js +7 -0
  186. package/dist/types/discovery.js.map +1 -0
  187. package/dist/types/driver.d.ts +148 -0
  188. package/dist/types/driver.d.ts.map +1 -0
  189. package/dist/types/driver.js +7 -0
  190. package/dist/types/driver.js.map +1 -0
  191. package/dist/types/index.d.ts +8 -0
  192. package/dist/types/index.d.ts.map +1 -0
  193. package/dist/types/index.js +24 -0
  194. package/dist/types/index.js.map +1 -0
  195. package/dist/types/prompts.d.ts +158 -0
  196. package/dist/types/prompts.d.ts.map +1 -0
  197. package/dist/types/prompts.js +6 -0
  198. package/dist/types/prompts.js.map +1 -0
  199. package/dist/types/state.d.ts +278 -0
  200. package/dist/types/state.d.ts.map +1 -0
  201. package/dist/types/state.js +7 -0
  202. package/dist/types/state.js.map +1 -0
  203. package/dist/utils/config-loader.d.ts +29 -0
  204. package/dist/utils/config-loader.d.ts.map +1 -0
  205. package/dist/utils/config-loader.js +163 -0
  206. package/dist/utils/config-loader.js.map +1 -0
  207. package/dist/utils/index.d.ts +5 -0
  208. package/dist/utils/index.d.ts.map +1 -0
  209. package/dist/utils/index.js +9 -0
  210. package/dist/utils/index.js.map +1 -0
  211. package/package.json +24 -3
  212. package/dist/ai/simple-ai-client.d.ts +0 -70
  213. package/dist/ai/simple-ai-client.d.ts.map +0 -1
  214. package/dist/ai/simple-ai-client.js +0 -181
  215. package/dist/ai/simple-ai-client.js.map +0 -1
  216. package/dist/analyzers/analyzer.d.ts +0 -23
  217. package/dist/analyzers/analyzer.d.ts.map +0 -1
  218. package/dist/analyzers/analyzer.js +0 -127
  219. package/dist/analyzers/analyzer.js.map +0 -1
  220. package/dist/cli-old/cli.d.ts +0 -3
  221. package/dist/cli-old/cli.d.ts.map +0 -1
  222. package/dist/cli-old/cli.js +0 -388
  223. package/dist/cli-old/cli.js.map +0 -1
  224. package/dist/commands/review.d.ts +0 -11
  225. package/dist/commands/review.d.ts.map +0 -1
  226. package/dist/commands/review.js +0 -82
  227. package/dist/commands/review.js.map +0 -1
  228. package/dist/database/connection.d.ts +0 -40
  229. package/dist/database/connection.d.ts.map +0 -1
  230. package/dist/database/connection.js +0 -136
  231. package/dist/database/connection.js.map +0 -1
  232. package/dist/database/introspection.d.ts +0 -59
  233. package/dist/database/introspection.d.ts.map +0 -1
  234. package/dist/database/introspection.js +0 -124
  235. package/dist/database/introspection.js.map +0 -1
  236. package/dist/generators/markdown-generator.d.ts +0 -8
  237. package/dist/generators/markdown-generator.d.ts.map +0 -1
  238. package/dist/generators/markdown-generator.js +0 -106
  239. package/dist/generators/markdown-generator.js.map +0 -1
  240. package/dist/generators/sql-generator.d.ts +0 -20
  241. package/dist/generators/sql-generator.d.ts.map +0 -1
  242. package/dist/generators/sql-generator.js +0 -83
  243. package/dist/generators/sql-generator.js.map +0 -1
  244. package/dist/state/state-manager.d.ts +0 -95
  245. package/dist/state/state-manager.d.ts.map +0 -1
  246. package/dist/state/state-manager.js +0 -236
  247. package/dist/state/state-manager.js.map +0 -1
  248. package/dist/types/state-file.d.ts +0 -124
  249. package/dist/types/state-file.d.ts.map +0 -1
  250. package/dist/types/state-file.js +0 -79
  251. package/dist/types/state-file.js.map +0 -1
@@ -0,0 +1,431 @@
1
+ "use strict";
2
+ /**
3
+ * LLM Discovery Validator
4
+ * Uses LLM reasoning to validate and refine PK/FK candidates discovered through statistical analysis
5
+ * Processes one table at a time with rich statistical context
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.LLMDiscoveryValidator = void 0;
9
+ const ai_1 = require("@memberjunction/ai");
10
+ const global_1 = require("@memberjunction/global");
11
+ class LLMDiscoveryValidator {
12
+ constructor(driver, config, aiConfig, statsCache, schemas) {
13
+ this.driver = driver;
14
+ this.config = config;
15
+ this.aiConfig = aiConfig;
16
+ this.statsCache = statsCache;
17
+ this.schemas = schemas;
18
+ // Create LLM instance using MJ ClassFactory
19
+ const llm = global_1.MJGlobal.Instance.ClassFactory.CreateInstance(ai_1.BaseLLM, aiConfig.provider, aiConfig.apiKey);
20
+ if (!llm) {
21
+ throw new Error(`Failed to create LLM instance for provider: ${aiConfig.provider}. Check that the provider name matches a registered BaseLLM subclass.`);
22
+ }
23
+ this.llm = llm;
24
+ }
25
+ /**
26
+ * Validate PK/FK candidates for a single table using LLM reasoning
27
+ */
28
+ async validateTableRelationships(schemaName, tableName, pkCandidates, fkCandidates) {
29
+ // Build rich context for LLM
30
+ const context = this.buildTableContext(schemaName, tableName, pkCandidates, fkCandidates);
31
+ // Create prompt for LLM
32
+ const prompt = this.buildValidationPrompt(context);
33
+ // Call LLM
34
+ const params = {
35
+ model: this.aiConfig.model,
36
+ messages: [
37
+ {
38
+ role: 'system',
39
+ content: 'You are a database schema expert specializing in relationship discovery and validation.'
40
+ },
41
+ {
42
+ role: 'user',
43
+ content: prompt
44
+ }
45
+ ],
46
+ temperature: this.aiConfig.temperature ?? 0.1,
47
+ maxOutputTokens: this.aiConfig.maxTokens,
48
+ responseFormat: 'JSON'
49
+ };
50
+ const chatResult = await this.llm.ChatCompletion(params);
51
+ if (!chatResult.success) {
52
+ return {
53
+ validated: false,
54
+ reasoning: `LLM call failed: ${chatResult.errorMessage}`,
55
+ confidenceAdjustment: 0,
56
+ recommendations: [],
57
+ tokensUsed: 0
58
+ };
59
+ }
60
+ // Parse LLM response
61
+ const content = chatResult.data.choices[0].message.content;
62
+ const usage = chatResult.data.usage;
63
+ try {
64
+ const result = JSON.parse(content);
65
+ return {
66
+ validated: result.validated,
67
+ reasoning: result.reasoning,
68
+ confidenceAdjustment: 0, // Overall adjustment
69
+ recommendations: result.recommendations || [],
70
+ tokensUsed: usage?.totalTokens || 0
71
+ };
72
+ }
73
+ catch (parseError) {
74
+ return {
75
+ validated: false,
76
+ reasoning: `Failed to parse LLM response: ${parseError.message}\n\nRaw content:\n${content}`,
77
+ confidenceAdjustment: 0,
78
+ recommendations: [],
79
+ tokensUsed: usage?.totalTokens || 0
80
+ };
81
+ }
82
+ }
83
+ /**
84
+ * Build rich context for a table including stats from cache
85
+ */
86
+ buildTableContext(schemaName, tableName, pkCandidates, fkCandidates) {
87
+ // Get table stats from cache
88
+ const tableStats = this.statsCache.getTableStats(schemaName, tableName);
89
+ if (!tableStats) {
90
+ console.warn(`[LLMDiscoveryValidator] No cached stats found for table ${schemaName}.${tableName} - validation will be limited`);
91
+ // Return minimal context without column stats
92
+ return {
93
+ targetTable: {
94
+ schema: schemaName,
95
+ table: tableName,
96
+ rowCount: 0,
97
+ columns: []
98
+ },
99
+ relatedTables: [],
100
+ pkCandidates: pkCandidates.map(pk => ({
101
+ columnNames: pk.columnNames,
102
+ confidence: pk.confidence,
103
+ reasoning: pk.evidence ? `Uniqueness: ${pk.evidence.uniqueness}, Naming: ${pk.evidence.namingScore}` : 'Statistical analysis'
104
+ })),
105
+ fkCandidates: fkCandidates.map(fk => ({
106
+ sourceColumn: fk.sourceColumn,
107
+ targetTable: `${fk.targetSchema}.${fk.targetTable}`,
108
+ targetColumn: fk.targetColumn,
109
+ confidence: fk.confidence,
110
+ reasoning: fk.evidence ? `Naming: ${fk.evidence.namingMatch}, Value overlap: ${fk.evidence.valueOverlap}` : 'Statistical analysis'
111
+ }))
112
+ };
113
+ }
114
+ // Build target table context with column stats
115
+ const targetTable = {
116
+ schema: schemaName,
117
+ table: tableName,
118
+ rowCount: tableStats.totalRows,
119
+ columns: Array.from(tableStats.columns.values()).map(col => ({
120
+ name: col.columnName,
121
+ type: col.dataType,
122
+ uniqueness: col.uniqueness,
123
+ nullPercentage: col.nullPercentage,
124
+ distinctCount: col.distinctCount,
125
+ dataPattern: col.dataPattern,
126
+ sampleValues: col.sampleValues.slice(0, 10) // Limit sample size for prompt
127
+ }))
128
+ };
129
+ // Find related tables (tables with columns that have similar names)
130
+ const relatedTables = this.findRelatedTables(schemaName, tableName);
131
+ // Build PK candidates context
132
+ const pkContext = pkCandidates.map(pk => ({
133
+ columnNames: pk.columnNames,
134
+ confidence: pk.confidence,
135
+ reasoning: this.buildPKReasoning(pk)
136
+ }));
137
+ // Build FK candidates context
138
+ const fkContext = fkCandidates
139
+ .filter(fk => fk.sourceTable === tableName) // Only FKs from this table
140
+ .map(fk => ({
141
+ sourceColumn: fk.sourceColumn,
142
+ targetTable: `${fk.targetSchema}.${fk.targetTable}`,
143
+ targetColumn: fk.targetColumn,
144
+ confidence: fk.confidence,
145
+ reasoning: this.buildFKReasoning(fk)
146
+ }));
147
+ return {
148
+ targetTable,
149
+ relatedTables,
150
+ pkCandidates: pkContext,
151
+ fkCandidates: fkContext
152
+ };
153
+ }
154
+ /**
155
+ * Find tables that might be related based on column name patterns
156
+ */
157
+ findRelatedTables(schemaName, tableName) {
158
+ const related = [];
159
+ // Get all columns in target table
160
+ const targetTableStats = this.statsCache.getTableStats(schemaName, tableName);
161
+ if (!targetTableStats)
162
+ return related;
163
+ const targetColumns = Array.from(targetTableStats.columns.values());
164
+ // Look for columns with similar names in other tables
165
+ for (const otherTableStats of this.statsCache.getAllTables()) {
166
+ // Skip the target table itself
167
+ if (otherTableStats.schemaName === schemaName &&
168
+ otherTableStats.tableName === tableName) {
169
+ continue;
170
+ }
171
+ const potentialRelationships = [];
172
+ for (const targetCol of targetColumns) {
173
+ for (const otherCol of otherTableStats.columns.values()) {
174
+ const similarity = this.calculateColumnSimilarity(targetCol, otherCol);
175
+ if (similarity > 0.6) {
176
+ potentialRelationships.push({
177
+ columnName: `${targetCol.columnName} ↔ ${otherCol.columnName}`,
178
+ similarity,
179
+ reason: this.explainSimilarity(targetCol, otherCol, similarity)
180
+ });
181
+ }
182
+ }
183
+ }
184
+ if (potentialRelationships.length > 0) {
185
+ related.push({
186
+ schema: otherTableStats.schemaName,
187
+ table: otherTableStats.tableName,
188
+ rowCount: otherTableStats.totalRows,
189
+ potentialRelationships: potentialRelationships.sort((a, b) => b.similarity - a.similarity).slice(0, 5) // Top 5 relationships
190
+ });
191
+ }
192
+ }
193
+ // Return top 10 most related tables
194
+ return related
195
+ .sort((a, b) => {
196
+ const aMaxSim = Math.max(...a.potentialRelationships.map(r => r.similarity));
197
+ const bMaxSim = Math.max(...b.potentialRelationships.map(r => r.similarity));
198
+ return bMaxSim - aMaxSim;
199
+ })
200
+ .slice(0, 10);
201
+ }
202
+ /**
203
+ * Calculate similarity between two columns
204
+ */
205
+ calculateColumnSimilarity(col1, col2) {
206
+ let score = 0;
207
+ // Name similarity (50% weight)
208
+ const nameSim = this.calculateNameSimilarity(col1.columnName, col2.columnName);
209
+ score += nameSim * 0.5;
210
+ // Data type match (30% weight)
211
+ if (this.areDataTypesCompatible(col1.dataType, col2.dataType)) {
212
+ score += 0.3;
213
+ }
214
+ // Cardinality relationship (20% weight)
215
+ // If one column has much higher uniqueness, they might be PK-FK pair
216
+ const uniquenessDiff = Math.abs(col1.uniqueness - col2.uniqueness);
217
+ if (uniquenessDiff > 0.3) {
218
+ score += 0.2;
219
+ }
220
+ return score;
221
+ }
222
+ /**
223
+ * Calculate name similarity using Levenshtein distance
224
+ */
225
+ calculateNameSimilarity(name1, name2) {
226
+ const lower1 = name1.toLowerCase();
227
+ const lower2 = name2.toLowerCase();
228
+ // Exact match
229
+ if (lower1 === lower2)
230
+ return 1.0;
231
+ // One contains the other
232
+ if (lower1.includes(lower2) || lower2.includes(lower1)) {
233
+ return 0.8;
234
+ }
235
+ // Levenshtein distance
236
+ const distance = this.levenshteinDistance(lower1, lower2);
237
+ const maxLength = Math.max(lower1.length, lower2.length);
238
+ return 1 - distance / maxLength;
239
+ }
240
+ /**
241
+ * Calculate Levenshtein distance
242
+ */
243
+ levenshteinDistance(str1, str2) {
244
+ const matrix = [];
245
+ for (let i = 0; i <= str2.length; i++) {
246
+ matrix[i] = [i];
247
+ }
248
+ for (let j = 0; j <= str1.length; j++) {
249
+ matrix[0][j] = j;
250
+ }
251
+ for (let i = 1; i <= str2.length; i++) {
252
+ for (let j = 1; j <= str1.length; j++) {
253
+ if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
254
+ matrix[i][j] = matrix[i - 1][j - 1];
255
+ }
256
+ else {
257
+ matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
258
+ }
259
+ }
260
+ }
261
+ return matrix[str2.length][str1.length];
262
+ }
263
+ /**
264
+ * Check if data types are compatible
265
+ */
266
+ areDataTypesCompatible(type1, type2) {
267
+ const normalize = (type) => type
268
+ .toLowerCase()
269
+ .replace(/\([^)]*\)/g, '')
270
+ .replace(/\s+/g, '');
271
+ const t1 = normalize(type1);
272
+ const t2 = normalize(type2);
273
+ if (t1 === t2)
274
+ return true;
275
+ // INT variants
276
+ const intTypes = ['int', 'integer', 'bigint', 'smallint', 'tinyint'];
277
+ if (intTypes.some(t => t1.includes(t)) && intTypes.some(t => t2.includes(t))) {
278
+ return true;
279
+ }
280
+ // String variants
281
+ const stringTypes = ['varchar', 'char', 'nvarchar', 'nchar', 'text'];
282
+ if (stringTypes.some(t => t1.includes(t)) &&
283
+ stringTypes.some(t => t2.includes(t))) {
284
+ return true;
285
+ }
286
+ // GUID variants
287
+ if ((t1.includes('uniqueidentifier') || t1.includes('uuid') || t1.includes('guid')) &&
288
+ (t2.includes('uniqueidentifier') || t2.includes('uuid') || t2.includes('guid'))) {
289
+ return true;
290
+ }
291
+ return false;
292
+ }
293
+ /**
294
+ * Explain why two columns are similar
295
+ */
296
+ explainSimilarity(col1, col2, similarity) {
297
+ const reasons = [];
298
+ if (col1.columnName.toLowerCase() === col2.columnName.toLowerCase()) {
299
+ reasons.push('exact name match');
300
+ }
301
+ else if (col1.columnName.toLowerCase().includes(col2.columnName.toLowerCase()) ||
302
+ col2.columnName.toLowerCase().includes(col1.columnName.toLowerCase())) {
303
+ reasons.push('name similarity');
304
+ }
305
+ if (this.areDataTypesCompatible(col1.dataType, col2.dataType)) {
306
+ reasons.push('compatible types');
307
+ }
308
+ if (Math.abs(col1.uniqueness - col2.uniqueness) > 0.3) {
309
+ reasons.push('PK-FK cardinality pattern');
310
+ }
311
+ return reasons.join(', ');
312
+ }
313
+ /**
314
+ * Build reasoning string for PK candidate
315
+ */
316
+ buildPKReasoning(pk) {
317
+ const reasons = [];
318
+ if (pk.evidence.uniqueness >= 0.99) {
319
+ reasons.push('highly unique');
320
+ }
321
+ if (pk.evidence.nullCount === 0) {
322
+ reasons.push('no nulls');
323
+ }
324
+ if (pk.evidence.namingScore > 0.7) {
325
+ reasons.push('matches PK naming pattern');
326
+ }
327
+ if (pk.evidence.dataPattern !== 'unknown') {
328
+ reasons.push(`${pk.evidence.dataPattern} pattern`);
329
+ }
330
+ return reasons.join(', ');
331
+ }
332
+ /**
333
+ * Build reasoning string for FK candidate
334
+ */
335
+ buildFKReasoning(fk) {
336
+ const reasons = [];
337
+ if (fk.evidence.valueOverlap >= 0.9) {
338
+ reasons.push(`${(fk.evidence.valueOverlap * 100).toFixed(0)}% value overlap`);
339
+ }
340
+ if (fk.evidence.namingMatch > 0.7) {
341
+ reasons.push('strong name similarity');
342
+ }
343
+ if (fk.evidence.dataTypeMatch) {
344
+ reasons.push('matching data types');
345
+ }
346
+ if (fk.evidence.orphanCount === 0) {
347
+ reasons.push('no orphans');
348
+ }
349
+ return reasons.join(', ');
350
+ }
351
+ /**
352
+ * Build LLM validation prompt
353
+ */
354
+ buildValidationPrompt(context) {
355
+ return `
356
+ You are a database schema expert analyzing potential primary keys and foreign keys.
357
+
358
+ ## Target Table: ${context.targetTable.schema}.${context.targetTable.table}
359
+ Row Count: ${context.targetTable.rowCount}
360
+
361
+ ### Columns and Statistics:
362
+ ${context.targetTable.columns
363
+ .map(col => `
364
+ - **${col.name}** (${col.type})
365
+ - Uniqueness: ${(col.uniqueness * 100).toFixed(1)}%
366
+ - Null %: ${(col.nullPercentage * 100).toFixed(1)}%
367
+ - Distinct Values: ${col.distinctCount}
368
+ - Pattern: ${col.dataPattern}
369
+ - Sample: ${col.sampleValues.slice(0, 5).join(', ')}
370
+ `)
371
+ .join('\n')}
372
+
373
+ ${context.relatedTables && context.relatedTables.length > 0
374
+ ? `
375
+ ### Related Tables (by column name similarity):
376
+ ${context.relatedTables
377
+ .map(table => `
378
+ - **${table.schema}.${table.table}** (${table.rowCount} rows)
379
+ ${table.potentialRelationships.map(rel => ` - ${rel.columnName}: ${rel.reason}`).join('\n ')}
380
+ `)
381
+ .join('\n')}
382
+ `
383
+ : ''}
384
+
385
+ ### Statistical Analysis Found:
386
+
387
+ **Primary Key Candidates:**
388
+ ${context.pkCandidates.length > 0
389
+ ? context.pkCandidates
390
+ .map(pk => `
391
+ - ${pk.columnNames.join(', ')} (${pk.confidence}% confidence)
392
+ Reasoning: ${pk.reasoning}
393
+ `)
394
+ .join('\n')
395
+ : 'None'}
396
+
397
+ **Foreign Key Candidates:**
398
+ ${context.fkCandidates.length > 0
399
+ ? context.fkCandidates
400
+ .map(fk => `
401
+ - ${fk.sourceColumn} → ${fk.targetTable}.${fk.targetColumn} (${fk.confidence}% confidence)
402
+ Reasoning: ${fk.reasoning}
403
+ `)
404
+ .join('\n')
405
+ : 'None'}
406
+
407
+ ## Your Task:
408
+ Analyze the statistical findings and provide validation:
409
+
410
+ 1. **Validate Primary Keys**: Are the PK candidates correct? Should any be removed or added?
411
+ 2. **Validate Foreign Keys**: Are the FK candidates correct? Look for:
412
+ - Columns marked as PKs that should actually be FKs
413
+ - Missing FK relationships based on column names and data patterns
414
+ 3. **Cross-table Context**: Use the related tables information to identify relationships
415
+
416
+ **Output Format:**
417
+ {
418
+ "validated": true/false,
419
+ "reasoning": "Your detailed analysis",
420
+ "confidenceAdjustments": [
421
+ { "type": "pk|fk", "table": "...", "column": "...", "adjustment": -20 to +20, "reason": "..." }
422
+ ],
423
+ "recommendations": [
424
+ { "type": "confirm|reject|modify|add_new", "target": "pk|fk", "details": "..." }
425
+ ]
426
+ }
427
+ `.trim();
428
+ }
429
+ }
430
+ exports.LLMDiscoveryValidator = LLMDiscoveryValidator;
431
+ //# sourceMappingURL=LLMDiscoveryValidator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LLMDiscoveryValidator.js","sourceRoot":"","sources":["../../src/discovery/LLMDiscoveryValidator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * LLM Sanity Checker
3
+ * Uses LLM intelligence to review and reject obviously wrong PK/FK candidates
4
+ * This is a MACRO-LEVEL review that happens once after statistical detection
5
+ */
6
+ import { PKCandidate, FKCandidate } from '../types/discovery.js';
7
+ import { AIConfig } from '../types/config.js';
8
+ export interface SanityCheckResult {
9
+ invalidPKs: Array<{
10
+ schema: string;
11
+ table: string;
12
+ column: string;
13
+ reason: string;
14
+ }>;
15
+ invalidFKs: Array<{
16
+ schema: string;
17
+ table: string;
18
+ column: string;
19
+ reason: string;
20
+ }>;
21
+ suggestions: string[];
22
+ tokensUsed: number;
23
+ }
24
+ export declare class LLMSanityChecker {
25
+ private aiConfig;
26
+ private llm;
27
+ constructor(aiConfig: AIConfig);
28
+ /**
29
+ * Review all detected PKs and FKs for obvious errors
30
+ * This is a one-time macro review after statistical detection
31
+ */
32
+ reviewCandidates(pkCandidates: PKCandidate[], fkCandidates: FKCandidate[]): Promise<SanityCheckResult>;
33
+ /**
34
+ * Build the sanity check prompt with all candidate information
35
+ */
36
+ private buildSanityCheckPrompt;
37
+ }
38
+ //# sourceMappingURL=LLMSanityChecker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LLMSanityChecker.d.ts","sourceRoot":"","sources":["../../src/discovery/LLMSanityChecker.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,KAAK,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IACH,UAAU,EAAE,KAAK,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;IACH,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,gBAAgB;IAGf,OAAO,CAAC,QAAQ;IAF5B,OAAO,CAAC,GAAG,CAAU;gBAED,QAAQ,EAAE,QAAQ;IAiBtC;;;OAGG;IACU,gBAAgB,CAC3B,YAAY,EAAE,WAAW,EAAE,EAC3B,YAAY,EAAE,WAAW,EAAE,GAC1B,OAAO,CAAC,iBAAiB,CAAC;IAoE7B;;OAEG;IACH,OAAO,CAAC,sBAAsB;CAgF/B"}
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * LLM Sanity Checker
4
+ * Uses LLM intelligence to review and reject obviously wrong PK/FK candidates
5
+ * This is a MACRO-LEVEL review that happens once after statistical detection
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.LLMSanityChecker = void 0;
9
+ const ai_1 = require("@memberjunction/ai");
10
+ const global_1 = require("@memberjunction/global");
11
+ class LLMSanityChecker {
12
+ constructor(aiConfig) {
13
+ this.aiConfig = aiConfig;
14
+ // Create LLM instance using MJ ClassFactory
15
+ const llm = global_1.MJGlobal.Instance.ClassFactory.CreateInstance(ai_1.BaseLLM, aiConfig.provider, aiConfig.apiKey);
16
+ if (!llm) {
17
+ throw new Error(`Failed to create LLM instance for provider: ${aiConfig.provider}`);
18
+ }
19
+ this.llm = llm;
20
+ }
21
+ /**
22
+ * Review all detected PKs and FKs for obvious errors
23
+ * This is a one-time macro review after statistical detection
24
+ */
25
+ async reviewCandidates(pkCandidates, fkCandidates) {
26
+ console.log(`[LLMSanityChecker] Reviewing ${pkCandidates.length} PK candidates and ${fkCandidates.length} FK candidates`);
27
+ // Build prompt with all candidates
28
+ const prompt = this.buildSanityCheckPrompt(pkCandidates, fkCandidates);
29
+ // Call LLM
30
+ const params = {
31
+ model: this.aiConfig.model,
32
+ messages: [
33
+ {
34
+ role: 'system',
35
+ content: 'You are a database schema expert specializing in identifying incorrect primary key and foreign key candidates. Your job is to reject obviously wrong candidates based on naming patterns and data types.'
36
+ },
37
+ {
38
+ role: 'user',
39
+ content: prompt
40
+ }
41
+ ],
42
+ temperature: 0.1,
43
+ maxOutputTokens: this.aiConfig.maxTokens,
44
+ responseFormat: 'JSON'
45
+ };
46
+ console.log(`[LLMSanityChecker] Calling LLM for sanity check...`);
47
+ const chatResult = await this.llm.ChatCompletion(params);
48
+ if (!chatResult.success) {
49
+ console.warn(`[LLMSanityChecker] LLM call failed: ${chatResult.errorMessage}`);
50
+ return {
51
+ invalidPKs: [],
52
+ invalidFKs: [],
53
+ suggestions: [],
54
+ tokensUsed: 0
55
+ };
56
+ }
57
+ // Parse LLM response
58
+ const content = chatResult.data.choices[0].message.content;
59
+ const usage = chatResult.data.usage;
60
+ try {
61
+ const result = JSON.parse(content);
62
+ console.log(`[LLMSanityChecker] Found ${result.invalidPKs.length} invalid PKs, ${result.invalidFKs.length} invalid FKs`);
63
+ return {
64
+ invalidPKs: result.invalidPKs,
65
+ invalidFKs: result.invalidFKs,
66
+ suggestions: result.suggestions || [],
67
+ tokensUsed: usage?.totalTokens || 0
68
+ };
69
+ }
70
+ catch (parseError) {
71
+ console.error(`[LLMSanityChecker] Failed to parse LLM response: ${parseError.message}`);
72
+ console.error(`[LLMSanityChecker] Raw content: ${content}`);
73
+ return {
74
+ invalidPKs: [],
75
+ invalidFKs: [],
76
+ suggestions: [],
77
+ tokensUsed: usage?.totalTokens || 0
78
+ };
79
+ }
80
+ }
81
+ /**
82
+ * Build the sanity check prompt with all candidate information
83
+ */
84
+ buildSanityCheckPrompt(pkCandidates, fkCandidates) {
85
+ // Group PKs by table
86
+ const pksByTable = new Map();
87
+ for (const pk of pkCandidates) {
88
+ const key = `${pk.schemaName}.${pk.tableName}`;
89
+ if (!pksByTable.has(key)) {
90
+ pksByTable.set(key, []);
91
+ }
92
+ pksByTable.get(key).push(pk);
93
+ }
94
+ // Group FKs by table
95
+ const fksByTable = new Map();
96
+ for (const fk of fkCandidates) {
97
+ const key = `${fk.schemaName}.${fk.sourceTable}`;
98
+ if (!fksByTable.has(key)) {
99
+ fksByTable.set(key, []);
100
+ }
101
+ fksByTable.get(key).push(fk);
102
+ }
103
+ let prompt = `You are reviewing database primary key and foreign key candidates for obvious errors.
104
+
105
+ CRITICAL RULES:
106
+ 1. Date/time fields are NEVER primary keys (they are not unique per row)
107
+ 2. Quantity, count, amount fields are NEVER primary keys
108
+ 3. Text fields (names, descriptions, notes) are NEVER primary keys
109
+ 4. Boolean/flag fields are NEVER primary keys
110
+ 5. Each table should have exactly 1 PK (or a composite PK with 2-3 columns max)
111
+ 6. Foreign keys should reference another table, not point to themselves
112
+
113
+ DETECTED PRIMARY KEY CANDIDATES:
114
+
115
+ `;
116
+ // Add PK candidates
117
+ for (const [tableKey, pks] of pksByTable.entries()) {
118
+ prompt += `\nTable: ${tableKey}\n`;
119
+ for (const pk of pks) {
120
+ const uniqueness = pk.evidence?.uniqueness.toFixed(2) || '?';
121
+ const pattern = pk.evidence?.dataPattern || 'unknown';
122
+ prompt += ` - ${pk.columnNames.join(', ')} (pattern: ${pattern}, uniqueness: ${uniqueness}, confidence: ${pk.confidence}%)\n`;
123
+ }
124
+ }
125
+ prompt += `\nDETECTED FOREIGN KEY CANDIDATES:
126
+
127
+ `;
128
+ // Add FK candidates
129
+ for (const [tableKey, fks] of fksByTable.entries()) {
130
+ prompt += `\nTable: ${tableKey}\n`;
131
+ for (const fk of fks) {
132
+ prompt += ` - ${fk.sourceColumn} → ${fk.targetSchema}.${fk.targetTable}.${fk.targetColumn} (confidence: ${fk.confidence}%)\n`;
133
+ }
134
+ }
135
+ prompt += `\nTASK:
136
+ Identify PKs and FKs that are definitely WRONG based on the rules above.
137
+
138
+ OUTPUT FORMAT (JSON):
139
+ {
140
+ "invalidPKs": [
141
+ {"schema": "sales", "table": "addr", "column": "ln2", "reason": "VARCHAR field, not a unique identifier"},
142
+ {"schema": "sales", "table": "cst", "column": "lst_ord", "reason": "Date field, cannot be primary key"}
143
+ ],
144
+ "invalidFKs": [
145
+ {"schema": "inv", "table": "adj", "column": "adj_id", "reason": "Self-referencing FK to same table, likely misidentified"}
146
+ ],
147
+ "suggestions": [
148
+ "sales.addr should have only addr_id as PK",
149
+ "sales.cst should have only cst_id as PK"
150
+ ]
151
+ }`;
152
+ return prompt;
153
+ }
154
+ }
155
+ exports.LLMSanityChecker = LLMSanityChecker;
156
+ //# sourceMappingURL=LLMSanityChecker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LLMSanityChecker.js","sourceRoot":"","sources":["../../src/discovery/LLMSanityChecker.ts"],"names":[],"mappings":"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"}