@memberjunction/db-auto-doc 2.117.0 → 2.119.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 (263) hide show
  1. package/README.md +803 -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/generate-queries.d.ts +17 -0
  20. package/dist/commands/generate-queries.d.ts.map +1 -0
  21. package/dist/commands/generate-queries.js +182 -0
  22. package/dist/commands/generate-queries.js.map +1 -0
  23. package/dist/commands/init.d.ts +3 -4
  24. package/dist/commands/init.d.ts.map +1 -1
  25. package/dist/commands/init.js +206 -144
  26. package/dist/commands/init.js.map +1 -1
  27. package/dist/commands/reset.d.ts +4 -1
  28. package/dist/commands/reset.d.ts.map +1 -1
  29. package/dist/commands/reset.js +33 -19
  30. package/dist/commands/reset.js.map +1 -1
  31. package/dist/commands/status.d.ts +10 -0
  32. package/dist/commands/status.d.ts.map +1 -0
  33. package/dist/commands/status.js +66 -0
  34. package/dist/commands/status.js.map +1 -0
  35. package/dist/core/AnalysisEngine.d.ts +108 -0
  36. package/dist/core/AnalysisEngine.d.ts.map +1 -0
  37. package/dist/core/AnalysisEngine.js +716 -0
  38. package/dist/core/AnalysisEngine.js.map +1 -0
  39. package/dist/core/AnalysisOrchestrator.d.ts +41 -0
  40. package/dist/core/AnalysisOrchestrator.d.ts.map +1 -0
  41. package/dist/core/AnalysisOrchestrator.js +377 -0
  42. package/dist/core/AnalysisOrchestrator.js.map +1 -0
  43. package/dist/core/BackpropagationEngine.d.ts +32 -0
  44. package/dist/core/BackpropagationEngine.d.ts.map +1 -0
  45. package/dist/core/BackpropagationEngine.js +121 -0
  46. package/dist/core/BackpropagationEngine.js.map +1 -0
  47. package/dist/core/ConvergenceDetector.d.ts +27 -0
  48. package/dist/core/ConvergenceDetector.d.ts.map +1 -0
  49. package/dist/core/ConvergenceDetector.js +92 -0
  50. package/dist/core/ConvergenceDetector.js.map +1 -0
  51. package/dist/core/GuardrailsManager.d.ts +78 -0
  52. package/dist/core/GuardrailsManager.d.ts.map +1 -0
  53. package/dist/core/GuardrailsManager.js +367 -0
  54. package/dist/core/GuardrailsManager.js.map +1 -0
  55. package/dist/core/index.d.ts +7 -0
  56. package/dist/core/index.d.ts.map +1 -0
  57. package/dist/core/index.js +13 -0
  58. package/dist/core/index.js.map +1 -0
  59. package/dist/database/Database.d.ts +56 -0
  60. package/dist/database/Database.d.ts.map +1 -0
  61. package/dist/database/Database.js +172 -0
  62. package/dist/database/Database.js.map +1 -0
  63. package/dist/database/TopologicalSorter.d.ts +25 -0
  64. package/dist/database/TopologicalSorter.d.ts.map +1 -0
  65. package/dist/database/TopologicalSorter.js +150 -0
  66. package/dist/database/TopologicalSorter.js.map +1 -0
  67. package/dist/database/index.d.ts +6 -0
  68. package/dist/database/index.d.ts.map +1 -0
  69. package/dist/database/index.js +14 -0
  70. package/dist/database/index.js.map +1 -0
  71. package/dist/discovery/ColumnStatsCache.d.ts +91 -0
  72. package/dist/discovery/ColumnStatsCache.d.ts.map +1 -0
  73. package/dist/discovery/ColumnStatsCache.js +231 -0
  74. package/dist/discovery/ColumnStatsCache.js.map +1 -0
  75. package/dist/discovery/DiscoveryEngine.d.ts +100 -0
  76. package/dist/discovery/DiscoveryEngine.d.ts.map +1 -0
  77. package/dist/discovery/DiscoveryEngine.js +726 -0
  78. package/dist/discovery/DiscoveryEngine.js.map +1 -0
  79. package/dist/discovery/DiscoveryTriggerAnalyzer.d.ts +57 -0
  80. package/dist/discovery/DiscoveryTriggerAnalyzer.d.ts.map +1 -0
  81. package/dist/discovery/DiscoveryTriggerAnalyzer.js +186 -0
  82. package/dist/discovery/DiscoveryTriggerAnalyzer.js.map +1 -0
  83. package/dist/discovery/FKDetector.d.ts +47 -0
  84. package/dist/discovery/FKDetector.d.ts.map +1 -0
  85. package/dist/discovery/FKDetector.js +317 -0
  86. package/dist/discovery/FKDetector.js.map +1 -0
  87. package/dist/discovery/LLMDiscoveryValidator.d.ts +64 -0
  88. package/dist/discovery/LLMDiscoveryValidator.d.ts.map +1 -0
  89. package/dist/discovery/LLMDiscoveryValidator.js +431 -0
  90. package/dist/discovery/LLMDiscoveryValidator.js.map +1 -0
  91. package/dist/discovery/LLMSanityChecker.d.ts +38 -0
  92. package/dist/discovery/LLMSanityChecker.d.ts.map +1 -0
  93. package/dist/discovery/LLMSanityChecker.js +156 -0
  94. package/dist/discovery/LLMSanityChecker.js.map +1 -0
  95. package/dist/discovery/PKDetector.d.ts +62 -0
  96. package/dist/discovery/PKDetector.d.ts.map +1 -0
  97. package/dist/discovery/PKDetector.js +436 -0
  98. package/dist/discovery/PKDetector.js.map +1 -0
  99. package/dist/discovery/index.d.ts +9 -0
  100. package/dist/discovery/index.d.ts.map +1 -0
  101. package/dist/discovery/index.js +25 -0
  102. package/dist/discovery/index.js.map +1 -0
  103. package/dist/drivers/BaseAutoDocDriver.d.ts +132 -0
  104. package/dist/drivers/BaseAutoDocDriver.d.ts.map +1 -0
  105. package/dist/drivers/BaseAutoDocDriver.js +121 -0
  106. package/dist/drivers/BaseAutoDocDriver.js.map +1 -0
  107. package/dist/drivers/MySQLDriver.d.ts +61 -0
  108. package/dist/drivers/MySQLDriver.d.ts.map +1 -0
  109. package/dist/drivers/MySQLDriver.js +668 -0
  110. package/dist/drivers/MySQLDriver.js.map +1 -0
  111. package/dist/drivers/PostgreSQLDriver.d.ts +65 -0
  112. package/dist/drivers/PostgreSQLDriver.d.ts.map +1 -0
  113. package/dist/drivers/PostgreSQLDriver.js +704 -0
  114. package/dist/drivers/PostgreSQLDriver.js.map +1 -0
  115. package/dist/drivers/SQLServerDriver.d.ts +61 -0
  116. package/dist/drivers/SQLServerDriver.d.ts.map +1 -0
  117. package/dist/drivers/SQLServerDriver.js +667 -0
  118. package/dist/drivers/SQLServerDriver.js.map +1 -0
  119. package/dist/generators/CSVGenerator.d.ts +35 -0
  120. package/dist/generators/CSVGenerator.d.ts.map +1 -0
  121. package/dist/generators/CSVGenerator.js +154 -0
  122. package/dist/generators/CSVGenerator.js.map +1 -0
  123. package/dist/generators/HTMLGenerator.d.ts +29 -0
  124. package/dist/generators/HTMLGenerator.d.ts.map +1 -0
  125. package/dist/generators/HTMLGenerator.js +710 -0
  126. package/dist/generators/HTMLGenerator.js.map +1 -0
  127. package/dist/generators/MarkdownGenerator.d.ts +27 -0
  128. package/dist/generators/MarkdownGenerator.d.ts.map +1 -0
  129. package/dist/generators/MarkdownGenerator.js +361 -0
  130. package/dist/generators/MarkdownGenerator.js.map +1 -0
  131. package/dist/generators/MermaidGenerator.d.ts +35 -0
  132. package/dist/generators/MermaidGenerator.d.ts.map +1 -0
  133. package/dist/generators/MermaidGenerator.js +321 -0
  134. package/dist/generators/MermaidGenerator.js.map +1 -0
  135. package/dist/generators/ReportGenerator.d.ts +22 -0
  136. package/dist/generators/ReportGenerator.d.ts.map +1 -0
  137. package/dist/generators/ReportGenerator.js +176 -0
  138. package/dist/generators/ReportGenerator.js.map +1 -0
  139. package/dist/generators/SQLGenerator.d.ts +31 -0
  140. package/dist/generators/SQLGenerator.d.ts.map +1 -0
  141. package/dist/generators/SQLGenerator.js +168 -0
  142. package/dist/generators/SQLGenerator.js.map +1 -0
  143. package/dist/generators/SampleQueryGenerator.d.ts +64 -0
  144. package/dist/generators/SampleQueryGenerator.d.ts.map +1 -0
  145. package/dist/generators/SampleQueryGenerator.js +500 -0
  146. package/dist/generators/SampleQueryGenerator.js.map +1 -0
  147. package/dist/generators/index.d.ts +10 -0
  148. package/dist/generators/index.d.ts.map +1 -0
  149. package/dist/generators/index.js +19 -0
  150. package/dist/generators/index.js.map +1 -0
  151. package/dist/index.d.ts +11 -20
  152. package/dist/index.d.ts.map +1 -1
  153. package/dist/index.js +19 -20
  154. package/dist/index.js.map +1 -1
  155. package/dist/prompts/PromptEngine.d.ts +65 -0
  156. package/dist/prompts/PromptEngine.d.ts.map +1 -0
  157. package/dist/prompts/PromptEngine.js +305 -0
  158. package/dist/prompts/PromptEngine.js.map +1 -0
  159. package/dist/prompts/PromptFileLoader.d.ts +21 -0
  160. package/dist/prompts/PromptFileLoader.d.ts.map +1 -0
  161. package/dist/prompts/PromptFileLoader.js +74 -0
  162. package/dist/prompts/PromptFileLoader.js.map +1 -0
  163. package/dist/prompts/index.d.ts +6 -0
  164. package/dist/prompts/index.d.ts.map +1 -0
  165. package/dist/prompts/index.js +11 -0
  166. package/dist/prompts/index.js.map +1 -0
  167. package/dist/state/IterationTracker.d.ts +64 -0
  168. package/dist/state/IterationTracker.d.ts.map +1 -0
  169. package/dist/state/IterationTracker.js +136 -0
  170. package/dist/state/IterationTracker.js.map +1 -0
  171. package/dist/state/StateManager.d.ts +79 -0
  172. package/dist/state/StateManager.d.ts.map +1 -0
  173. package/dist/state/StateManager.js +348 -0
  174. package/dist/state/StateManager.js.map +1 -0
  175. package/dist/state/StateValidator.d.ts +24 -0
  176. package/dist/state/StateValidator.d.ts.map +1 -0
  177. package/dist/state/StateValidator.js +147 -0
  178. package/dist/state/StateValidator.js.map +1 -0
  179. package/dist/state/index.d.ts +7 -0
  180. package/dist/state/index.d.ts.map +1 -0
  181. package/dist/state/index.js +13 -0
  182. package/dist/state/index.js.map +1 -0
  183. package/dist/types/analysis.d.ts +76 -0
  184. package/dist/types/analysis.d.ts.map +1 -0
  185. package/dist/types/analysis.js +6 -0
  186. package/dist/types/analysis.js.map +1 -0
  187. package/dist/types/config.d.ts +143 -0
  188. package/dist/types/config.d.ts.map +1 -0
  189. package/dist/types/config.js +7 -0
  190. package/dist/types/config.js.map +1 -0
  191. package/dist/types/discovery.d.ts +277 -0
  192. package/dist/types/discovery.d.ts.map +1 -0
  193. package/dist/types/discovery.js +7 -0
  194. package/dist/types/discovery.js.map +1 -0
  195. package/dist/types/driver.d.ts +148 -0
  196. package/dist/types/driver.d.ts.map +1 -0
  197. package/dist/types/driver.js +7 -0
  198. package/dist/types/driver.js.map +1 -0
  199. package/dist/types/index.d.ts +8 -0
  200. package/dist/types/index.d.ts.map +1 -0
  201. package/dist/types/index.js +24 -0
  202. package/dist/types/index.js.map +1 -0
  203. package/dist/types/prompts.d.ts +158 -0
  204. package/dist/types/prompts.d.ts.map +1 -0
  205. package/dist/types/prompts.js +6 -0
  206. package/dist/types/prompts.js.map +1 -0
  207. package/dist/types/sample-queries.d.ts +172 -0
  208. package/dist/types/sample-queries.d.ts.map +1 -0
  209. package/dist/types/sample-queries.js +7 -0
  210. package/dist/types/sample-queries.js.map +1 -0
  211. package/dist/types/state.d.ts +291 -0
  212. package/dist/types/state.d.ts.map +1 -0
  213. package/dist/types/state.js +7 -0
  214. package/dist/types/state.js.map +1 -0
  215. package/dist/utils/config-loader.d.ts +29 -0
  216. package/dist/utils/config-loader.d.ts.map +1 -0
  217. package/dist/utils/config-loader.js +163 -0
  218. package/dist/utils/config-loader.js.map +1 -0
  219. package/dist/utils/index.d.ts +5 -0
  220. package/dist/utils/index.d.ts.map +1 -0
  221. package/dist/utils/index.js +9 -0
  222. package/dist/utils/index.js.map +1 -0
  223. package/package.json +28 -3
  224. package/dist/ai/simple-ai-client.d.ts +0 -70
  225. package/dist/ai/simple-ai-client.d.ts.map +0 -1
  226. package/dist/ai/simple-ai-client.js +0 -181
  227. package/dist/ai/simple-ai-client.js.map +0 -1
  228. package/dist/analyzers/analyzer.d.ts +0 -23
  229. package/dist/analyzers/analyzer.d.ts.map +0 -1
  230. package/dist/analyzers/analyzer.js +0 -127
  231. package/dist/analyzers/analyzer.js.map +0 -1
  232. package/dist/cli-old/cli.d.ts +0 -3
  233. package/dist/cli-old/cli.d.ts.map +0 -1
  234. package/dist/cli-old/cli.js +0 -388
  235. package/dist/cli-old/cli.js.map +0 -1
  236. package/dist/commands/review.d.ts +0 -11
  237. package/dist/commands/review.d.ts.map +0 -1
  238. package/dist/commands/review.js +0 -82
  239. package/dist/commands/review.js.map +0 -1
  240. package/dist/database/connection.d.ts +0 -40
  241. package/dist/database/connection.d.ts.map +0 -1
  242. package/dist/database/connection.js +0 -136
  243. package/dist/database/connection.js.map +0 -1
  244. package/dist/database/introspection.d.ts +0 -59
  245. package/dist/database/introspection.d.ts.map +0 -1
  246. package/dist/database/introspection.js +0 -124
  247. package/dist/database/introspection.js.map +0 -1
  248. package/dist/generators/markdown-generator.d.ts +0 -8
  249. package/dist/generators/markdown-generator.d.ts.map +0 -1
  250. package/dist/generators/markdown-generator.js +0 -106
  251. package/dist/generators/markdown-generator.js.map +0 -1
  252. package/dist/generators/sql-generator.d.ts +0 -20
  253. package/dist/generators/sql-generator.d.ts.map +0 -1
  254. package/dist/generators/sql-generator.js +0 -83
  255. package/dist/generators/sql-generator.js.map +0 -1
  256. package/dist/state/state-manager.d.ts +0 -95
  257. package/dist/state/state-manager.d.ts.map +0 -1
  258. package/dist/state/state-manager.js +0 -236
  259. package/dist/state/state-manager.js.map +0 -1
  260. package/dist/types/state-file.d.ts +0 -124
  261. package/dist/types/state-file.d.ts.map +0 -1
  262. package/dist/types/state-file.js +0 -79
  263. package/dist/types/state-file.js.map +0 -1
