@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.
- package/README.md +652 -165
- package/bin/run.js +7 -0
- package/dist/api/DBAutoDocAPI.d.ts +252 -0
- package/dist/api/DBAutoDocAPI.d.ts.map +1 -0
- package/dist/api/DBAutoDocAPI.js +530 -0
- package/dist/api/DBAutoDocAPI.js.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +10 -0
- package/dist/api/index.js.map +1 -0
- package/dist/commands/analyze.d.ts +6 -4
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +58 -71
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/export.d.ts +14 -4
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +156 -61
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/init.d.ts +3 -4
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +155 -146
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/reset.d.ts +4 -1
- package/dist/commands/reset.d.ts.map +1 -1
- package/dist/commands/reset.js +33 -19
- package/dist/commands/reset.js.map +1 -1
- package/dist/commands/status.d.ts +10 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +66 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/core/AnalysisEngine.d.ts +108 -0
- package/dist/core/AnalysisEngine.d.ts.map +1 -0
- package/dist/core/AnalysisEngine.js +716 -0
- package/dist/core/AnalysisEngine.js.map +1 -0
- package/dist/core/AnalysisOrchestrator.d.ts +37 -0
- package/dist/core/AnalysisOrchestrator.d.ts.map +1 -0
- package/dist/core/AnalysisOrchestrator.js +294 -0
- package/dist/core/AnalysisOrchestrator.js.map +1 -0
- package/dist/core/BackpropagationEngine.d.ts +32 -0
- package/dist/core/BackpropagationEngine.d.ts.map +1 -0
- package/dist/core/BackpropagationEngine.js +121 -0
- package/dist/core/BackpropagationEngine.js.map +1 -0
- package/dist/core/ConvergenceDetector.d.ts +27 -0
- package/dist/core/ConvergenceDetector.d.ts.map +1 -0
- package/dist/core/ConvergenceDetector.js +92 -0
- package/dist/core/ConvergenceDetector.js.map +1 -0
- package/dist/core/GuardrailsManager.d.ts +78 -0
- package/dist/core/GuardrailsManager.d.ts.map +1 -0
- package/dist/core/GuardrailsManager.js +367 -0
- package/dist/core/GuardrailsManager.js.map +1 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/database/Database.d.ts +56 -0
- package/dist/database/Database.d.ts.map +1 -0
- package/dist/database/Database.js +172 -0
- package/dist/database/Database.js.map +1 -0
- package/dist/database/TopologicalSorter.d.ts +25 -0
- package/dist/database/TopologicalSorter.d.ts.map +1 -0
- package/dist/database/TopologicalSorter.js +150 -0
- package/dist/database/TopologicalSorter.js.map +1 -0
- package/dist/database/index.d.ts +6 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +14 -0
- package/dist/database/index.js.map +1 -0
- package/dist/discovery/ColumnStatsCache.d.ts +91 -0
- package/dist/discovery/ColumnStatsCache.d.ts.map +1 -0
- package/dist/discovery/ColumnStatsCache.js +231 -0
- package/dist/discovery/ColumnStatsCache.js.map +1 -0
- package/dist/discovery/DiscoveryEngine.d.ts +100 -0
- package/dist/discovery/DiscoveryEngine.d.ts.map +1 -0
- package/dist/discovery/DiscoveryEngine.js +726 -0
- package/dist/discovery/DiscoveryEngine.js.map +1 -0
- package/dist/discovery/DiscoveryTriggerAnalyzer.d.ts +57 -0
- package/dist/discovery/DiscoveryTriggerAnalyzer.d.ts.map +1 -0
- package/dist/discovery/DiscoveryTriggerAnalyzer.js +186 -0
- package/dist/discovery/DiscoveryTriggerAnalyzer.js.map +1 -0
- package/dist/discovery/FKDetector.d.ts +47 -0
- package/dist/discovery/FKDetector.d.ts.map +1 -0
- package/dist/discovery/FKDetector.js +317 -0
- package/dist/discovery/FKDetector.js.map +1 -0
- package/dist/discovery/LLMDiscoveryValidator.d.ts +64 -0
- package/dist/discovery/LLMDiscoveryValidator.d.ts.map +1 -0
- package/dist/discovery/LLMDiscoveryValidator.js +431 -0
- package/dist/discovery/LLMDiscoveryValidator.js.map +1 -0
- package/dist/discovery/LLMSanityChecker.d.ts +38 -0
- package/dist/discovery/LLMSanityChecker.d.ts.map +1 -0
- package/dist/discovery/LLMSanityChecker.js +156 -0
- package/dist/discovery/LLMSanityChecker.js.map +1 -0
- package/dist/discovery/PKDetector.d.ts +62 -0
- package/dist/discovery/PKDetector.d.ts.map +1 -0
- package/dist/discovery/PKDetector.js +436 -0
- package/dist/discovery/PKDetector.js.map +1 -0
- package/dist/discovery/index.d.ts +9 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +25 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/drivers/BaseAutoDocDriver.d.ts +132 -0
- package/dist/drivers/BaseAutoDocDriver.d.ts.map +1 -0
- package/dist/drivers/BaseAutoDocDriver.js +121 -0
- package/dist/drivers/BaseAutoDocDriver.js.map +1 -0
- package/dist/drivers/MySQLDriver.d.ts +61 -0
- package/dist/drivers/MySQLDriver.d.ts.map +1 -0
- package/dist/drivers/MySQLDriver.js +668 -0
- package/dist/drivers/MySQLDriver.js.map +1 -0
- package/dist/drivers/PostgreSQLDriver.d.ts +65 -0
- package/dist/drivers/PostgreSQLDriver.d.ts.map +1 -0
- package/dist/drivers/PostgreSQLDriver.js +704 -0
- package/dist/drivers/PostgreSQLDriver.js.map +1 -0
- package/dist/drivers/SQLServerDriver.d.ts +61 -0
- package/dist/drivers/SQLServerDriver.d.ts.map +1 -0
- package/dist/drivers/SQLServerDriver.js +667 -0
- package/dist/drivers/SQLServerDriver.js.map +1 -0
- package/dist/generators/CSVGenerator.d.ts +35 -0
- package/dist/generators/CSVGenerator.d.ts.map +1 -0
- package/dist/generators/CSVGenerator.js +154 -0
- package/dist/generators/CSVGenerator.js.map +1 -0
- package/dist/generators/HTMLGenerator.d.ts +29 -0
- package/dist/generators/HTMLGenerator.d.ts.map +1 -0
- package/dist/generators/HTMLGenerator.js +710 -0
- package/dist/generators/HTMLGenerator.js.map +1 -0
- package/dist/generators/MarkdownGenerator.d.ts +27 -0
- package/dist/generators/MarkdownGenerator.d.ts.map +1 -0
- package/dist/generators/MarkdownGenerator.js +361 -0
- package/dist/generators/MarkdownGenerator.js.map +1 -0
- package/dist/generators/MermaidGenerator.d.ts +35 -0
- package/dist/generators/MermaidGenerator.d.ts.map +1 -0
- package/dist/generators/MermaidGenerator.js +321 -0
- package/dist/generators/MermaidGenerator.js.map +1 -0
- package/dist/generators/ReportGenerator.d.ts +22 -0
- package/dist/generators/ReportGenerator.d.ts.map +1 -0
- package/dist/generators/ReportGenerator.js +176 -0
- package/dist/generators/ReportGenerator.js.map +1 -0
- package/dist/generators/SQLGenerator.d.ts +31 -0
- package/dist/generators/SQLGenerator.d.ts.map +1 -0
- package/dist/generators/SQLGenerator.js +168 -0
- package/dist/generators/SQLGenerator.js.map +1 -0
- package/dist/generators/index.d.ts +10 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +19 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/index.d.ts +11 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -20
- package/dist/index.js.map +1 -1
- package/dist/prompts/PromptEngine.d.ts +65 -0
- package/dist/prompts/PromptEngine.d.ts.map +1 -0
- package/dist/prompts/PromptEngine.js +282 -0
- package/dist/prompts/PromptEngine.js.map +1 -0
- package/dist/prompts/PromptFileLoader.d.ts +21 -0
- package/dist/prompts/PromptFileLoader.d.ts.map +1 -0
- package/dist/prompts/PromptFileLoader.js +74 -0
- package/dist/prompts/PromptFileLoader.js.map +1 -0
- package/dist/prompts/index.d.ts +6 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +11 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/state/IterationTracker.d.ts +64 -0
- package/dist/state/IterationTracker.d.ts.map +1 -0
- package/dist/state/IterationTracker.js +136 -0
- package/dist/state/IterationTracker.js.map +1 -0
- package/dist/state/StateManager.d.ts +79 -0
- package/dist/state/StateManager.d.ts.map +1 -0
- package/dist/state/StateManager.js +348 -0
- package/dist/state/StateManager.js.map +1 -0
- package/dist/state/StateValidator.d.ts +24 -0
- package/dist/state/StateValidator.d.ts.map +1 -0
- package/dist/state/StateValidator.js +147 -0
- package/dist/state/StateValidator.js.map +1 -0
- package/dist/state/index.d.ts +7 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +13 -0
- package/dist/state/index.js.map +1 -0
- package/dist/types/analysis.d.ts +76 -0
- package/dist/types/analysis.d.ts.map +1 -0
- package/dist/types/analysis.js +6 -0
- package/dist/types/analysis.js.map +1 -0
- package/dist/types/config.d.ts +132 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +7 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/discovery.d.ts +277 -0
- package/dist/types/discovery.d.ts.map +1 -0
- package/dist/types/discovery.js +7 -0
- package/dist/types/discovery.js.map +1 -0
- package/dist/types/driver.d.ts +148 -0
- package/dist/types/driver.d.ts.map +1 -0
- package/dist/types/driver.js +7 -0
- package/dist/types/driver.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +24 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/prompts.d.ts +158 -0
- package/dist/types/prompts.d.ts.map +1 -0
- package/dist/types/prompts.js +6 -0
- package/dist/types/prompts.js.map +1 -0
- package/dist/types/state.d.ts +278 -0
- package/dist/types/state.d.ts.map +1 -0
- package/dist/types/state.js +7 -0
- package/dist/types/state.js.map +1 -0
- package/dist/utils/config-loader.d.ts +29 -0
- package/dist/utils/config-loader.d.ts.map +1 -0
- package/dist/utils/config-loader.js +163 -0
- package/dist/utils/config-loader.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +24 -3
- package/dist/ai/simple-ai-client.d.ts +0 -70
- package/dist/ai/simple-ai-client.d.ts.map +0 -1
- package/dist/ai/simple-ai-client.js +0 -181
- package/dist/ai/simple-ai-client.js.map +0 -1
- package/dist/analyzers/analyzer.d.ts +0 -23
- package/dist/analyzers/analyzer.d.ts.map +0 -1
- package/dist/analyzers/analyzer.js +0 -127
- package/dist/analyzers/analyzer.js.map +0 -1
- package/dist/cli-old/cli.d.ts +0 -3
- package/dist/cli-old/cli.d.ts.map +0 -1
- package/dist/cli-old/cli.js +0 -388
- package/dist/cli-old/cli.js.map +0 -1
- package/dist/commands/review.d.ts +0 -11
- package/dist/commands/review.d.ts.map +0 -1
- package/dist/commands/review.js +0 -82
- package/dist/commands/review.js.map +0 -1
- package/dist/database/connection.d.ts +0 -40
- package/dist/database/connection.d.ts.map +0 -1
- package/dist/database/connection.js +0 -136
- package/dist/database/connection.js.map +0 -1
- package/dist/database/introspection.d.ts +0 -59
- package/dist/database/introspection.d.ts.map +0 -1
- package/dist/database/introspection.js +0 -124
- package/dist/database/introspection.js.map +0 -1
- package/dist/generators/markdown-generator.d.ts +0 -8
- package/dist/generators/markdown-generator.d.ts.map +0 -1
- package/dist/generators/markdown-generator.js +0 -106
- package/dist/generators/markdown-generator.js.map +0 -1
- package/dist/generators/sql-generator.d.ts +0 -20
- package/dist/generators/sql-generator.d.ts.map +0 -1
- package/dist/generators/sql-generator.js +0 -83
- package/dist/generators/sql-generator.js.map +0 -1
- package/dist/state/state-manager.d.ts +0 -95
- package/dist/state/state-manager.d.ts.map +0 -1
- package/dist/state/state-manager.js +0 -236
- package/dist/state/state-manager.js.map +0 -1
- package/dist/types/state-file.d.ts +0 -124
- package/dist/types/state-file.d.ts.map +0 -1
- package/dist/types/state-file.js +0 -79
- 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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"}
|