@memberjunction/db-auto-doc 2.116.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,667 @@
1
+ "use strict";
2
+ /**
3
+ * SQL Server implementation of the BaseAutoDocDriver
4
+ * Uses mssql driver for database connectivity
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
23
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
24
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
25
+ 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;
26
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
27
+ };
28
+ var __importStar = (this && this.__importStar) || function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ var __metadata = (this && this.__metadata) || function (k, v) {
36
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.SQLServerDriver = void 0;
40
+ const sql = __importStar(require("mssql"));
41
+ const global_1 = require("@memberjunction/global");
42
+ const BaseAutoDocDriver_js_1 = require("./BaseAutoDocDriver.js");
43
+ /**
44
+ * SQL Server driver implementation
45
+ * Registered with MJGlobal for factory instantiation
46
+ */
47
+ let SQLServerDriver = class SQLServerDriver extends BaseAutoDocDriver_js_1.BaseAutoDocDriver {
48
+ constructor(config) {
49
+ super(config);
50
+ this.pool = null;
51
+ // Map generic config to SQL Server specific config
52
+ this.sqlConfig = {
53
+ server: config.host,
54
+ port: config.port || 1433,
55
+ database: config.database,
56
+ user: config.user || config.username,
57
+ password: config.password,
58
+ options: {
59
+ encrypt: config.encrypt ?? true,
60
+ trustServerCertificate: config.trustServerCertificate ?? false
61
+ },
62
+ connectionTimeout: config.connectionTimeout ?? 30000,
63
+ requestTimeout: config.requestTimeout ?? 30000,
64
+ pool: {
65
+ max: config.maxConnections ?? 10,
66
+ min: config.minConnections ?? 0,
67
+ idleTimeoutMillis: config.idleTimeoutMillis ?? 30000
68
+ }
69
+ };
70
+ }
71
+ // ============================================================================
72
+ // CONNECTION MANAGEMENT
73
+ // ============================================================================
74
+ async connect() {
75
+ if (this.pool) {
76
+ return;
77
+ }
78
+ this.pool = await sql.connect(this.sqlConfig);
79
+ }
80
+ async test() {
81
+ try {
82
+ await this.connect();
83
+ const result = await this.executeQuery(`
84
+ SELECT
85
+ 1 as test,
86
+ @@VERSION as version,
87
+ DB_NAME() as db
88
+ `);
89
+ if (result.success && result.data && result.data.length > 0) {
90
+ return {
91
+ success: true,
92
+ message: `Successfully connected to ${result.data[0].db} on ${this.config.host}`,
93
+ serverVersion: result.data[0].version,
94
+ databaseName: result.data[0].db
95
+ };
96
+ }
97
+ return {
98
+ success: false,
99
+ message: 'Connection established but test query failed'
100
+ };
101
+ }
102
+ catch (error) {
103
+ return {
104
+ success: false,
105
+ message: `Connection failed: ${error.message}`
106
+ };
107
+ }
108
+ }
109
+ async close() {
110
+ if (this.pool) {
111
+ await this.pool.close();
112
+ this.pool = null;
113
+ }
114
+ }
115
+ // ============================================================================
116
+ // SCHEMA INTROSPECTION
117
+ // ============================================================================
118
+ async getSchemas(schemaFilter, tableFilter) {
119
+ // Get all tables grouped by schema
120
+ const tablesQuery = this.buildTablesQuery(schemaFilter, tableFilter);
121
+ const tablesResult = await this.executeQuery(tablesQuery);
122
+ if (!tablesResult.success || !tablesResult.data) {
123
+ throw new Error(`Failed to get tables: ${tablesResult.errorMessage}`);
124
+ }
125
+ // Group tables by schema
126
+ const schemaMap = new Map();
127
+ for (const row of tablesResult.data) {
128
+ if (!schemaMap.has(row.schema_name)) {
129
+ schemaMap.set(row.schema_name, []);
130
+ }
131
+ schemaMap.get(row.schema_name).push({
132
+ tableName: row.table_name,
133
+ rowCount: row.row_count
134
+ });
135
+ }
136
+ // Build schemas with full table details
137
+ const schemas = [];
138
+ for (const [schemaName, tableSummaries] of schemaMap) {
139
+ const tables = [];
140
+ for (const { tableName, rowCount } of tableSummaries) {
141
+ const [columns, foreignKeys, primaryKeys] = await Promise.all([
142
+ this.getColumns(schemaName, tableName),
143
+ this.getForeignKeys(schemaName, tableName),
144
+ this.getPrimaryKeys(schemaName, tableName)
145
+ ]);
146
+ tables.push({
147
+ schemaName,
148
+ tableName,
149
+ rowCount,
150
+ columns,
151
+ foreignKeys,
152
+ primaryKeys
153
+ });
154
+ }
155
+ schemas.push({
156
+ name: schemaName,
157
+ tables
158
+ });
159
+ }
160
+ return schemas;
161
+ }
162
+ async getTables(schemaName, tableFilter) {
163
+ const query = this.buildTablesQuery({ include: [schemaName] }, tableFilter);
164
+ const result = await this.executeQuery(query);
165
+ if (!result.success || !result.data) {
166
+ return [];
167
+ }
168
+ const tables = [];
169
+ for (const row of result.data) {
170
+ const [columns, foreignKeys, primaryKeys] = await Promise.all([
171
+ this.getColumns(row.schema_name, row.table_name),
172
+ this.getForeignKeys(row.schema_name, row.table_name),
173
+ this.getPrimaryKeys(row.schema_name, row.table_name)
174
+ ]);
175
+ tables.push({
176
+ schemaName: row.schema_name,
177
+ tableName: row.table_name,
178
+ rowCount: row.row_count,
179
+ columns,
180
+ foreignKeys,
181
+ primaryKeys
182
+ });
183
+ }
184
+ return tables;
185
+ }
186
+ async getColumns(schemaName, tableName) {
187
+ const query = `
188
+ SELECT
189
+ c.name as column_name,
190
+ t.name as data_type,
191
+ c.is_nullable,
192
+ c.max_length,
193
+ c.precision,
194
+ c.scale,
195
+ CAST(CASE WHEN pk.column_id IS NOT NULL THEN 1 ELSE 0 END AS BIT) as is_primary_key,
196
+ CAST(CASE WHEN fk.parent_column_id IS NOT NULL THEN 1 ELSE 0 END AS BIT) as is_foreign_key,
197
+ cc.definition as check_constraint,
198
+ dc.definition as default_value
199
+ FROM sys.columns c
200
+ INNER JOIN sys.types t ON c.user_type_id = t.user_type_id
201
+ INNER JOIN sys.tables tbl ON c.object_id = tbl.object_id
202
+ INNER JOIN sys.schemas s ON tbl.schema_id = s.schema_id
203
+ LEFT JOIN (
204
+ SELECT ic.object_id, ic.column_id
205
+ FROM sys.index_columns ic
206
+ INNER JOIN sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
207
+ WHERE i.is_primary_key = 1
208
+ ) pk ON c.object_id = pk.object_id AND c.column_id = pk.column_id
209
+ LEFT JOIN sys.foreign_key_columns fk ON c.object_id = fk.parent_object_id AND c.column_id = fk.parent_column_id
210
+ LEFT JOIN sys.check_constraints cc ON c.object_id = cc.parent_object_id AND cc.parent_column_id = c.column_id
211
+ LEFT JOIN sys.default_constraints dc ON c.object_id = dc.parent_object_id AND c.column_id = dc.parent_column_id
212
+ WHERE s.name = '${schemaName}' AND tbl.name = '${tableName}'
213
+ ORDER BY c.column_id
214
+ `;
215
+ const result = await this.executeQuery(query);
216
+ if (!result.success || !result.data) {
217
+ return [];
218
+ }
219
+ return result.data.map(row => ({
220
+ name: row.column_name,
221
+ dataType: row.data_type,
222
+ isNullable: row.is_nullable,
223
+ isPrimaryKey: row.is_primary_key,
224
+ isForeignKey: row.is_foreign_key,
225
+ checkConstraint: row.check_constraint || undefined,
226
+ defaultValue: row.default_value || undefined,
227
+ maxLength: row.max_length > 0 ? row.max_length : undefined,
228
+ precision: row.precision > 0 ? row.precision : undefined,
229
+ scale: row.scale > 0 ? row.scale : undefined
230
+ }));
231
+ }
232
+ async getExistingDescriptions(schemaName, tableName) {
233
+ const query = `
234
+ SELECT
235
+ ISNULL(c.name, '') as column_name,
236
+ CAST(ep.value AS NVARCHAR(MAX)) as description
237
+ FROM sys.extended_properties ep
238
+ INNER JOIN sys.tables t ON ep.major_id = t.object_id
239
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
240
+ LEFT JOIN sys.columns c ON ep.major_id = c.object_id AND ep.minor_id = c.column_id
241
+ WHERE ep.name = 'MS_Description'
242
+ AND s.name = '${schemaName}'
243
+ AND t.name = '${tableName}'
244
+ `;
245
+ const result = await this.executeQuery(query);
246
+ if (!result.success || !result.data) {
247
+ return [];
248
+ }
249
+ return result.data.map(row => ({
250
+ target: row.column_name ? 'column' : 'table',
251
+ targetName: row.column_name,
252
+ description: row.description
253
+ }));
254
+ }
255
+ // ============================================================================
256
+ // DATA SAMPLING AND STATISTICS
257
+ // ============================================================================
258
+ async getColumnStatistics(schemaName, tableName, columnName, dataType, cardinalityThreshold, sampleSize) {
259
+ const stats = {
260
+ totalRows: 0,
261
+ distinctCount: 0,
262
+ uniquenessRatio: 0,
263
+ nullCount: 0,
264
+ nullPercentage: 0,
265
+ sampleValues: []
266
+ };
267
+ // Get cardinality and null statistics
268
+ const cardinalityStats = await this.getCardinalityStats(schemaName, tableName, columnName);
269
+ Object.assign(stats, cardinalityStats);
270
+ // Get value distribution for low-cardinality columns
271
+ if (stats.distinctCount <= cardinalityThreshold && stats.distinctCount > 0) {
272
+ const distribution = await this.getValueDistribution(schemaName, tableName, columnName, 100);
273
+ stats.valueDistribution = distribution.map(d => ({
274
+ ...d,
275
+ percentage: (d.frequency / (cardinalityStats.totalCount || 1)) * 100
276
+ }));
277
+ }
278
+ // Get type-specific statistics
279
+ if (this.isNumericType(dataType)) {
280
+ const numericStats = await this.getNumericStats(schemaName, tableName, columnName);
281
+ Object.assign(stats, numericStats);
282
+ }
283
+ else if (this.isDateType(dataType)) {
284
+ const dateStats = await this.getDateStats(schemaName, tableName, columnName);
285
+ Object.assign(stats, dateStats);
286
+ }
287
+ else if (this.isStringType(dataType)) {
288
+ const stringStats = await this.getStringStats(schemaName, tableName, columnName);
289
+ Object.assign(stats, stringStats);
290
+ }
291
+ // Get sample values
292
+ stats.sampleValues = await this.getSampleValues(schemaName, tableName, columnName, sampleSize);
293
+ return stats;
294
+ }
295
+ async getDistinctCount(schemaName, tableName, columnName) {
296
+ const query = `
297
+ SELECT COUNT(DISTINCT ${this.escapeIdentifier(columnName)}) as distinct_count
298
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
299
+ `;
300
+ const result = await this.executeQuery(query);
301
+ return result.success && result.data && result.data.length > 0 ? result.data[0].distinct_count : 0;
302
+ }
303
+ async getValueDistribution(schemaName, tableName, columnName, limit) {
304
+ const query = `
305
+ SELECT TOP ${limit}
306
+ ${this.escapeIdentifier(columnName)} as value,
307
+ COUNT(*) as frequency
308
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
309
+ WHERE ${this.escapeIdentifier(columnName)} IS NOT NULL
310
+ GROUP BY ${this.escapeIdentifier(columnName)}
311
+ ORDER BY COUNT(*) DESC
312
+ `;
313
+ const result = await this.executeQuery(query);
314
+ return result.success && result.data ? result.data : [];
315
+ }
316
+ async getSampleValues(schemaName, tableName, columnName, sampleSize) {
317
+ // **IMPORTANT**: Limit sample size to max 20 to reduce JSON size
318
+ // User requested: "narrow that down to maybe 10-20 values randomly selected from each col"
319
+ const limitedSampleSize = Math.min(sampleSize, 20);
320
+ const query = `
321
+ SELECT TOP ${limitedSampleSize} ${this.escapeIdentifier(columnName)} as value
322
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
323
+ WHERE ${this.escapeIdentifier(columnName)} IS NOT NULL
324
+ ORDER BY NEWID()
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) {
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 result = await this.pool.request().query(query);
340
+ return {
341
+ success: true,
342
+ data: result.recordset,
343
+ rowCount: result.rowsAffected[0]
344
+ };
345
+ }
346
+ catch (error) {
347
+ lastError = error;
348
+ // Check if error is transient
349
+ if (this.isTransientError(error) && attempt < maxRetries) {
350
+ await this.sleep(Math.pow(2, attempt) * 1000);
351
+ continue;
352
+ }
353
+ break;
354
+ }
355
+ }
356
+ return {
357
+ success: false,
358
+ errorMessage: lastError?.message || 'Unknown error'
359
+ };
360
+ }
361
+ // ============================================================================
362
+ // PROVIDER-SPECIFIC HELPERS
363
+ // ============================================================================
364
+ escapeIdentifier(identifier) {
365
+ return `[${identifier}]`;
366
+ }
367
+ getLimitClause(limit) {
368
+ return `TOP ${limit}`;
369
+ }
370
+ // ============================================================================
371
+ // PRIVATE HELPER METHODS
372
+ // ============================================================================
373
+ buildTablesQuery(schemaFilter, tableFilter) {
374
+ let whereClause = 'WHERE t.is_ms_shipped = 0';
375
+ whereClause += this.buildSchemaFilterClause(schemaFilter, 's.name');
376
+ whereClause += this.buildTableFilterClause(tableFilter, 't.name');
377
+ return `
378
+ SELECT
379
+ s.name as schema_name,
380
+ t.name as table_name,
381
+ ISNULL(p.rows, 0) as row_count
382
+ FROM sys.tables t
383
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
384
+ LEFT JOIN sys.partitions p ON t.object_id = p.object_id AND p.index_id IN (0, 1)
385
+ ${whereClause}
386
+ ORDER BY s.name, t.name
387
+ `;
388
+ }
389
+ async getForeignKeys(schemaName, tableName) {
390
+ const query = `
391
+ SELECT
392
+ c.name as column_name,
393
+ rs.name as referenced_schema,
394
+ rt.name as referenced_table,
395
+ rc.name as referenced_column,
396
+ fkc.name as constraint_name
397
+ FROM sys.foreign_key_columns fk
398
+ INNER JOIN sys.foreign_keys fkc ON fk.constraint_object_id = fkc.object_id
399
+ INNER JOIN sys.tables t ON fk.parent_object_id = t.object_id
400
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
401
+ INNER JOIN sys.columns c ON fk.parent_object_id = c.object_id AND fk.parent_column_id = c.column_id
402
+ INNER JOIN sys.tables rt ON fk.referenced_object_id = rt.object_id
403
+ INNER JOIN sys.schemas rs ON rt.schema_id = rs.schema_id
404
+ INNER JOIN sys.columns rc ON fk.referenced_object_id = rc.object_id AND fk.referenced_column_id = rc.column_id
405
+ WHERE s.name = '${schemaName}' AND t.name = '${tableName}'
406
+ `;
407
+ const result = await this.executeQuery(query);
408
+ if (!result.success || !result.data) {
409
+ return [];
410
+ }
411
+ return result.data.map(row => ({
412
+ columnName: row.column_name,
413
+ referencedSchema: row.referenced_schema,
414
+ referencedTable: row.referenced_table,
415
+ referencedColumn: row.referenced_column,
416
+ constraintName: row.constraint_name
417
+ }));
418
+ }
419
+ async getPrimaryKeys(schemaName, tableName) {
420
+ const query = `
421
+ SELECT
422
+ c.name as column_name,
423
+ ic.key_ordinal as ordinal_position,
424
+ i.name as constraint_name
425
+ FROM sys.index_columns ic
426
+ INNER JOIN sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
427
+ INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
428
+ INNER JOIN sys.tables t ON i.object_id = t.object_id
429
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
430
+ WHERE i.is_primary_key = 1
431
+ AND s.name = '${schemaName}'
432
+ AND t.name = '${tableName}'
433
+ ORDER BY ic.key_ordinal
434
+ `;
435
+ const result = await this.executeQuery(query);
436
+ if (!result.success || !result.data) {
437
+ return [];
438
+ }
439
+ return result.data.map(row => ({
440
+ columnName: row.column_name,
441
+ ordinalPosition: row.ordinal_position,
442
+ constraintName: row.constraint_name
443
+ }));
444
+ }
445
+ async getCardinalityStats(schemaName, tableName, columnName) {
446
+ const query = `
447
+ SELECT
448
+ COUNT(DISTINCT ${this.escapeIdentifier(columnName)}) as distinct_count,
449
+ COUNT(*) as total_count,
450
+ SUM(CASE WHEN ${this.escapeIdentifier(columnName)} IS NULL THEN 1 ELSE 0 END) as null_count
451
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
452
+ `;
453
+ const result = await this.executeQuery(query);
454
+ if (result.success && result.data && result.data.length > 0) {
455
+ const row = result.data[0];
456
+ const totalCount = row.total_count || 1;
457
+ return {
458
+ distinctCount: row.distinct_count,
459
+ uniquenessRatio: row.distinct_count / totalCount,
460
+ nullCount: row.null_count,
461
+ nullPercentage: (row.null_count / totalCount) * 100,
462
+ totalCount
463
+ };
464
+ }
465
+ return {
466
+ distinctCount: 0,
467
+ uniquenessRatio: 0,
468
+ nullCount: 0,
469
+ nullPercentage: 0,
470
+ totalCount: 0
471
+ };
472
+ }
473
+ async getNumericStats(schemaName, tableName, columnName) {
474
+ const query = `
475
+ SELECT
476
+ MIN(${this.escapeIdentifier(columnName)}) as min_value,
477
+ MAX(${this.escapeIdentifier(columnName)}) as max_value,
478
+ AVG(CAST(${this.escapeIdentifier(columnName)} AS FLOAT)) as avg_value,
479
+ STDEV(${this.escapeIdentifier(columnName)}) as std_dev
480
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
481
+ WHERE ${this.escapeIdentifier(columnName)} IS NOT NULL
482
+ `;
483
+ const result = await this.executeQuery(query);
484
+ if (result.success && result.data && result.data.length > 0) {
485
+ const row = result.data[0];
486
+ return {
487
+ min: row.min_value,
488
+ max: row.max_value,
489
+ avg: row.avg_value,
490
+ stdDev: row.std_dev
491
+ };
492
+ }
493
+ return {};
494
+ }
495
+ async getDateStats(schemaName, tableName, columnName) {
496
+ const query = `
497
+ SELECT
498
+ MIN(${this.escapeIdentifier(columnName)}) as min_value,
499
+ MAX(${this.escapeIdentifier(columnName)}) as max_value
500
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
501
+ WHERE ${this.escapeIdentifier(columnName)} IS NOT NULL
502
+ `;
503
+ const result = await this.executeQuery(query);
504
+ if (result.success && result.data && result.data.length > 0) {
505
+ const row = result.data[0];
506
+ return {
507
+ min: row.min_value,
508
+ max: row.max_value
509
+ };
510
+ }
511
+ return {};
512
+ }
513
+ async getStringStats(schemaName, tableName, columnName) {
514
+ const query = `
515
+ SELECT
516
+ AVG(LEN(${this.escapeIdentifier(columnName)})) as avg_length,
517
+ MAX(LEN(${this.escapeIdentifier(columnName)})) as max_length,
518
+ MIN(LEN(${this.escapeIdentifier(columnName)})) as min_length
519
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
520
+ WHERE ${this.escapeIdentifier(columnName)} IS NOT NULL
521
+ `;
522
+ const result = await this.executeQuery(query);
523
+ if (result.success && result.data && result.data.length > 0) {
524
+ const row = result.data[0];
525
+ return {
526
+ avgLength: row.avg_length,
527
+ maxLength: row.max_length,
528
+ minLength: row.min_length
529
+ };
530
+ }
531
+ return {};
532
+ }
533
+ isTransientError(error) {
534
+ const transientMessages = [
535
+ 'connection',
536
+ 'timeout',
537
+ 'deadlock',
538
+ 'network',
539
+ 'transport'
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
+ c.name,
554
+ t.name as type,
555
+ c.is_nullable as nullable
556
+ FROM sys.columns c
557
+ INNER JOIN sys.types t ON c.user_type_id = t.user_type_id
558
+ INNER JOIN sys.tables tbl ON c.object_id = tbl.object_id
559
+ INNER JOIN sys.schemas s ON tbl.schema_id = s.schema_id
560
+ WHERE s.name = '${schemaName}'
561
+ AND tbl.name = '${tableName}'
562
+ AND c.name = '${columnName}'
563
+ `;
564
+ const result = await this.executeQuery(query);
565
+ if (!result.success || !result.data || result.data.length === 0) {
566
+ throw new Error(`Column ${schemaName}.${tableName}.${columnName} not found`);
567
+ }
568
+ return {
569
+ name: result.data[0].name,
570
+ type: result.data[0].type,
571
+ nullable: result.data[0].nullable
572
+ };
573
+ }
574
+ /**
575
+ * Test value overlap between source and target columns
576
+ */
577
+ async testValueOverlap(sourceTable, sourceColumn, targetTable, targetColumn, sampleSize) {
578
+ try {
579
+ const [sourceSchema, sourceTableName] = this.parseTableIdentifier(sourceTable);
580
+ const [targetSchema, targetTableName] = this.parseTableIdentifier(targetTable);
581
+ const query = `
582
+ WITH SourceSample AS (
583
+ SELECT DISTINCT TOP ${sampleSize}
584
+ ${this.escapeIdentifier(sourceColumn)} as value
585
+ FROM ${this.escapeIdentifier(sourceSchema)}.${this.escapeIdentifier(sourceTableName)}
586
+ WHERE ${this.escapeIdentifier(sourceColumn)} IS NOT NULL
587
+ ),
588
+ TargetValues AS (
589
+ SELECT DISTINCT ${this.escapeIdentifier(targetColumn)} as value
590
+ FROM ${this.escapeIdentifier(targetSchema)}.${this.escapeIdentifier(targetTableName)}
591
+ WHERE ${this.escapeIdentifier(targetColumn)} IS NOT NULL
592
+ )
593
+ SELECT
594
+ COUNT(*) as total_source,
595
+ SUM(CASE WHEN tv.value IS NOT NULL THEN 1 ELSE 0 END) as matching_count
596
+ FROM SourceSample ss
597
+ LEFT JOIN TargetValues tv ON ss.value = tv.value
598
+ `;
599
+ const result = await this.executeQuery(query);
600
+ if (!result.success || !result.data || result.data.length === 0) {
601
+ return 0;
602
+ }
603
+ const row = result.data[0];
604
+ if (row.total_source === 0) {
605
+ return 0;
606
+ }
607
+ return row.matching_count / row.total_source;
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 TOP ${sampleSize}
626
+ ${columnList}
627
+ FROM ${this.escapeIdentifier(schemaName)}.${this.escapeIdentifier(tableName)}
628
+ WHERE ${escapedColumns.map(col => `${col} IS NOT NULL`).join(' AND ')}
629
+ ),
630
+ GroupedData AS (
631
+ SELECT
632
+ ${columnList},
633
+ COUNT(*) as occurrence_count
634
+ FROM SampledData
635
+ GROUP BY ${columnList}
636
+ HAVING COUNT(*) > 1
637
+ )
638
+ SELECT COUNT(*) as duplicate_count
639
+ FROM GroupedData
640
+ `;
641
+ const result = await this.executeQuery(query);
642
+ if (!result.success || !result.data || result.data.length === 0) {
643
+ return false;
644
+ }
645
+ return result.data[0].duplicate_count === 0;
646
+ }
647
+ catch (error) {
648
+ return false;
649
+ }
650
+ }
651
+ /**
652
+ * Parse table identifier in format "schema.table"
653
+ */
654
+ parseTableIdentifier(tableIdentifier) {
655
+ const parts = tableIdentifier.split('.');
656
+ if (parts.length !== 2) {
657
+ throw new Error(`Invalid table identifier format: ${tableIdentifier}. Expected "schema.table"`);
658
+ }
659
+ return [parts[0], parts[1]];
660
+ }
661
+ };
662
+ exports.SQLServerDriver = SQLServerDriver;
663
+ exports.SQLServerDriver = SQLServerDriver = __decorate([
664
+ (0, global_1.RegisterClass)(BaseAutoDocDriver_js_1.BaseAutoDocDriver, 'SQLServer'),
665
+ __metadata("design:paramtypes", [Object])
666
+ ], SQLServerDriver);
667
+ //# sourceMappingURL=SQLServerDriver.js.map