@@ -0,0 +1,668 @@
1
+ "use strict";
2
+ /**
3
+ * MySQL implementation of the BaseAutoDocDriver
4
+ * Uses mysql2 driver for database connectivity
5
+ */
6
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
7
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
8
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
9
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
10
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
11
+ };
12
+ var __metadata = (this && this.__metadata) || function (k, v) {
13
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
14
+ };
15
+ var __importDefault = (this && this.__importDefault) || function (mod) {
16
+ return (mod && mod.__esModule) ? mod : { "default": mod };
17
+ };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.MySQLDriver = void 0;
20
+ const promise_1 = __importDefault(require("mysql2/promise"));
21
+ const global_1 = require("@memberjunction/global");
22
+ const BaseAutoDocDriver_js_1 = require("./BaseAutoDocDriver.js");
23
+ /**
24
+ * MySQL driver implementation
25
+ * Registered with MJGlobal for factory instantiation
26
+ */
27
+ let MySQLDriver = class MySQLDriver extends BaseAutoDocDriver_js_1.BaseAutoDocDriver {
28
+ constructor(config) {
29
+ super(config);
30
+ this.pool = null;
31
+ // Map generic config to MySQL specific config
32
+ this.mysqlConfig = {
33
+ host: config.host,
34
+ port: config.port || 3306,
35
+ database: config.database,
36
+ user: config.user || config.username,
37
+ password: config.password,
38
+ socketPath: config.socketPath,
39
+ connectionLimit: config.maxConnections || 10,
40
+ connectTimeout: config.connectionTimeout || 30000,
41
+ waitForConnections: true,
42
+ queueLimit: 0,
43
+ enableKeepAlive: true,
44
+ keepAliveInitialDelay: 0,
45
+ // MySQL 8+ requires explicit configuration
46
+ authPlugins: {
47
+ mysql_native_password: () => () => Buffer.from(''),
48
+ caching_sha2_password: () => () => Buffer.from('')
49
+ }
50
+ };
51
+ }
52
+ // ============================================================================
53
+ // CONNECTION MANAGEMENT
54
+ // ============================================================================
55
+ async connect() {
56
+ if (this.pool) {
57
+ return;
58
+ }
59
+ this.pool = promise_1.default.createPool(this.mysqlConfig);
60
+ }
61
+ async test() {
62
+ try {
63
+ await this.connect();
64
+ const result = await this.executeQuery(`
65
+ SELECT
66
+ 1 as test,
67
+ VERSION() as version,
68
+ DATABASE() as db
69
+ `);
70
+ if (result.success && result.data && result.data.length > 0) {
71
+ return {
72
+ success: true,
73
+ message: `Successfully connected to ${result.data[0].db} on ${this.config.host}`,
74
+ serverVersion: result.data[0].version,
75
+ databaseName: result.data[0].db
76
+ };
77
+ }
78
+ return {
79
+ success: false,
80
+ message: 'Connection established but test query failed'
81
+ };
82
+ }
83
+ catch (error) {
84
+ return {
85
+ success: false,
86
+ message: `Connection failed: ${error.message}`
87
+ };
88
+ }
89
+ }
90
+ async close() {
91
+ if (this.pool) {
92
+ await this.pool.end();
93
+ this.pool = null;
94
+ }
95
+ }
96
+ // ============================================================================
97
+ // SCHEMA INTROSPECTION
98
+ // ============================================================================
99
+ async getSchemas(schemaFilter, tableFilter) {
100
+ // Get all tables grouped by schema
101
+ const tablesQuery = this.buildTablesQuery(schemaFilter, tableFilter);
102
+ const tablesResult = await this.executeQuery(tablesQuery);
103
+ if (!tablesResult.success || !tablesResult.data) {
104
+ throw new Error(`Failed to get tables: ${tablesResult.errorMessage}`);
105
+ }
106
+ // Group tables by schema
107
+ const schemaMap = new Map();
108
+ for (const row of tablesResult.data) {
109
+ if (!schemaMap.has(row.schema_name)) {
110
+ schemaMap.set(row.schema_name, []);
111
+ }
112
+ schemaMap.get(row.schema_name).push({
113
+ tableName: row.table_name,
114
+ rowCount: row.row_count
115
+ });
116
+ }
117
+ // Build schemas with full table details
118
+ const schemas = [];
119
+ for (const [schemaName, tableSummaries] of schemaMap) {
120
+ const tables = [];
121
+ for (const { tableName, rowCount } of tableSummaries) {
122
+ const [columns, foreignKeys, primaryKeys] = await Promise.all([
123
+ this.getColumns(schemaName, tableName),
124
+ this.getForeignKeys(schemaName, tableName),
125
+ this.getPrimaryKeys(schemaName, tableName)
126
+ ]);
127
+ tables.push({
128
+ schemaName,
129
+ tableName,
130
+ rowCount,
131
+ columns,
132
+ foreignKeys,
133
+ primaryKeys
134
+ });
135
+ }
136
+ schemas.push({
137
+ name: schemaName,
138
+ tables
139
+ });
140
+ }
141
+ return schemas;
142
+ }
143
+ async getTables(schemaName, tableFilter) {
144
+ const query = this.buildTablesQuery({ include: [schemaName] }, tableFilter);
145
+ const result = await this.executeQuery(query);
146
+ if (!result.success || !result.data) {
147
+ return [];
148
+ }
149
+ const tables = [];
150
+ for (const row of result.data) {
151
+ const [columns, foreignKeys, primaryKeys] = await Promise.all([
152
+ this.getColumns(row.schema_name, row.table_name),
153
+ this.getForeignKeys(row.schema_name, row.table_name),
154
+ this.getPrimaryKeys(row.schema_name, row.table_name)
155
+ ]);
156
+ tables.push({
157
+ schemaName: row.schema_name,
158
+ tableName: row.table_name,
159
+ rowCount: row.row_count,
160
+ columns,
161
+ foreignKeys,
162
+ primaryKeys
163
+ });
164
+ }
165
+ return tables;
166
+ }
167
+ async getColumns(schemaName, tableName) {
168
+ const query = `
169
+ SELECT
170
+ c.COLUMN_NAME as column_name,
171
+ c.DATA_TYPE as data_type,
172
+ c.IS_NULLABLE as is_nullable,
173
+ c.CHARACTER_MAXIMUM_LENGTH as max_length,
174
+ c.NUMERIC_PRECISION as precision,
175
+ c.NUMERIC_SCALE as scale,
176
+ c.COLUMN_KEY as column_key,
177
+ c.COLUMN_DEFAULT as default_value,
178
+ c.EXTRA as extra,
179
+ CASE
180
+ WHEN c.COLUMN_KEY = 'PRI' THEN 1
181
+ ELSE 0
182
+ END as is_primary_key,
183
+ CASE
184
+ WHEN c.COLUMN_KEY = 'MUL' THEN 1
185
+ ELSE 0
186
+ END as is_foreign_key
187
+ FROM INFORMATION_SCHEMA.COLUMNS c
188
+ WHERE c.TABLE_SCHEMA = ?
189
+ AND c.TABLE_NAME = ?
190
+ ORDER BY c.ORDINAL_POSITION
191
+ `;
192
+ const result = await this.executeQuery(query, 3, [schemaName, tableName]);
193
+ if (!result.success || !result.data) {
194
+ return [];
195
+ }
196
+ return result.data.map(row => ({
197
+ name: row.column_name,
198
+ dataType: row.data_type,
199
+ isNullable: row.is_nullable === 'YES',
200
+ isPrimaryKey: row.is_primary_key === 1,
201
+ isForeignKey: row.is_foreign_key === 1,
202
+ defaultValue: row.default_value || undefined,
203
+ maxLength: row.max_length != null ? row.max_length : undefined,
204
+ precision: row.precision != null ? row.precision : undefined,
205
+ scale: row.scale != null ? row.scale : undefined
206
+ }));
207
+ }
208
+ async getExistingDescriptions(schemaName, tableName) {
209
+ // MySQL stores comments in INFORMATION_SCHEMA
210
+ const tableQuery = `
211
+ SELECT TABLE_COMMENT as description
212
+ FROM INFORMATION_SCHEMA.TABLES
213
+ WHERE TABLE_SCHEMA = ?
214
+ AND TABLE_NAME = ?
215
+ AND TABLE_COMMENT != ''
216
+ `;
217
+ const columnQuery = `
218
+ SELECT
219
+ COLUMN_NAME as column_name,
220
+ COLUMN_COMMENT as description
221
+ FROM INFORMATION_SCHEMA.COLUMNS
222
+ WHERE TABLE_SCHEMA = ?
223
+ AND TABLE_NAME = ?
224
+ AND COLUMN_COMMENT != ''
225
+ `;
226
+ const [tableResult, columnResult] = await Promise.all([
227
+ this.executeQuery(tableQuery, 3, [schemaName, tableName]),
228
+ this.executeQuery(columnQuery, 3, [schemaName, tableName])
229
+ ]);
230
+ const descriptions = [];
231
+ // Add table description
232
+ if (tableResult.success && tableResult.data && tableResult.data.length > 0) {
233
+ descriptions.push({
234
+ target: 'table',
235
+ targetName: '',
236
+ description: tableResult.data[0].description
237
+ });
238
+ }
239
+ // Add column descriptions
240
+ if (columnResult.success && columnResult.data) {
241
+ for (const row of columnResult.data) {
242
+ descriptions.push({
243
+ target: 'column',
244
+ targetName: row.column_name,
245
+ description: row.description
246
+ });
247
+ }
248
+ }
249
+ return descriptions;
250
+ }
251
+ // ============================================================================
252
+ // DATA SAMPLING AND STATISTICS
253
+ // ============================================================================
254
+ async getColumnStatistics(schemaName, tableName, columnName, dataType, cardinalityThreshold, sampleSize) {
255
+ const stats = {
256
+ totalRows: 0,
257
+ distinctCount: 0,
258
+ uniquenessRatio: 0,
259
+ nullCount: 0,
260
+ nullPercentage: 0,
261
+ sampleValues: []
262
+ };
263
+ // Get cardinality and null statistics
264
+ const cardinalityStats = await this.getCardinalityStats(schemaName, tableName, columnName);
265
+ Object.assign(stats, cardinalityStats);
266
+ // Get value distribution for low-cardinality columns
267
+ if (stats.distinctCount <= cardinalityThreshold && stats.distinctCount > 0) {
268
+ const distribution = await this.getValueDistribution(schemaName, tableName, columnName, 100);
269
+ stats.valueDistribution = distribution.map(d => ({
270
+ ...d,
271
+ percentage: (d.frequency / (cardinalityStats.totalCount || 1)) * 100
272
+ }));
273
+ }
274
+ // Get type-specific statistics
275
+ if (this.isNumericType(dataType)) {
276
+ const numericStats = await this.getNumericStats(schemaName, tableName, columnName);
277
+ Object.assign(stats, numericStats);
278
+ }
279
+ else if (this.isDateType(dataType)) {
280
+ const dateStats = await this.getDateStats(schemaName, tableName, columnName);
281
+ Object.assign(stats, dateStats);
282
+ }
283
+ else if (this.isStringType(dataType)) {
284
+ const stringStats = await this.getStringStats(schemaName, tableName, columnName);
285
+ Object.assign(stats, stringStats);
286
+ }
287
+ // Get sample values
288
+ stats.sampleValues = await this.getSampleValues(schemaName, tableName, columnName, sampleSize);
289
+ return stats;
290
+ }
291
+ async getDistinctCount(schemaName, tableName, columnName) {
292
+ const query = `
293
+ SELECT COUNT(DISTINCT ${this.escapeIdentifier(columnName)}) as distinct_count
294
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
295
+ `;
296
+ const result = await this.executeQuery(query);
297
+ return result.success && result.data && result.data.length > 0 ? Number(result.data[0].distinct_count) : 0;
298
+ }
299
+ async getValueDistribution(schemaName, tableName, columnName, limit) {
300
+ const query = `
301
+ SELECT
302
+ ${this.escapeIdentifier(columnName)} as value,
303
+ COUNT(*) as frequency
304
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
305
+ WHERE ${this.escapeIdentifier(columnName)} IS NOT NULL
306
+ GROUP BY ${this.escapeIdentifier(columnName)}
307
+ ORDER BY COUNT(*) DESC
308
+ LIMIT ${limit}
309
+ `;
310
+ const result = await this.executeQuery(query);
311
+ return result.success && result.data ? result.data.map(r => ({
312
+ value: r.value,
313
+ frequency: Number(r.frequency)
314
+ })) : [];
315
+ }
316
+ async getSampleValues(schemaName, tableName, columnName, sampleSize) {
317
+ // Limit sample size to max 20 to reduce JSON size
318
+ const limitedSampleSize = Math.min(sampleSize, 20);
319
+ const query = `
320
+ SELECT ${this.escapeIdentifier(columnName)} as value
321
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
322
+ WHERE ${this.escapeIdentifier(columnName)} IS NOT NULL
323
+ ORDER BY RAND()
324
+ LIMIT ${limitedSampleSize}
325
+ `;
326
+ const result = await this.executeQuery(query);
327
+ return result.success && result.data ? result.data.map(r => r.value) : [];
328
+ }
329
+ // ============================================================================
330
+ // QUERY EXECUTION
331
+ // ============================================================================
332
+ async executeQuery(query, maxRetries = 3, params) {
333
+ let lastError = null;
334
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
335
+ try {
336
+ if (!this.pool) {
337
+ await this.connect();
338
+ }
339
+ const [rows] = params
340
+ ? await this.pool.execute(query, params)
341
+ : await this.pool.query(query);
342
+ return {
343
+ success: true,
344
+ data: rows,
345
+ rowCount: Array.isArray(rows) ? rows.length : 0
346
+ };
347
+ }
348
+ catch (error) {
349
+ lastError = error;
350
+ // Check if error is transient
351
+ if (this.isTransientError(error) && attempt < maxRetries) {
352
+ await this.sleep(Math.pow(2, attempt) * 1000);
353
+ continue;
354
+ }
355
+ break;
356
+ }
357
+ }
358
+ return {
359
+ success: false,
360
+ errorMessage: lastError?.message || 'Unknown error'
361
+ };
362
+ }
363
+ // ============================================================================
364
+ // PROVIDER-SPECIFIC HELPERS
365
+ // ============================================================================
366
+ escapeIdentifier(identifier) {
367
+ return `\`${identifier}\``;
368
+ }
369
+ getLimitClause(limit) {
370
+ return `LIMIT ${limit}`;
371
+ }
372
+ // ============================================================================
373
+ // PRIVATE HELPER METHODS
374
+ // ============================================================================
375
+ buildTablesQuery(schemaFilter, tableFilter) {
376
+ let whereClause = 'WHERE t.TABLE_TYPE = \'BASE TABLE\'';
377
+ whereClause += this.buildSchemaFilterClause(schemaFilter, 't.TABLE_SCHEMA');
378
+ whereClause += this.buildTableFilterClause(tableFilter, 't.TABLE_NAME');
379
+ return `
380
+ SELECT
381
+ t.TABLE_SCHEMA as schema_name,
382
+ t.TABLE_NAME as table_name,
383
+ COALESCE(t.TABLE_ROWS, 0) as row_count
384
+ FROM INFORMATION_SCHEMA.TABLES t
385
+ ${whereClause}
386
+ ORDER BY t.TABLE_SCHEMA, t.TABLE_NAME
387
+ `;
388
+ }
389
+ async getForeignKeys(schemaName, tableName) {
390
+ const query = `
391
+ SELECT
392
+ kcu.COLUMN_NAME as column_name,
393
+ kcu.REFERENCED_TABLE_SCHEMA as referenced_schema,
394
+ kcu.REFERENCED_TABLE_NAME as referenced_table,
395
+ kcu.REFERENCED_COLUMN_NAME as referenced_column,
396
+ kcu.CONSTRAINT_NAME as constraint_name
397
+ FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
398
+ WHERE kcu.TABLE_SCHEMA = ?
399
+ AND kcu.TABLE_NAME = ?
400
+ AND kcu.REFERENCED_TABLE_NAME IS NOT NULL
401
+ ORDER BY kcu.ORDINAL_POSITION
402
+ `;
403
+ const result = await this.executeQuery(query, 3, [schemaName, tableName]);
404
+ if (!result.success || !result.data) {
405
+ return [];
406
+ }
407
+ return result.data.map(row => ({
408
+ columnName: row.column_name,
409
+ referencedSchema: row.referenced_schema,
410
+ referencedTable: row.referenced_table,
411
+ referencedColumn: row.referenced_column,
412
+ constraintName: row.constraint_name
413
+ }));
414
+ }
415
+ async getPrimaryKeys(schemaName, tableName) {
416
+ const query = `
417
+ SELECT
418
+ kcu.COLUMN_NAME as column_name,
419
+ kcu.ORDINAL_POSITION as ordinal_position,
420
+ kcu.CONSTRAINT_NAME as constraint_name
421
+ FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
422
+ INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
423
+ ON kcu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
424
+ AND kcu.TABLE_SCHEMA = tc.TABLE_SCHEMA
425
+ AND kcu.TABLE_NAME = tc.TABLE_NAME
426
+ WHERE tc.CONSTRAINT_TYPE = 'PRIMARY KEY'
427
+ AND kcu.TABLE_SCHEMA = ?
428
+ AND kcu.TABLE_NAME = ?
429
+ ORDER BY kcu.ORDINAL_POSITION
430
+ `;
431
+ const result = await this.executeQuery(query, 3, [schemaName, tableName]);
432
+ if (!result.success || !result.data) {
433
+ return [];
434
+ }
435
+ return result.data.map(row => ({
436
+ columnName: row.column_name,
437
+ ordinalPosition: Number(row.ordinal_position),
438
+ constraintName: row.constraint_name
439
+ }));
440
+ }
441
+ async getCardinalityStats(schemaName, tableName, columnName) {
442
+ const query = `
443
+ SELECT
444
+ COUNT(DISTINCT ${this.escapeIdentifier(columnName)}) as distinct_count,
445
+ COUNT(*) as total_count,
446
+ SUM(CASE WHEN ${this.escapeIdentifier(columnName)} IS NULL THEN 1 ELSE 0 END) as null_count
447
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
448
+ `;
449
+ const result = await this.executeQuery(query);
450
+ if (result.success && result.data && result.data.length > 0) {
451
+ const row = result.data[0];
452
+ const totalCount = Number(row.total_count) || 1;
453
+ const distinctCount = Number(row.distinct_count);
454
+ const nullCount = Number(row.null_count);
455
+ return {
456
+ distinctCount,
457
+ uniquenessRatio: distinctCount / totalCount,
458
+ nullCount,
459
+ nullPercentage: (nullCount / totalCount) * 100,
460
+ totalCount
461
+ };
462
+ }
463
+ return {
464
+ distinctCount: 0,
465
+ uniquenessRatio: 0,
466
+ nullCount: 0,
467
+ nullPercentage: 0,
468
+ totalCount: 0
469
+ };
470
+ }
471
+ async getNumericStats(schemaName, tableName, columnName) {
472
+ const query = `
473
+ SELECT
474
+ MIN(${this.escapeIdentifier(columnName)}) as min_value,
475
+ MAX(${this.escapeIdentifier(columnName)}) as max_value,
476
+ AVG(${this.escapeIdentifier(columnName)}) as avg_value,
477
+ STDDEV(${this.escapeIdentifier(columnName)}) as std_dev
478
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
479
+ WHERE ${this.escapeIdentifier(columnName)} IS NOT NULL
480
+ `;
481
+ const result = await this.executeQuery(query);
482
+ if (result.success && result.data && result.data.length > 0) {
483
+ const row = result.data[0];
484
+ return {
485
+ min: row.min_value,
486
+ max: row.max_value,
487
+ avg: row.avg_value != null ? Number(row.avg_value) : undefined,
488
+ stdDev: row.std_dev != null ? Number(row.std_dev) : undefined
489
+ };
490
+ }
491
+ return {};
492
+ }
493
+ async getDateStats(schemaName, tableName, columnName) {
494
+ const query = `
495
+ SELECT
496
+ MIN(${this.escapeIdentifier(columnName)}) as min_value,
497
+ MAX(${this.escapeIdentifier(columnName)}) as max_value
498
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
499
+ WHERE ${this.escapeIdentifier(columnName)} IS NOT NULL
500
+ `;
501
+ const result = await this.executeQuery(query);
502
+ if (result.success && result.data && result.data.length > 0) {
503
+ const row = result.data[0];
504
+ return {
505
+ min: row.min_value,
506
+ max: row.max_value
507
+ };
508
+ }
509
+ return {};
510
+ }
511
+ async getStringStats(schemaName, tableName, columnName) {
512
+ const query = `
513
+ SELECT
514
+ AVG(LENGTH(${this.escapeIdentifier(columnName)})) as avg_length,
515
+ MAX(LENGTH(${this.escapeIdentifier(columnName)})) as max_length,
516
+ MIN(LENGTH(${this.escapeIdentifier(columnName)})) as min_length
517
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
518
+ WHERE ${this.escapeIdentifier(columnName)} IS NOT NULL
519
+ `;
520
+ const result = await this.executeQuery(query);
521
+ if (result.success && result.data && result.data.length > 0) {
522
+ const row = result.data[0];
523
+ return {
524
+ avgLength: row.avg_length != null ? Number(row.avg_length) : undefined,
525
+ maxLength: row.max_length != null ? Number(row.max_length) : undefined,
526
+ minLength: row.min_length != null ? Number(row.min_length) : undefined
527
+ };
528
+ }
529
+ return {};
530
+ }
531
+ isTransientError(error) {
532
+ const transientMessages = [
533
+ 'connection',
534
+ 'timeout',
535
+ 'deadlock',
536
+ 'network',
537
+ 'ECONNRESET',
538
+ 'ETIMEDOUT',
539
+ 'PROTOCOL_CONNECTION_LOST'
540
+ ];
541
+ const message = error.message.toLowerCase();
542
+ return transientMessages.some(msg => message.includes(msg));
543
+ }
544
+ // ============================================================================
545
+ // RELATIONSHIP DISCOVERY METHODS
546
+ // ============================================================================
547
+ /**
548
+ * Get column information for relationship discovery
549
+ */
550
+ async getColumnInfo(schemaName, tableName, columnName) {
551
+ const query = `
552
+ SELECT
553
+ COLUMN_NAME as name,
554
+ DATA_TYPE as type,
555
+ IS_NULLABLE as nullable
556
+ FROM INFORMATION_SCHEMA.COLUMNS
557
+ WHERE TABLE_SCHEMA = ?
558
+ AND TABLE_NAME = ?
559
+ AND COLUMN_NAME = ?
560
+ `;
561
+ const result = await this.executeQuery(query, 3, [schemaName, tableName, columnName]);
562
+ if (!result.success || !result.data || result.data.length === 0) {
563
+ throw new Error(`Column ${schemaName}.${tableName}.${columnName} not found`);
564
+ }
565
+ return {
566
+ name: result.data[0].name,
567
+ type: result.data[0].type,
568
+ nullable: result.data[0].nullable === 'YES'
569
+ };
570
+ }
571
+ /**
572
+ * Test value overlap between source and target columns
573
+ */
574
+ async testValueOverlap(sourceTable, sourceColumn, targetTable, targetColumn, sampleSize) {
575
+ try {
576
+ const [sourceSchema, sourceTableName] = this.parseTableIdentifier(sourceTable);
577
+ const [targetSchema, targetTableName] = this.parseTableIdentifier(targetTable);
578
+ const query = `
579
+ WITH SourceSample AS (
580
+ SELECT DISTINCT ${this.escapeIdentifier(sourceColumn)} as value
581
+ FROM ${this.escapeIdentifier(sourceSchema)}.${this.escapeIdentifier(sourceTableName)}
582
+ WHERE ${this.escapeIdentifier(sourceColumn)} IS NOT NULL
583
+ ORDER BY RAND()
584
+ LIMIT ${sampleSize}
585
+ ),
586
+ TargetValues AS (
587
+ SELECT DISTINCT ${this.escapeIdentifier(targetColumn)} as value
588
+ FROM ${this.escapeIdentifier(targetSchema)}.${this.escapeIdentifier(targetTableName)}
589
+ WHERE ${this.escapeIdentifier(targetColumn)} IS NOT NULL
590
+ )
591
+ SELECT
592
+ COUNT(*) as total_source,
593
+ SUM(CASE WHEN tv.value IS NOT NULL THEN 1 ELSE 0 END) as matching_count
594
+ FROM SourceSample ss
595
+ LEFT JOIN TargetValues tv ON ss.value = tv.value
596
+ `;
597
+ const result = await this.executeQuery(query);
598
+ if (!result.success || !result.data || result.data.length === 0) {
599
+ return 0;
600
+ }
601
+ const row = result.data[0];
602
+ const totalSource = Number(row.total_source);
603
+ const matchingCount = Number(row.matching_count);
604
+ if (totalSource === 0) {
605
+ return 0;
606
+ }
607
+ return matchingCount / totalSource;
608
+ }
609
+ catch (error) {
610
+ return 0;
611
+ }
612
+ }
613
+ /**
614
+ * Check if combination of columns is unique
615
+ */
616
+ async checkColumnCombinationUniqueness(schemaName, tableName, columnNames, sampleSize) {
617
+ try {
618
+ if (columnNames.length === 0) {
619
+ return false;
620
+ }
621
+ const escapedColumns = columnNames.map(col => this.escapeIdentifier(col));
622
+ const columnList = escapedColumns.join(', ');
623
+ const query = `
624
+ WITH SampledData AS (
625
+ SELECT
626
+ ${columnList}
627
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
628
+ WHERE ${escapedColumns.map(col => `${col} IS NOT NULL`).join(' AND ')}
629
+ LIMIT ${sampleSize}
630
+ ),
631
+ GroupedData AS (
632
+ SELECT
633
+ ${columnList},
634
+ COUNT(*) as occurrence_count
635
+ FROM SampledData
636
+ GROUP BY ${columnList}
637
+ HAVING COUNT(*) > 1
638
+ )
639
+ SELECT COUNT(*) as duplicate_count
640
+ FROM GroupedData
641
+ `;
642
+ const result = await this.executeQuery(query);
643
+ if (!result.success || !result.data || result.data.length === 0) {
644
+ return false;
645
+ }
646
+ return Number(result.data[0].duplicate_count) === 0;
647
+ }
648
+ catch (error) {
649
+ return false;
650
+ }
651
+ }
652
+ /**
653
+ * Parse table identifier in format "schema.table"
654
+ */
655
+ parseTableIdentifier(tableIdentifier) {
656
+ const parts = tableIdentifier.split('.');
657
+ if (parts.length !== 2) {
658
+ throw new Error(`Invalid table identifier format: ${tableIdentifier}. Expected "schema.table"`);
659
+ }
660
+ return [parts[0], parts[1]];
661
+ }
662
+ };
663
+ exports.MySQLDriver = MySQLDriver;
664
+ exports.MySQLDriver = MySQLDriver = __decorate([
665
+ (0, global_1.RegisterClass)(BaseAutoDocDriver_js_1.BaseAutoDocDriver, 'MySQL'),
666
+ __metadata("design:paramtypes", [Object])
667
+ ], MySQLDriver);
668
+ //# sourceMappingURL=MySQLDriver.js.map