datapeek 0.1.10 → 0.1.12

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 (92) hide show
  1. package/dist/cli/chunk-2I4MNNVK.js +628 -0
  2. package/dist/cli/chunk-4GDQ7VJZ.js +662 -0
  3. package/dist/cli/chunk-4MIQHH6K.js +47 -0
  4. package/dist/cli/chunk-6K3WSEIM.js +375 -0
  5. package/dist/cli/chunk-6PMCDR7J.js +628 -0
  6. package/dist/cli/chunk-B7K46745.js +605 -0
  7. package/dist/cli/chunk-CK2O76SG.js +713 -0
  8. package/dist/cli/chunk-FXOMCTFV.js +696 -0
  9. package/dist/cli/chunk-G4ID5SFT.js +628 -0
  10. package/dist/cli/chunk-GCVFEHSZ.js +708 -0
  11. package/dist/cli/chunk-LGE2JQ3S.js +628 -0
  12. package/dist/cli/chunk-NDLKLB5A.js +710 -0
  13. package/dist/cli/chunk-PG6I26XT.js +614 -0
  14. package/dist/cli/chunk-RK2Q2AX5.js +582 -0
  15. package/dist/cli/chunk-S5LRCCK6.js +582 -0
  16. package/dist/cli/chunk-UBFQXPPF.js +701 -0
  17. package/dist/cli/chunk-X2DQBOP6.js +712 -0
  18. package/dist/cli/chunk-XRMPVZIS.js +709 -0
  19. package/dist/cli/chunk-Z5G3UEXN.js +711 -0
  20. package/dist/cli/chunk-ZMP7S3G6.js +696 -0
  21. package/dist/cli/db-32TDDTFP.js +28 -0
  22. package/dist/cli/db-47O74DN5.js +34 -0
  23. package/dist/cli/db-4U22OWGB.js +29 -0
  24. package/dist/cli/db-CL72XDNO.js +34 -0
  25. package/dist/cli/db-CZCZOEID.js +28 -0
  26. package/dist/cli/db-IX3DXZ2C.js +34 -0
  27. package/dist/cli/db-LJCRTZTY.js +34 -0
  28. package/dist/cli/db-LNX4UMRF.js +28 -0
  29. package/dist/cli/db-NESFXDWL.js +28 -0
  30. package/dist/cli/db-OIJ2PJK6.js +34 -0
  31. package/dist/cli/db-OPAF6ZO3.js +28 -0
  32. package/dist/cli/db-PQURQHSK.js +28 -0
  33. package/dist/cli/db-QN5MTDYB.js +28 -0
  34. package/dist/cli/db-RBMUR3OK.js +34 -0
  35. package/dist/cli/db-REMUYLPP.js +34 -0
  36. package/dist/cli/db-RTHQ4ZAU.js +28 -0
  37. package/dist/cli/db-SHFLGGWD.js +28 -0
  38. package/dist/cli/db-ULMGZXQ5.js +34 -0
  39. package/dist/cli/db-YOGJ4LXE.js +28 -0
  40. package/dist/cli/dev.js +717 -291
  41. package/dist/cli/index.js +720 -293
  42. package/dist/cli/queryCancellation-4CMKYTFU.js +46 -0
  43. package/dist/cli/queryCancellation-E5O4FBUY.js +14 -0
  44. package/dist/client/assets/index-BXssAVuE.css +1 -0
  45. package/dist/client/assets/index-DgwSpfvt.js +378 -0
  46. package/dist/client/index.html +2 -2
  47. package/dist/server/chunk-26GSUAI4.js +710 -0
  48. package/dist/server/chunk-36OOXHKI.js +659 -0
  49. package/dist/server/chunk-3DAIYH42.js +44 -0
  50. package/dist/server/chunk-4ELMZYWA.js +611 -0
  51. package/dist/server/chunk-5ESS5YBD.js +707 -0
  52. package/dist/server/chunk-7HIBWXBL.js +625 -0
  53. package/dist/server/chunk-BH22Q2FV.js +705 -0
  54. package/dist/server/chunk-CFU2CLKS.js +693 -0
  55. package/dist/server/chunk-CXA3HXTK.js +698 -0
  56. package/dist/server/chunk-DAUUXYQF.js +706 -0
  57. package/dist/server/chunk-FMSIEQ2T.js +579 -0
  58. package/dist/server/chunk-G6A463RM.js +625 -0
  59. package/dist/server/chunk-H6DUOXOK.js +625 -0
  60. package/dist/server/chunk-JCRZ6H7P.js +579 -0
  61. package/dist/server/chunk-L6LL3NE7.js +602 -0
  62. package/dist/server/chunk-TH6TUILG.js +709 -0
  63. package/dist/server/chunk-UJ2LRK25.js +373 -0
  64. package/dist/server/chunk-YI67PW64.js +625 -0
  65. package/dist/server/chunk-ZDZ2C5ZQ.js +693 -0
  66. package/dist/server/chunk-ZJOVVCPT.js +708 -0
  67. package/dist/server/db-22DQ6YG7.js +32 -0
  68. package/dist/server/db-3CBO6RHU.js +26 -0
  69. package/dist/server/db-3XN2KWYT.js +32 -0
  70. package/dist/server/db-3Y6K4EDP.js +26 -0
  71. package/dist/server/db-57HXNWPD.js +26 -0
  72. package/dist/server/db-5GCTDKYH.js +27 -0
  73. package/dist/server/db-5VQOTJ52.js +26 -0
  74. package/dist/server/db-B5L7VQ7E.js +32 -0
  75. package/dist/server/db-CJPCGHL3.js +32 -0
  76. package/dist/server/db-DAQ4BVCU.js +32 -0
  77. package/dist/server/db-EEA6EWHL.js +26 -0
  78. package/dist/server/db-KR7Z5M5V.js +32 -0
  79. package/dist/server/db-LMSBISDM.js +26 -0
  80. package/dist/server/db-LSOQE7N7.js +32 -0
  81. package/dist/server/db-NHBP6YLH.js +26 -0
  82. package/dist/server/db-OWVJVBBD.js +26 -0
  83. package/dist/server/db-TTVXKX7P.js +26 -0
  84. package/dist/server/db-YJ753EQV.js +26 -0
  85. package/dist/server/db-ZV6GZHFU.js +32 -0
  86. package/dist/server/dev.js +717 -291
  87. package/dist/server/index.js +717 -291
  88. package/dist/server/queryCancellation-M56DISJX.js +43 -0
  89. package/dist/server/queryCancellation-T2HSNMIV.js +12 -0
  90. package/package.json +3 -1
  91. package/dist/client/assets/index-BhZ7NrhL.css +0 -1
  92. package/dist/client/assets/index-D-mash8_.js +0 -370
package/dist/cli/dev.js CHANGED
@@ -6,8 +6,15 @@ import {
6
6
  executeQuery,
7
7
  executeQueryMultiple,
8
8
  getConnection,
9
+ getDbType,
10
+ getDialect,
11
+ setDbType,
9
12
  testConnection
10
- } from "./chunk-3XB4P3G3.js";
13
+ } from "./chunk-CK2O76SG.js";
14
+ import {
15
+ cancelQuery,
16
+ generateQueryId
17
+ } from "./chunk-4MIQHH6K.js";
11
18
 
12
19
  // src/server/index.ts
13
20
  import express from "express";
@@ -27,9 +34,12 @@ connectionRoutes.post("/test", async (req, res) => {
27
34
  message: "Connection test timeout"
28
35
  });
29
36
  }
30
- }, 1e4);
37
+ }, 18e5);
31
38
  try {
32
39
  const config = req.body;
40
+ if (config.dbType) {
41
+ setDbType(config.dbType);
42
+ }
33
43
  await testConnection(config);
34
44
  clearTimeout(timeout);
35
45
  if (!res.headersSent) {
@@ -57,9 +67,12 @@ connectionRoutes.post("/", async (req, res) => {
57
67
  message: "Connection timeout"
58
68
  });
59
69
  }
60
- }, 15e3);
70
+ }, 18e5);
61
71
  try {
62
72
  const config = req.body;
73
+ if (config.dbType) {
74
+ setDbType(config.dbType);
75
+ }
63
76
  await connect(config);
64
77
  clearTimeout(timeout);
65
78
  if (!res.headersSent) {
@@ -88,19 +101,28 @@ connectionRoutes.delete("/", async (req, res) => {
88
101
  });
89
102
  connectionRoutes.get("/status", async (req, res) => {
90
103
  try {
91
- const { getConnection: getConnection2, executeQuery: executeQuery3 } = await import("./mssql-AYS72PRQ.js");
92
- const pool = getConnection2();
93
- if (pool && pool.connected) {
94
- try {
95
- const result = await executeQuery3("SELECT DB_NAME() as databaseName");
96
- const databaseName = result[0]?.databaseName || null;
97
- res.json({ connected: true, databaseName });
98
- } catch (error) {
99
- const errorMessage = error.message || "";
100
- if (errorMessage.includes("Login failed") || errorMessage.includes("authentication")) {
101
- const { disconnect: disconnect2 } = await import("./mssql-AYS72PRQ.js");
102
- await disconnect2();
104
+ const pool = getConnection();
105
+ if (pool) {
106
+ let isConnected = false;
107
+ if ("connected" in pool) {
108
+ isConnected = pool.connected === true;
109
+ } else {
110
+ isConnected = !pool.ended;
111
+ }
112
+ if (isConnected) {
113
+ try {
114
+ const dialect = getDialect();
115
+ const result = await executeQuery(dialect.currentDbQuery());
116
+ const databaseName = result[0]?.databaseName || null;
117
+ res.json({ connected: true, databaseName });
118
+ } catch (error) {
119
+ const errorMessage = error.message || "";
120
+ if (errorMessage.includes("Login failed") || errorMessage.includes("authentication") || errorMessage.includes("password authentication")) {
121
+ await disconnect();
122
+ }
123
+ res.json({ connected: false });
103
124
  }
125
+ } else {
104
126
  res.json({ connected: false });
105
127
  }
106
128
  } else {
@@ -113,28 +135,34 @@ connectionRoutes.get("/status", async (req, res) => {
113
135
 
114
136
  // src/server/routes/tables.ts
115
137
  import { Router as Router2 } from "express";
116
- import sql from "mssql";
117
138
  var tableRoutes = Router2();
118
139
  tableRoutes.get("/", async (req, res) => {
119
140
  try {
120
141
  const pool = getConnection();
121
- if (!pool || !pool.connected) {
142
+ if (!pool) {
143
+ return res.status(400).json({ error: "Not connected to database" });
144
+ }
145
+ const isConnected = "connected" in pool ? pool.connected === true : !pool.ended;
146
+ if (!isConnected) {
122
147
  return res.status(400).json({ error: "Not connected to database" });
123
148
  }
149
+ const dialect = getDialect();
150
+ const dbType = getDbType();
151
+ const schemaFilter = dbType === "postgres" ? `AND table_schema NOT IN ('pg_catalog', 'information_schema')` : "";
124
152
  const query = `
125
153
  SELECT
126
- TABLE_SCHEMA as schemaName,
127
- TABLE_NAME as tableName
128
- FROM INFORMATION_SCHEMA.TABLES
129
- WHERE TABLE_TYPE = 'BASE TABLE'
130
- ORDER BY TABLE_SCHEMA, TABLE_NAME
154
+ table_schema as "schemaName",
155
+ table_name as "tableName"
156
+ FROM information_schema.tables
157
+ WHERE table_type = 'BASE TABLE'${schemaFilter}
158
+ ORDER BY table_schema, table_name
131
159
  `;
132
160
  const result = await executeQuery(query);
133
161
  res.json(result);
134
162
  } catch (error) {
135
163
  const errorMessage = error.message || "";
136
- if (errorMessage.includes("Login failed") || errorMessage.includes("authentication")) {
137
- const { disconnect: disconnect2 } = await import("./mssql-AYS72PRQ.js");
164
+ if (errorMessage.includes("Login failed") || errorMessage.includes("authentication") || errorMessage.includes("password authentication")) {
165
+ const { disconnect: disconnect2 } = await import("./db-OIJ2PJK6.js");
138
166
  await disconnect2();
139
167
  }
140
168
  res.status(500).json({ error: error.message || "Failed to fetch tables" });
@@ -144,64 +172,69 @@ tableRoutes.get("/:schema/:table", async (req, res) => {
144
172
  try {
145
173
  const { schema, table } = req.params;
146
174
  const pool = getConnection();
147
- if (!pool || !pool.connected) {
175
+ if (!pool) {
176
+ return res.status(400).json({ error: "Not connected to database" });
177
+ }
178
+ const isConnected = "connected" in pool ? pool.connected === true : !pool.ended;
179
+ if (!isConnected) {
148
180
  return res.status(400).json({ error: "Not connected to database" });
149
181
  }
182
+ const dialect = getDialect();
150
183
  const query = `
151
184
  SELECT
152
- c.COLUMN_NAME as columnName,
153
- c.DATA_TYPE as dataType,
154
- c.CHARACTER_MAXIMUM_LENGTH as maxLength,
155
- c.IS_NULLABLE as isNullable,
156
- c.COLUMN_DEFAULT as defaultValue,
157
- CASE WHEN pk.COLUMN_NAME IS NOT NULL THEN 1 ELSE 0 END as isPrimaryKey,
158
- fk.REFERENCED_TABLE_SCHEMA as referencedSchema,
159
- fk.REFERENCED_TABLE_NAME as referencedTable,
160
- fk.REFERENCED_COLUMN_NAME as referencedColumn
161
- FROM INFORMATION_SCHEMA.COLUMNS c
185
+ c.column_name as "columnName",
186
+ c.data_type as "dataType",
187
+ c.character_maximum_length as "maxLength",
188
+ c.is_nullable as "isNullable",
189
+ c.column_default as "defaultValue",
190
+ CASE WHEN pk.column_name IS NOT NULL THEN 1 ELSE 0 END as "isPrimaryKey",
191
+ fk.referenced_table_schema as "referencedSchema",
192
+ fk.referenced_table_name as "referencedTable",
193
+ fk.referenced_column_name as "referencedColumn"
194
+ FROM information_schema.columns c
162
195
  LEFT JOIN (
163
- SELECT ku.TABLE_SCHEMA, ku.TABLE_NAME, ku.COLUMN_NAME
164
- FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
165
- INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE ku
166
- ON tc.CONSTRAINT_TYPE = 'PRIMARY KEY'
167
- AND tc.CONSTRAINT_NAME = ku.CONSTRAINT_NAME
168
- ) pk ON c.TABLE_SCHEMA = pk.TABLE_SCHEMA
169
- AND c.TABLE_NAME = pk.TABLE_NAME
170
- AND c.COLUMN_NAME = pk.COLUMN_NAME
196
+ SELECT ku.table_schema, ku.table_name, ku.column_name
197
+ FROM information_schema.table_constraints tc
198
+ INNER JOIN information_schema.key_column_usage ku
199
+ ON tc.constraint_type = 'PRIMARY KEY'
200
+ AND tc.constraint_name = ku.constraint_name
201
+ ) pk ON c.table_schema = pk.table_schema
202
+ AND c.table_name = pk.table_name
203
+ AND c.column_name = pk.column_name
171
204
  LEFT JOIN (
172
205
  SELECT
173
- kcu1.TABLE_SCHEMA,
174
- kcu1.TABLE_NAME,
175
- kcu1.COLUMN_NAME,
176
- kcu2.TABLE_SCHEMA as REFERENCED_TABLE_SCHEMA,
177
- kcu2.TABLE_NAME as REFERENCED_TABLE_NAME,
178
- kcu2.COLUMN_NAME as REFERENCED_COLUMN_NAME
179
- FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
180
- INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu1
181
- ON rc.CONSTRAINT_CATALOG = kcu1.CONSTRAINT_CATALOG
182
- AND rc.CONSTRAINT_SCHEMA = kcu1.CONSTRAINT_SCHEMA
183
- AND rc.CONSTRAINT_NAME = kcu1.CONSTRAINT_NAME
184
- INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu2
185
- ON rc.UNIQUE_CONSTRAINT_CATALOG = kcu2.CONSTRAINT_CATALOG
186
- AND rc.UNIQUE_CONSTRAINT_SCHEMA = kcu2.CONSTRAINT_SCHEMA
187
- AND rc.UNIQUE_CONSTRAINT_NAME = kcu2.CONSTRAINT_NAME
188
- AND kcu1.ORDINAL_POSITION = kcu2.ORDINAL_POSITION
189
- ) fk ON c.TABLE_SCHEMA = fk.TABLE_SCHEMA
190
- AND c.TABLE_NAME = fk.TABLE_NAME
191
- AND c.COLUMN_NAME = fk.COLUMN_NAME
192
- WHERE c.TABLE_SCHEMA = @schema
193
- AND c.TABLE_NAME = @table
194
- ORDER BY c.ORDINAL_POSITION
206
+ kcu1.table_schema,
207
+ kcu1.table_name,
208
+ kcu1.column_name,
209
+ kcu2.table_schema as referenced_table_schema,
210
+ kcu2.table_name as referenced_table_name,
211
+ kcu2.column_name as referenced_column_name
212
+ FROM information_schema.referential_constraints rc
213
+ INNER JOIN information_schema.key_column_usage kcu1
214
+ ON rc.constraint_catalog = kcu1.constraint_catalog
215
+ AND rc.constraint_schema = kcu1.constraint_schema
216
+ AND rc.constraint_name = kcu1.constraint_name
217
+ INNER JOIN information_schema.key_column_usage kcu2
218
+ ON rc.unique_constraint_catalog = kcu2.constraint_catalog
219
+ AND rc.unique_constraint_schema = kcu2.constraint_schema
220
+ AND rc.unique_constraint_name = kcu2.constraint_name
221
+ AND kcu1.ordinal_position = kcu2.ordinal_position
222
+ ) fk ON c.table_schema = fk.table_schema
223
+ AND c.table_name = fk.table_name
224
+ AND c.column_name = fk.column_name
225
+ WHERE c.table_schema = @schema
226
+ AND c.table_name = @table
227
+ ORDER BY c.ordinal_position
195
228
  `;
196
229
  const result = await executeQuery(query, [
197
- { name: "schema", value: schema, type: sql.NVarChar },
198
- { name: "table", value: table, type: sql.NVarChar }
230
+ { name: "schema", value: schema },
231
+ { name: "table", value: table }
199
232
  ]);
200
233
  res.json(result);
201
234
  } catch (error) {
202
235
  const errorMessage = error.message || "";
203
- if (errorMessage.includes("Login failed") || errorMessage.includes("authentication")) {
204
- const { disconnect: disconnect2 } = await import("./mssql-AYS72PRQ.js");
236
+ if (errorMessage.includes("Login failed") || errorMessage.includes("authentication") || errorMessage.includes("password authentication")) {
237
+ const { disconnect: disconnect2 } = await import("./db-OIJ2PJK6.js");
205
238
  await disconnect2();
206
239
  }
207
240
  res.status(500).json({ error: error.message || "Failed to fetch table structure" });
@@ -216,62 +249,230 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
216
249
  const sortDirection = req.query.sortDirection || "asc";
217
250
  const fkDisplayMode = req.query.fkDisplayMode || "key-only";
218
251
  const offset = (page - 1) * pageSize;
219
- const filters = {};
252
+ const parsedFilters = [];
253
+ const seenFilterColumns = /* @__PURE__ */ new Set();
254
+ const parseFilterEntry = (columnName, rawValue) => {
255
+ if (!columnName || rawValue === null || rawValue === void 0 || seenFilterColumns.has(columnName)) {
256
+ return;
257
+ }
258
+ const filterValue = String(rawValue).trim();
259
+ if (!filterValue) return;
260
+ try {
261
+ const parsed = JSON.parse(filterValue);
262
+ if (parsed && typeof parsed === "object" && parsed.operator) {
263
+ parsedFilters.push({
264
+ column: columnName,
265
+ operator: parsed.operator,
266
+ value: parsed.value,
267
+ dataType: parsed.dataType
268
+ });
269
+ } else {
270
+ parsedFilters.push({
271
+ column: columnName,
272
+ operator: "contains",
273
+ value: filterValue
274
+ });
275
+ }
276
+ } catch {
277
+ parsedFilters.push({
278
+ column: columnName,
279
+ operator: "contains",
280
+ value: filterValue
281
+ });
282
+ }
283
+ seenFilterColumns.add(columnName);
284
+ };
220
285
  Object.keys(req.query).forEach((key) => {
221
286
  const match = key.match(/^filter\[(.+)\]$/);
222
- if (match && req.query[key] && String(req.query[key]).trim()) {
223
- filters[match[1]] = String(req.query[key]).trim();
287
+ if (match) {
288
+ const columnName = match[1];
289
+ parseFilterEntry(columnName, req.query[key]);
224
290
  }
225
291
  });
226
- console.log("Received filters from query:", filters);
227
- console.log("All query params:", req.query);
292
+ const nestedFilters = req.query.filter;
293
+ if (nestedFilters && typeof nestedFilters === "object" && !Array.isArray(nestedFilters)) {
294
+ Object.entries(nestedFilters).forEach(([columnName, rawValue]) => {
295
+ parseFilterEntry(columnName, rawValue);
296
+ });
297
+ }
298
+ console.log("Parsed filters:", parsedFilters);
228
299
  const pool = getConnection();
229
- if (!pool || !pool.connected) {
300
+ if (!pool) {
301
+ return res.status(400).json({ error: "Not connected to database" });
302
+ }
303
+ const isConnected = "connected" in pool ? pool.connected === true : !pool.ended;
304
+ if (!isConnected) {
230
305
  return res.status(400).json({ error: "Not connected to database" });
231
306
  }
232
- const filterColumns = [];
233
- if (Object.keys(filters).length > 0) {
307
+ const dialect = getDialect();
308
+ const columnMetadata = {};
309
+ if (parsedFilters.length > 0) {
234
310
  try {
235
- const columnNames = Object.keys(filters);
236
- const placeholders = columnNames.map((_, i) => `@col${i}`).join(", ");
311
+ const columnNames = [...new Set(parsedFilters.map((f) => f.column))];
312
+ const placeholders = columnNames.map((_, i) => dialect.param(i + 3)).join(", ");
237
313
  const validateQuery = `
238
- SELECT COLUMN_NAME
239
- FROM INFORMATION_SCHEMA.COLUMNS
240
- WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND COLUMN_NAME IN (${placeholders})
314
+ SELECT column_name, data_type
315
+ FROM information_schema.columns
316
+ WHERE table_schema = ${dialect.param(1)} AND table_name = ${dialect.param(2)} AND column_name IN (${placeholders})
241
317
  `;
242
318
  const validateParams = [
243
- { name: "schema", value: schema, type: sql.NVarChar },
244
- { name: "table", value: table, type: sql.NVarChar },
245
- ...columnNames.map((col, i) => ({ name: `col${i}`, value: col, type: sql.NVarChar }))
319
+ { name: "schema", value: schema },
320
+ { name: "table", value: table },
321
+ ...columnNames.map((col) => ({ name: "col", value: col }))
246
322
  ];
247
323
  const validateResult = await executeQuery(validateQuery, validateParams);
248
- filterColumns.push(...validateResult.map((r) => r.COLUMN_NAME));
249
- console.log("Validated filter columns:", filterColumns, "from filters:", filters);
324
+ validateResult.forEach((r) => {
325
+ const colName = r.column_name || r.COLUMN_NAME;
326
+ const dataType = r.data_type || r.DATA_TYPE;
327
+ columnMetadata[colName] = {
328
+ dataType,
329
+ exists: true
330
+ };
331
+ });
332
+ console.log("Column metadata:", columnMetadata);
250
333
  } catch (e) {
251
334
  console.error("Error validating filter columns:", e);
252
- console.error("Filters that failed validation:", filters);
253
335
  }
254
336
  }
255
337
  let whereClause = "";
256
338
  const filterParams = [];
257
- if (filterColumns.length > 0) {
258
- const validFilters = filterColumns.filter((col) => {
259
- const filterValue = filters[col];
260
- return filterValue && filterValue.trim() !== "";
339
+ let paramIndex = 1;
340
+ if (parsedFilters.length > 0) {
341
+ const whereConditions = [];
342
+ parsedFilters.forEach((filter) => {
343
+ const columnName = filter.column;
344
+ const metadata = columnMetadata[columnName];
345
+ if (!metadata || !metadata.exists) {
346
+ console.warn(`Filter column ${columnName} not found, skipping`);
347
+ return;
348
+ }
349
+ const dataType = filter.dataType || metadata.dataType;
350
+ const operator = filter.operator;
351
+ const value = filter.value;
352
+ if (value === null || value === void 0 || value === "") {
353
+ return;
354
+ }
355
+ const quotedColumn = dialect.quoteId(columnName);
356
+ try {
357
+ let condition = "";
358
+ switch (operator) {
359
+ // Text operators
360
+ case "contains":
361
+ filterParams.push({ name: `filter${paramIndex}`, value: `%${String(value)}%` });
362
+ condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
363
+ break;
364
+ case "equals":
365
+ filterParams.push({ name: `filter${paramIndex}`, value: String(value) });
366
+ condition = `${quotedColumn} = ${dialect.param(paramIndex)}`;
367
+ break;
368
+ case "startsWith":
369
+ filterParams.push({ name: `filter${paramIndex}`, value: `${String(value)}%` });
370
+ condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
371
+ break;
372
+ case "endsWith":
373
+ filterParams.push({ name: `filter${paramIndex}`, value: `%${String(value)}` });
374
+ condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
375
+ break;
376
+ case "notContains":
377
+ filterParams.push({ name: `filter${paramIndex}`, value: `%${String(value)}%` });
378
+ condition = `${quotedColumn} NOT LIKE ${dialect.param(paramIndex)}`;
379
+ break;
380
+ // Number operators
381
+ case "eq":
382
+ filterParams.push({ name: `filter${paramIndex}`, value: Number(value) });
383
+ condition = `${quotedColumn} = ${dialect.param(paramIndex)}`;
384
+ break;
385
+ case "gt":
386
+ filterParams.push({ name: `filter${paramIndex}`, value: Number(value) });
387
+ condition = `${quotedColumn} > ${dialect.param(paramIndex)}`;
388
+ break;
389
+ case "gte":
390
+ filterParams.push({ name: `filter${paramIndex}`, value: Number(value) });
391
+ condition = `${quotedColumn} >= ${dialect.param(paramIndex)}`;
392
+ break;
393
+ case "lt":
394
+ filterParams.push({ name: `filter${paramIndex}`, value: Number(value) });
395
+ condition = `${quotedColumn} < ${dialect.param(paramIndex)}`;
396
+ break;
397
+ case "lte":
398
+ filterParams.push({ name: `filter${paramIndex}`, value: Number(value) });
399
+ condition = `${quotedColumn} <= ${dialect.param(paramIndex)}`;
400
+ break;
401
+ case "between":
402
+ if (typeof value === "object" && "from" in value && "to" in value) {
403
+ const fromParamIndex = paramIndex;
404
+ const toParamIndex = paramIndex + 1;
405
+ filterParams.push({ name: `filter${fromParamIndex}`, value: Number(value.from) });
406
+ filterParams.push({ name: `filter${toParamIndex}`, value: Number(value.to) });
407
+ condition = `${quotedColumn} BETWEEN ${dialect.param(fromParamIndex)} AND ${dialect.param(toParamIndex)}`;
408
+ paramIndex++;
409
+ }
410
+ break;
411
+ // Date operators
412
+ case "dateEq":
413
+ filterParams.push({ name: `filter${paramIndex}`, value: String(value) });
414
+ condition = `${dialect.castToDate(quotedColumn)} = ${dialect.castToDate(dialect.param(paramIndex))}`;
415
+ break;
416
+ case "dateAfter":
417
+ filterParams.push({ name: `filter${paramIndex}`, value: String(value) });
418
+ condition = `${dialect.castToDate(quotedColumn)} > ${dialect.castToDate(dialect.param(paramIndex))}`;
419
+ break;
420
+ case "dateBefore":
421
+ filterParams.push({ name: `filter${paramIndex}`, value: String(value) });
422
+ condition = `${dialect.castToDate(quotedColumn)} < ${dialect.castToDate(dialect.param(paramIndex))}`;
423
+ break;
424
+ case "dateBetween":
425
+ if (typeof value === "object" && "from" in value && "to" in value) {
426
+ const fromParamIndex = paramIndex;
427
+ const toParamIndex = paramIndex + 1;
428
+ filterParams.push({ name: `filter${fromParamIndex}`, value: String(value.from) });
429
+ filterParams.push({ name: `filter${toParamIndex}`, value: String(value.to) });
430
+ condition = `${dialect.castToDate(quotedColumn)} BETWEEN ${dialect.castToDate(dialect.param(fromParamIndex))} AND ${dialect.castToDate(dialect.param(toParamIndex))}`;
431
+ paramIndex++;
432
+ }
433
+ break;
434
+ // Multiple select operators
435
+ case "in":
436
+ case "notIn":
437
+ if (Array.isArray(value) && value.length > 0) {
438
+ const placeholders = [];
439
+ value.forEach((val, i) => {
440
+ const currentIndex = paramIndex + i;
441
+ filterParams.push({ name: `filter${currentIndex}`, value: val });
442
+ placeholders.push(dialect.param(currentIndex));
443
+ });
444
+ const inOperator = operator === "in" ? "IN" : "NOT IN";
445
+ condition = `${quotedColumn} ${inOperator} (${placeholders.join(", ")})`;
446
+ paramIndex += value.length - 1;
447
+ }
448
+ break;
449
+ default:
450
+ console.warn(`Unknown filter operator: ${operator}, falling back to contains`);
451
+ filterParams.push({ name: `filter${paramIndex}`, value: `%${String(value)}%` });
452
+ condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
453
+ }
454
+ if (condition) {
455
+ whereConditions.push(condition);
456
+ paramIndex++;
457
+ }
458
+ } catch (error) {
459
+ console.error(`Error building filter condition for ${columnName}:`, error);
460
+ }
261
461
  });
262
- if (validFilters.length > 0) {
263
- const whereConditions = validFilters.map((col, index) => {
264
- const filterValue = filters[col];
265
- filterParams.push({ name: `filter${index}`, value: `%${filterValue.trim()}%`, type: sql.NVarChar });
266
- return `[${col}] LIKE @filter${index}`;
267
- });
462
+ if (whereConditions.length > 0) {
268
463
  whereClause = `WHERE ${whereConditions.join(" AND ")}`;
269
464
  console.log("Applying WHERE clause:", whereClause);
270
- console.log("Filter params:", filterParams);
271
- console.log("Valid filters:", validFilters);
465
+ console.log("Filter params:", filterParams.map((p) => ({ name: p.name, value: p.value })));
272
466
  }
273
467
  }
274
- const countQuery = `SELECT COUNT(*) as total FROM [${schema}].[${table}]${whereClause ? " " + whereClause : ""}`;
468
+ const qualifiedDataWhereClause = parsedFilters.reduce((clause, filter) => {
469
+ const quotedColumn = dialect.quoteId(filter.column);
470
+ const quotedTableColumn = `${dialect.quoteId("t")}.${quotedColumn}`;
471
+ return clause.replace(new RegExp(quotedColumn.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), quotedTableColumn);
472
+ }, whereClause);
473
+ const quotedSchema = dialect.quoteId(schema);
474
+ const quotedTable = dialect.quoteId(table);
475
+ const countQuery = `SELECT COUNT(*) as total FROM ${quotedSchema}.${quotedTable}${whereClause ? " " + whereClause : ""}`;
275
476
  const countResult = await executeQuery(countQuery, filterParams.length > 0 ? filterParams : []);
276
477
  const total = countResult[0]?.total || 0;
277
478
  let orderByColumn = sortColumn || "";
@@ -279,17 +480,19 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
279
480
  if (orderByColumn) {
280
481
  try {
281
482
  const validateQuery = `
282
- SELECT COLUMN_NAME
283
- FROM INFORMATION_SCHEMA.COLUMNS
284
- WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND COLUMN_NAME = @column
483
+ SELECT column_name
484
+ FROM information_schema.columns
485
+ WHERE table_schema = ${dialect.param(1)} AND table_name = ${dialect.param(2)} AND column_name = ${dialect.param(3)}
285
486
  `;
286
487
  const validateResult = await executeQuery(validateQuery, [
287
- { name: "schema", value: schema, type: sql.NVarChar },
288
- { name: "table", value: table, type: sql.NVarChar },
289
- { name: "column", value: orderByColumn, type: sql.NVarChar }
488
+ { name: "schema", value: schema },
489
+ { name: "table", value: table },
490
+ { name: "column", value: orderByColumn }
290
491
  ]);
291
492
  if (validateResult.length === 0) {
292
493
  orderByColumn = "";
494
+ } else {
495
+ orderByColumn = validateResult[0].column_name || validateResult[0].COLUMN_NAME || orderByColumn;
293
496
  }
294
497
  } catch (e) {
295
498
  orderByColumn = "";
@@ -297,18 +500,20 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
297
500
  }
298
501
  if (!orderByColumn) {
299
502
  try {
503
+ const topClause = dialect.topN(1);
300
504
  const structureQuery = `
301
- SELECT TOP 1 COLUMN_NAME
302
- FROM INFORMATION_SCHEMA.COLUMNS
303
- WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table
304
- ORDER BY ORDINAL_POSITION
505
+ SELECT ${topClause ? topClause + " " : ""}column_name
506
+ FROM information_schema.columns
507
+ WHERE table_schema = ${dialect.param(1)} AND table_name = ${dialect.param(2)}
508
+ ORDER BY ordinal_position
509
+ ${!topClause ? dialect.limitOffset(0, 1) : ""}
305
510
  `;
306
511
  const structureResult = await executeQuery(structureQuery, [
307
- { name: "schema", value: schema, type: sql.NVarChar },
308
- { name: "table", value: table, type: sql.NVarChar }
512
+ { name: "schema", value: schema },
513
+ { name: "table", value: table }
309
514
  ]);
310
515
  if (structureResult.length > 0) {
311
- orderByColumn = structureResult[0].COLUMN_NAME;
516
+ orderByColumn = structureResult[0].column_name || structureResult[0].COLUMN_NAME;
312
517
  }
313
518
  } catch (e) {
314
519
  }
@@ -316,93 +521,97 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
316
521
  const fkJoins = [];
317
522
  const fkSelects = [];
318
523
  const fkDisplayColumns = {};
319
- if (fkDisplayMode === "key-display" || fkDisplayMode === "display-only") {
320
- const fkQuery = `
524
+ const fkQuery = `
321
525
  SELECT
322
- kcu1.COLUMN_NAME as fkColumnName,
323
- kcu2.TABLE_SCHEMA as referencedSchema,
324
- kcu2.TABLE_NAME as referencedTable,
325
- kcu2.COLUMN_NAME as referencedColumn
326
- FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
327
- INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu1
328
- ON rc.CONSTRAINT_CATALOG = kcu1.CONSTRAINT_CATALOG
329
- AND rc.CONSTRAINT_SCHEMA = kcu1.CONSTRAINT_SCHEMA
330
- AND rc.CONSTRAINT_NAME = kcu1.CONSTRAINT_NAME
331
- INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu2
332
- ON rc.UNIQUE_CONSTRAINT_CATALOG = kcu2.CONSTRAINT_CATALOG
333
- AND rc.UNIQUE_CONSTRAINT_SCHEMA = kcu2.CONSTRAINT_SCHEMA
334
- AND rc.UNIQUE_CONSTRAINT_NAME = kcu2.CONSTRAINT_NAME
335
- AND kcu1.ORDINAL_POSITION = kcu2.ORDINAL_POSITION
336
- WHERE kcu1.TABLE_SCHEMA = @schema
337
- AND kcu1.TABLE_NAME = @table
526
+ kcu1.column_name as "fkColumnName",
527
+ kcu2.table_schema as "referencedSchema",
528
+ kcu2.table_name as "referencedTable",
529
+ kcu2.column_name as "referencedColumn"
530
+ FROM information_schema.referential_constraints rc
531
+ INNER JOIN information_schema.key_column_usage kcu1
532
+ ON rc.constraint_catalog = kcu1.constraint_catalog
533
+ AND rc.constraint_schema = kcu1.constraint_schema
534
+ AND rc.constraint_name = kcu1.constraint_name
535
+ INNER JOIN information_schema.key_column_usage kcu2
536
+ ON rc.unique_constraint_catalog = kcu2.constraint_catalog
537
+ AND rc.unique_constraint_schema = kcu2.constraint_schema
538
+ AND rc.unique_constraint_name = kcu2.constraint_name
539
+ AND kcu1.ordinal_position = kcu2.ordinal_position
540
+ WHERE kcu1.table_schema = ${dialect.param(1)}
541
+ AND kcu1.table_name = ${dialect.param(2)}
338
542
  `;
339
- console.log("Fetching foreign keys with query:", fkQuery);
340
- const foreignKeys = await executeQuery(fkQuery, [
341
- { name: "schema", value: schema, type: sql.NVarChar },
342
- { name: "table", value: table, type: sql.NVarChar }
343
- ]);
344
- console.log(`Found ${foreignKeys.length} foreign key(s)`);
345
- if (foreignKeys.length > 0) {
346
- const uniqueRefTables = Array.from(
347
- new Set(foreignKeys.map((fk) => `${fk.referencedSchema}.${fk.referencedTable}`))
348
- );
349
- const tableConditions = uniqueRefTables.map((tableRef, idx) => {
350
- const [refSchema, refTable] = tableRef.split(".");
351
- return `(TABLE_SCHEMA = @refSchema${idx} AND TABLE_NAME = @refTable${idx})`;
352
- }).join(" OR ");
353
- const batchColumnsQuery = `
354
- SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, ORDINAL_POSITION
355
- FROM INFORMATION_SCHEMA.COLUMNS
543
+ console.log("Fetching foreign keys with query:", fkQuery);
544
+ const foreignKeys = await executeQuery(fkQuery, [
545
+ { name: "schema", value: schema },
546
+ { name: "table", value: table }
547
+ ]);
548
+ console.log(`Found ${foreignKeys.length} foreign key(s)`);
549
+ if (foreignKeys.length > 0) {
550
+ const uniqueRefTables = Array.from(
551
+ new Set(foreignKeys.map((fk) => `${fk.referencedSchema || fk.referenced_schema}.${fk.referencedTable || fk.referenced_table}`))
552
+ );
553
+ const tableConditions = uniqueRefTables.map((tableRef, idx) => {
554
+ const [refSchema, refTable] = tableRef.split(".");
555
+ return `(table_schema = ${dialect.param(idx * 2 + 1)} AND table_name = ${dialect.param(idx * 2 + 2)})`;
556
+ }).join(" OR ");
557
+ const batchColumnsQuery = `
558
+ SELECT table_schema, table_name, column_name, data_type, ordinal_position
559
+ FROM information_schema.columns
356
560
  WHERE ${tableConditions}
357
- ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION
561
+ ORDER BY table_schema, table_name, ordinal_position
358
562
  `;
359
- const batchParams = uniqueRefTables.flatMap((tableRef, idx) => {
360
- const [refSchema, refTable] = tableRef.split(".");
361
- return [
362
- { name: `refSchema${idx}`, value: refSchema, type: sql.NVarChar },
363
- { name: `refTable${idx}`, value: refTable, type: sql.NVarChar }
364
- ];
365
- });
366
- console.log("Fetching referenced table columns with query:", batchColumnsQuery);
367
- console.log("Batch parameters:", batchParams.map((p) => ({ name: p.name, value: p.value })));
368
- const allRefColumns = await executeQuery(batchColumnsQuery, batchParams);
369
- console.log(`Found columns for ${uniqueRefTables.length} referenced table(s)`);
370
- const columnsByTable = {};
371
- allRefColumns.forEach((col) => {
372
- const key = `${col.TABLE_SCHEMA}.${col.TABLE_NAME}`;
373
- if (!columnsByTable[key]) {
374
- columnsByTable[key] = [];
375
- }
376
- columnsByTable[key].push(col);
377
- });
378
- for (const fk of foreignKeys) {
379
- const fkColumn = fk.fkColumnName;
380
- const refSchema = fk.referencedSchema;
381
- const refTable = fk.referencedTable;
382
- const refColumn = fk.referencedColumn;
383
- const tableKey = `${refSchema}.${refTable}`;
384
- const refColumns = columnsByTable[tableKey] || [];
385
- const preferredNames = ["name", "title", "description", "code"];
386
- let displayColumn = null;
387
- for (const preferredName of preferredNames) {
388
- const found = refColumns.find(
389
- (col) => col.COLUMN_NAME.toLowerCase() === preferredName.toLowerCase()
390
- );
391
- if (found) {
392
- displayColumn = found.COLUMN_NAME;
393
- break;
394
- }
563
+ const batchParams = uniqueRefTables.flatMap((tableRef) => {
564
+ const [refSchema, refTable] = tableRef.split(".");
565
+ return [
566
+ { name: "refSchema", value: refSchema },
567
+ { name: "refTable", value: refTable }
568
+ ];
569
+ });
570
+ console.log("Fetching referenced table columns with query:", batchColumnsQuery);
571
+ console.log("Batch parameters:", batchParams.map((p) => ({ name: p.name, value: p.value })));
572
+ const allRefColumns = await executeQuery(batchColumnsQuery, batchParams);
573
+ console.log(`Found columns for ${uniqueRefTables.length} referenced table(s)`);
574
+ const columnsByTable = {};
575
+ allRefColumns.forEach((col) => {
576
+ const schemaName = col.table_schema || col.TABLE_SCHEMA;
577
+ const tableName = col.table_name || col.TABLE_NAME;
578
+ const key = `${schemaName}.${tableName}`;
579
+ if (!columnsByTable[key]) {
580
+ columnsByTable[key] = [];
581
+ }
582
+ columnsByTable[key].push(col);
583
+ });
584
+ for (const fk of foreignKeys) {
585
+ const fkColumn = fk.fkColumnName || fk.fk_column_name;
586
+ const refSchema = fk.referencedSchema || fk.referenced_schema;
587
+ const refTable = fk.referencedTable || fk.referenced_table;
588
+ const refColumn = fk.referencedColumn || fk.referenced_column;
589
+ const tableKey = `${refSchema}.${refTable}`;
590
+ const refColumns = columnsByTable[tableKey] || [];
591
+ const preferredNames = ["name", "title", "description", "code"];
592
+ let displayColumn = null;
593
+ for (const preferredName of preferredNames) {
594
+ const found = refColumns.find((col) => {
595
+ const colName = col.column_name || col.COLUMN_NAME;
596
+ return colName.toLowerCase() === preferredName.toLowerCase();
597
+ });
598
+ if (found) {
599
+ displayColumn = found.column_name || found.COLUMN_NAME;
600
+ break;
395
601
  }
396
- if (!displayColumn) {
397
- const stringTypes = ["varchar", "nvarchar", "char", "nchar", "text", "ntext"];
398
- const found = refColumns.find(
399
- (col) => stringTypes.some((type) => col.DATA_TYPE.toLowerCase().includes(type))
400
- );
401
- if (found) {
402
- displayColumn = found.COLUMN_NAME;
403
- }
602
+ }
603
+ if (!displayColumn) {
604
+ const stringTypes = ["varchar", "nvarchar", "char", "nchar", "text", "ntext"];
605
+ const found = refColumns.find((col) => {
606
+ const dataType = col.data_type || col.DATA_TYPE;
607
+ return stringTypes.some((type) => dataType.toLowerCase().includes(type));
608
+ });
609
+ if (found) {
610
+ displayColumn = found.column_name || found.COLUMN_NAME;
404
611
  }
405
- if (displayColumn) {
612
+ }
613
+ if (displayColumn) {
614
+ if (fkDisplayMode === "key-display" || fkDisplayMode === "display-only") {
406
615
  const alias = `fk_${fkColumn}`;
407
616
  fkJoins.push({
408
617
  alias,
@@ -412,89 +621,79 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
412
621
  refColumn,
413
622
  displayColumn
414
623
  });
415
- fkSelects.push(`${alias}.[${displayColumn}] as [${fkColumn}_display]`);
416
- fkDisplayColumns[fkColumn] = displayColumn;
624
+ fkSelects.push(`${dialect.quoteId(alias)}.${dialect.quoteId(displayColumn)} as ${dialect.quoteId(`${fkColumn}_display`)}`);
417
625
  }
626
+ fkDisplayColumns[fkColumn] = displayColumn;
418
627
  }
419
628
  }
420
629
  }
421
630
  const baseTableAlias = "t";
422
- let baseSelects = `[${baseTableAlias}].*`;
631
+ const quotedTableAlias = dialect.quoteId(baseTableAlias);
632
+ let baseSelects = `${quotedTableAlias}.*`;
423
633
  if (fkDisplayMode === "display-only") {
424
634
  const fkColumnNames = fkJoins.map((fk) => fk.fkColumn);
425
635
  if (fkColumnNames.length > 0) {
426
- baseSelects = `[${baseTableAlias}].*`;
636
+ baseSelects = `${quotedTableAlias}.*`;
427
637
  }
428
638
  }
429
639
  const allSelects = `${baseSelects}${fkSelects.length > 0 ? ", " + fkSelects.join(", ") : ""}`;
430
640
  const buildJoinClauses = (tableAlias) => {
431
- return fkJoins.map(
432
- (fk) => `LEFT JOIN [${fk.refSchema}].[${fk.refTable}] ${fk.alias} ON [${tableAlias}].[${fk.fkColumn}] = ${fk.alias}.[${fk.refColumn}]`
433
- ).join("\n ");
641
+ const quotedAlias = dialect.quoteId(tableAlias);
642
+ return fkJoins.map((fk) => {
643
+ const quotedRefSchema = dialect.quoteId(fk.refSchema);
644
+ const quotedRefTable = dialect.quoteId(fk.refTable);
645
+ const quotedAliasName = dialect.quoteId(fk.alias);
646
+ const quotedFkColumn = dialect.quoteId(fk.fkColumn);
647
+ const quotedRefColumn = dialect.quoteId(fk.refColumn);
648
+ return `LEFT JOIN ${quotedRefSchema}.${quotedRefTable} ${quotedAliasName} ON ${quotedAlias}.${quotedFkColumn} = ${quotedAliasName}.${quotedRefColumn}`;
649
+ }).join("\n ");
434
650
  };
435
651
  let data;
436
652
  let generatedQuery = "";
653
+ const offsetParamIndex = filterParams.length + 1;
654
+ const pageSizeParamIndex = filterParams.length + 2;
437
655
  if (orderByColumn) {
656
+ const quotedOrderByColumn = dialect.quoteId(orderByColumn);
657
+ const limitOffsetClause = dialect.limitOffset(offset, pageSize);
438
658
  const dataQuery = `
439
659
  SELECT ${allSelects}
440
- FROM [${schema}].[${table}] ${baseTableAlias}
660
+ FROM ${quotedSchema}.${quotedTable} ${quotedTableAlias}
441
661
  ${buildJoinClauses(baseTableAlias)}
442
- ${whereClause}
443
- ORDER BY ${baseTableAlias}.[${orderByColumn}] ${orderByDirection}
444
- OFFSET @offset ROWS
445
- FETCH NEXT @pageSize ROWS ONLY
662
+ ${qualifiedDataWhereClause}
663
+ ORDER BY ${quotedTableAlias}.${quotedOrderByColumn} ${orderByDirection}
664
+ ${limitOffsetClause}
446
665
  `;
447
666
  generatedQuery = `SELECT ${allSelects}
448
- FROM [${schema}].[${table}] ${baseTableAlias}${fkJoins.length > 0 ? "\n" + buildJoinClauses(baseTableAlias) : ""}${whereClause ? "\n" + whereClause : ""}
449
- ORDER BY ${baseTableAlias}.[${orderByColumn}] ${orderByDirection}
450
- OFFSET ${offset} ROWS
451
- FETCH NEXT ${pageSize} ROWS ONLY`;
667
+ FROM ${quotedSchema}.${quotedTable} ${quotedTableAlias}${fkJoins.length > 0 ? "\n" + buildJoinClauses(baseTableAlias) : ""}${qualifiedDataWhereClause ? "\n" + qualifiedDataWhereClause : ""}
668
+ ORDER BY ${quotedTableAlias}.${quotedOrderByColumn} ${orderByDirection}
669
+ ${limitOffsetClause}`;
452
670
  console.log("Executing SQL query:", dataQuery);
453
671
  console.log("Query parameters:", {
454
672
  offset,
455
673
  pageSize,
456
674
  filterParams: filterParams.map((p) => ({ name: p.name, value: p.value }))
457
675
  });
458
- data = await executeQuery(dataQuery, [
459
- { name: "offset", value: offset, type: sql.Int },
460
- { name: "pageSize", value: pageSize, type: sql.Int },
461
- ...filterParams
462
- ]);
676
+ data = await executeQuery(dataQuery, filterParams);
463
677
  } else {
464
- const innerQuery = `
465
- SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as rn
466
- FROM [${schema}].[${table}]
467
- ${whereClause}
468
- `;
678
+ const dbType = getDbType();
679
+ const limitOffsetClause = dialect.limitOffset(offset, pageSize);
469
680
  const dataQuery = `
470
681
  SELECT ${allSelects}
471
- FROM (${innerQuery}) ${baseTableAlias}
682
+ FROM ${quotedSchema}.${quotedTable} ${quotedTableAlias}
472
683
  ${buildJoinClauses(baseTableAlias)}
473
- WHERE ${baseTableAlias}.rn > @offset AND ${baseTableAlias}.rn <= @offset + @pageSize
474
- ORDER BY ${baseTableAlias}.rn
684
+ ${qualifiedDataWhereClause}
685
+ ${limitOffsetClause}
475
686
  `;
476
687
  generatedQuery = `SELECT ${allSelects}
477
- FROM (
478
- SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as rn
479
- FROM [${schema}].[${table}]${whereClause ? "\n " + whereClause : ""}
480
- ) ${baseTableAlias}${fkJoins.length > 0 ? "\n" + buildJoinClauses(baseTableAlias) : ""}
481
- WHERE ${baseTableAlias}.rn > ${offset} AND ${baseTableAlias}.rn <= ${offset + pageSize}
482
- ORDER BY ${baseTableAlias}.rn`;
688
+ FROM ${quotedSchema}.${quotedTable} ${quotedTableAlias}${fkJoins.length > 0 ? "\n" + buildJoinClauses(baseTableAlias) : ""}${qualifiedDataWhereClause ? "\n" + qualifiedDataWhereClause : ""}
689
+ ${limitOffsetClause}`;
483
690
  console.log("Executing SQL query:", dataQuery);
484
691
  console.log("Query parameters:", {
485
692
  offset,
486
693
  pageSize,
487
694
  filterParams: filterParams.map((p) => ({ name: p.name, value: p.value }))
488
695
  });
489
- data = await executeQuery(dataQuery, [
490
- { name: "offset", value: offset, type: sql.Int },
491
- { name: "pageSize", value: pageSize, type: sql.Int },
492
- ...filterParams
493
- ]);
494
- data = data.map((row) => {
495
- const { rn, ...rest } = row;
496
- return rest;
497
- });
696
+ data = await executeQuery(dataQuery, filterParams);
498
697
  }
499
698
  if (fkDisplayMode === "display-only") {
500
699
  const fkColumnNames = fkJoins.map((fk) => fk.fkColumn);
@@ -511,6 +710,34 @@ ORDER BY ${baseTableAlias}.rn`;
511
710
  return filteredRow;
512
711
  });
513
712
  }
713
+ if (generatedQuery && filterParams.length > 0) {
714
+ const formatSqlLiteral = (value) => {
715
+ if (value === null || value === void 0) return "NULL";
716
+ if (typeof value === "number") return Number.isFinite(value) ? String(value) : "NULL";
717
+ if (typeof value === "boolean") return value ? "1" : "0";
718
+ if (value instanceof Date) return `'${value.toISOString().replace("T", " ").slice(0, 19)}'`;
719
+ return `'${String(value).replace(/'/g, "''")}'`;
720
+ };
721
+ const paramValues = new Map(
722
+ filterParams.map((p) => [p.name, p.value])
723
+ );
724
+ const dbType = getDbType();
725
+ if (dbType === "postgres") {
726
+ let paramIndex2 = 1;
727
+ generatedQuery = generatedQuery.replace(/\$(\d+)/g, (full, index) => {
728
+ const idx = parseInt(index, 10) - 1;
729
+ if (idx < filterParams.length) {
730
+ return formatSqlLiteral(filterParams[idx].value);
731
+ }
732
+ return full;
733
+ });
734
+ } else {
735
+ generatedQuery = generatedQuery.replace(/@([A-Za-z0-9_]+)/g, (full, name) => {
736
+ if (!paramValues.has(name)) return full;
737
+ return formatSqlLiteral(paramValues.get(name));
738
+ });
739
+ }
740
+ }
514
741
  res.json({
515
742
  data,
516
743
  query: generatedQuery,
@@ -526,8 +753,8 @@ ORDER BY ${baseTableAlias}.rn`;
526
753
  } catch (error) {
527
754
  console.error("Error fetching table data:", error);
528
755
  const errorMessage = error.message || "";
529
- if (errorMessage.includes("Login failed") || errorMessage.includes("authentication")) {
530
- const { disconnect: disconnect2 } = await import("./mssql-AYS72PRQ.js");
756
+ if (errorMessage.includes("Login failed") || errorMessage.includes("authentication") || errorMessage.includes("password authentication")) {
757
+ const { disconnect: disconnect2 } = await import("./db-OIJ2PJK6.js");
531
758
  await disconnect2();
532
759
  }
533
760
  const isTimeout = error.code === "ETIMEOUT" || error.code === "ESOCKET" || error.message?.includes("timeout") || error.message?.includes("ETIMEDOUT") || error.originalError?.code === "ETIMEOUT" || error.originalError?.code === "ESOCKET";
@@ -554,73 +781,68 @@ tableRoutes.post("/:schema/:table/related-data", async (req, res) => {
554
781
  return res.status(400).json({ error: "Missing required parameters" });
555
782
  }
556
783
  const pool = getConnection();
557
- if (!pool || !pool.connected) {
784
+ if (!pool) {
785
+ return res.status(400).json({ error: "Not connected to database" });
786
+ }
787
+ const isConnected = "connected" in pool ? pool.connected === true : !pool.ended;
788
+ if (!isConnected) {
558
789
  return res.status(400).json({ error: "Not connected to database" });
559
790
  }
791
+ const dialect = getDialect();
560
792
  const columnsQuery = `
561
- SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH
562
- FROM INFORMATION_SCHEMA.COLUMNS
563
- WHERE TABLE_SCHEMA = @refSchema
564
- AND TABLE_NAME = @refTable
565
- ORDER BY ORDINAL_POSITION
793
+ SELECT column_name, data_type, character_maximum_length
794
+ FROM information_schema.columns
795
+ WHERE table_schema = ${dialect.param(1)}
796
+ AND table_name = ${dialect.param(2)}
797
+ ORDER BY ordinal_position
566
798
  `;
567
799
  const columns = await executeQuery(columnsQuery, [
568
- { name: "refSchema", value: referencedSchema, type: sql.NVarChar },
569
- { name: "refTable", value: referencedTable, type: sql.NVarChar }
800
+ { name: "refSchema", value: referencedSchema },
801
+ { name: "refTable", value: referencedTable }
570
802
  ]);
571
- const referencedColInfo = columns.find(
572
- (col) => col.COLUMN_NAME === referencedColumn
573
- );
803
+ const referencedColInfo = columns.find((col) => {
804
+ const colName = col.column_name || col.COLUMN_NAME;
805
+ return colName === referencedColumn;
806
+ });
574
807
  if (!referencedColInfo) {
575
808
  return res.status(400).json({ error: `Referenced column '${referencedColumn}' not found` });
576
809
  }
577
- const getSqlType = (dataType) => {
578
- const dt = dataType.toLowerCase();
579
- if (dt === "int" || dt === "integer") return sql.Int;
580
- if (dt === "bigint") return sql.BigInt;
581
- if (dt === "smallint") return sql.SmallInt;
582
- if (dt === "tinyint") return sql.TinyInt;
583
- if (dt === "bit") return sql.Bit;
584
- if (dt === "float" || dt === "real" || dt === "double precision") return sql.Float;
585
- if (dt === "decimal" || dt === "numeric" || dt === "money" || dt === "smallmoney") return sql.Decimal(18, 0);
586
- if (dt === "datetime" || dt === "datetime2" || dt === "smalldatetime") return sql.DateTime;
587
- if (dt === "date") return sql.Date;
588
- if (dt === "time") return sql.Time;
589
- if (dt === "uniqueidentifier") return sql.UniqueIdentifier;
590
- return sql.NVarChar;
591
- };
592
- const referencedColumnType = getSqlType(referencedColInfo.DATA_TYPE);
593
810
  const preferredNames = ["name", "title", "description", "code"];
594
811
  let displayColumn = null;
595
812
  for (const preferredName of preferredNames) {
596
- const found = columns.find(
597
- (col) => col.COLUMN_NAME.toLowerCase() === preferredName.toLowerCase()
598
- );
813
+ const found = columns.find((col) => {
814
+ const colName = col.column_name || col.COLUMN_NAME;
815
+ return colName.toLowerCase() === preferredName.toLowerCase();
816
+ });
599
817
  if (found) {
600
- displayColumn = found.COLUMN_NAME;
818
+ displayColumn = found.column_name || found.COLUMN_NAME;
601
819
  break;
602
820
  }
603
821
  }
604
822
  if (!displayColumn) {
605
823
  const stringTypes = ["varchar", "nvarchar", "char", "nchar", "text", "ntext"];
606
- const found = columns.find(
607
- (col) => stringTypes.some((type) => col.DATA_TYPE.toLowerCase().includes(type))
608
- );
824
+ const found = columns.find((col) => {
825
+ const dataType = col.data_type || col.DATA_TYPE;
826
+ return stringTypes.some((type) => dataType.toLowerCase().includes(type));
827
+ });
609
828
  if (found) {
610
- displayColumn = found.COLUMN_NAME;
829
+ displayColumn = found.column_name || found.COLUMN_NAME;
611
830
  }
612
831
  }
613
- const placeholders = ids.map((_, i) => `@id${i}`).join(", ");
614
- const selectColumns = displayColumn ? `[${referencedColumn}], [${displayColumn}]` : `[${referencedColumn}]`;
832
+ const quotedRefSchema = dialect.quoteId(referencedSchema);
833
+ const quotedRefTable = dialect.quoteId(referencedTable);
834
+ const quotedRefColumn = dialect.quoteId(referencedColumn);
835
+ const quotedDisplayColumn = displayColumn ? dialect.quoteId(displayColumn) : null;
836
+ const placeholders = ids.map((_, i) => dialect.param(i + 1)).join(", ");
837
+ const selectColumns = displayColumn ? `${quotedRefColumn}, ${quotedDisplayColumn}` : quotedRefColumn;
615
838
  const dataQuery = `
616
839
  SELECT ${selectColumns}
617
- FROM [${referencedSchema}].[${referencedTable}]
618
- WHERE [${referencedColumn}] IN (${placeholders})
840
+ FROM ${quotedRefSchema}.${quotedRefTable}
841
+ WHERE ${quotedRefColumn} IN (${placeholders})
619
842
  `;
620
- const params = ids.map((id, i) => ({
621
- name: `id${i}`,
622
- value: id,
623
- type: referencedColumnType
843
+ const params = ids.map((id) => ({
844
+ name: "id",
845
+ value: id
624
846
  }));
625
847
  const result = await executeQuery(dataQuery, params);
626
848
  const dataMap = {};
@@ -632,37 +854,223 @@ tableRoutes.post("/:schema/:table/related-data", async (req, res) => {
632
854
  } catch (error) {
633
855
  console.error("Error fetching related data:", error);
634
856
  const errorMessage = error.message || "";
635
- if (errorMessage.includes("Login failed") || errorMessage.includes("authentication")) {
636
- const { disconnect: disconnect2 } = await import("./mssql-AYS72PRQ.js");
857
+ if (errorMessage.includes("Login failed") || errorMessage.includes("authentication") || errorMessage.includes("password authentication")) {
858
+ const { disconnect: disconnect2 } = await import("./db-OIJ2PJK6.js");
637
859
  await disconnect2();
638
860
  }
639
861
  res.status(500).json({ error: error.message || "Failed to fetch related data" });
640
862
  }
641
863
  });
864
+ tableRoutes.get("/:schema/:table/distinct-values/:column", async (req, res) => {
865
+ try {
866
+ const { schema, table, column } = req.params;
867
+ const searchQuery = req.query.search;
868
+ const columnsParam = req.query.columns;
869
+ const pool = getConnection();
870
+ if (!pool) {
871
+ return res.status(400).json({ error: "Not connected to database" });
872
+ }
873
+ const isConnected = "connected" in pool ? pool.connected === true : !pool.ended;
874
+ if (!isConnected) {
875
+ return res.status(400).json({ error: "Not connected to database" });
876
+ }
877
+ const dialect = getDialect();
878
+ const columnQuery = `
879
+ SELECT
880
+ c.column_name,
881
+ c.data_type,
882
+ fk.referenced_table_schema as "referencedSchema",
883
+ fk.referenced_table_name as "referencedTable",
884
+ fk.referenced_column_name as "referencedColumn"
885
+ FROM information_schema.columns c
886
+ LEFT JOIN (
887
+ SELECT
888
+ kcu1.table_schema,
889
+ kcu1.table_name,
890
+ kcu1.column_name,
891
+ kcu2.table_schema as referenced_table_schema,
892
+ kcu2.table_name as referenced_table_name,
893
+ kcu2.column_name as referenced_column_name
894
+ FROM information_schema.referential_constraints rc
895
+ INNER JOIN information_schema.key_column_usage kcu1
896
+ ON rc.constraint_catalog = kcu1.constraint_catalog
897
+ AND rc.constraint_schema = kcu1.constraint_schema
898
+ AND rc.constraint_name = kcu1.constraint_name
899
+ INNER JOIN information_schema.key_column_usage kcu2
900
+ ON rc.unique_constraint_catalog = kcu2.constraint_catalog
901
+ AND rc.unique_constraint_schema = kcu2.constraint_schema
902
+ AND rc.unique_constraint_name = kcu2.constraint_name
903
+ AND kcu1.ordinal_position = kcu2.ordinal_position
904
+ ) fk ON c.table_schema = fk.table_schema
905
+ AND c.table_name = fk.table_name
906
+ AND c.column_name = fk.column_name
907
+ WHERE c.table_schema = ${dialect.param(1)} AND c.table_name = ${dialect.param(2)} AND c.column_name = ${dialect.param(3)}
908
+ `;
909
+ const columnResult = await executeQuery(columnQuery, [
910
+ { name: "schema", value: schema },
911
+ { name: "table", value: table },
912
+ { name: "column", value: column }
913
+ ]);
914
+ if (columnResult.length === 0) {
915
+ return res.status(400).json({ error: "Column not found" });
916
+ }
917
+ const columnInfo = columnResult[0];
918
+ const isForeignKey = !!(columnInfo.referencedSchema || columnInfo.referenced_schema) && !!(columnInfo.referencedTable || columnInfo.referenced_table);
919
+ let query = "";
920
+ const params = [];
921
+ let displayColumn = null;
922
+ if (isForeignKey) {
923
+ const refSchema = columnInfo.referencedSchema || columnInfo.referenced_schema;
924
+ const refTable = columnInfo.referencedTable || columnInfo.referenced_table;
925
+ const refColumn = columnInfo.referencedColumn || columnInfo.referenced_column;
926
+ const quotedRefSchema = dialect.quoteId(refSchema);
927
+ const quotedRefTable = dialect.quoteId(refTable);
928
+ const quotedRefColumn = dialect.quoteId(refColumn);
929
+ let columnsToSelect = [];
930
+ if (columnsParam) {
931
+ columnsToSelect = columnsParam.split(",").map((c) => c.trim()).filter((c) => c);
932
+ }
933
+ if (columnsToSelect.length > 0) {
934
+ const selectCols = columnsToSelect.map((col) => dialect.quoteId(col)).join(", ");
935
+ query = `SELECT DISTINCT ${selectCols} FROM ${quotedRefSchema}.${quotedRefTable}`;
936
+ if (searchQuery && searchQuery.trim()) {
937
+ const searchCols = columnsToSelect.map((col) => `${dialect.quoteId(col)} LIKE ${dialect.param(1)}`).join(" OR ");
938
+ query += ` WHERE (${searchCols}) AND ${quotedRefColumn} IS NOT NULL`;
939
+ params.push({ name: "search", value: `%${searchQuery.trim()}%` });
940
+ } else {
941
+ query += ` WHERE ${quotedRefColumn} IS NOT NULL`;
942
+ }
943
+ const orderByCol = columnsToSelect.length > 1 ? columnsToSelect[1] : columnsToSelect[0];
944
+ query += ` ORDER BY ${dialect.quoteId(orderByCol)} ${dialect.limitOffset(0, 1e3)}`;
945
+ } else {
946
+ const refColumnsQuery = `
947
+ SELECT column_name, data_type
948
+ FROM information_schema.columns
949
+ WHERE table_schema = ${dialect.param(1)} AND table_name = ${dialect.param(2)}
950
+ ORDER BY ordinal_position
951
+ `;
952
+ const refColumns = await executeQuery(refColumnsQuery, [
953
+ { name: "refSchema", value: refSchema },
954
+ { name: "refTable", value: refTable }
955
+ ]);
956
+ const preferredNames = ["name", "title", "description", "code"];
957
+ for (const preferredName of preferredNames) {
958
+ const found = refColumns.find((col) => {
959
+ const colName = col.column_name || col.COLUMN_NAME;
960
+ return colName.toLowerCase() === preferredName.toLowerCase() && colName.toLowerCase() !== refColumn.toLowerCase();
961
+ });
962
+ if (found) {
963
+ displayColumn = found.column_name || found.COLUMN_NAME;
964
+ break;
965
+ }
966
+ }
967
+ if (!displayColumn) {
968
+ const stringTypes = ["varchar", "nvarchar", "char", "nchar", "text", "ntext"];
969
+ const found = refColumns.find((col) => {
970
+ const colName = col.column_name || col.COLUMN_NAME;
971
+ const dataType = col.data_type || col.DATA_TYPE;
972
+ return colName.toLowerCase() !== refColumn.toLowerCase() && stringTypes.some((type) => dataType.toLowerCase().includes(type));
973
+ });
974
+ if (found) {
975
+ displayColumn = found.column_name || found.COLUMN_NAME;
976
+ }
977
+ }
978
+ const quotedDisplayColumn = displayColumn ? dialect.quoteId(displayColumn) : null;
979
+ const selectCols = displayColumn ? `${quotedRefColumn}, ${quotedDisplayColumn}` : quotedRefColumn;
980
+ query = `SELECT DISTINCT ${selectCols} FROM ${quotedRefSchema}.${quotedRefTable}`;
981
+ if (searchQuery && searchQuery.trim()) {
982
+ if (displayColumn) {
983
+ query += ` WHERE ${quotedDisplayColumn} LIKE ${dialect.param(1)} OR ${quotedRefColumn} LIKE ${dialect.param(1)}`;
984
+ } else {
985
+ query += ` WHERE ${quotedRefColumn} LIKE ${dialect.param(1)}`;
986
+ }
987
+ params.push({ name: "search", value: `%${searchQuery.trim()}%` });
988
+ query += ` AND ${quotedRefColumn} IS NOT NULL`;
989
+ } else {
990
+ query += ` WHERE ${quotedRefColumn} IS NOT NULL`;
991
+ }
992
+ query += ` ORDER BY ${displayColumn ? quotedDisplayColumn : quotedRefColumn} ${dialect.limitOffset(0, 1e3)}`;
993
+ }
994
+ } else {
995
+ const dataType = (columnInfo.data_type || columnInfo.DATA_TYPE || "").toLowerCase();
996
+ const quotedSchema = dialect.quoteId(schema);
997
+ const quotedTable = dialect.quoteId(table);
998
+ const quotedColumn = dialect.quoteId(column);
999
+ const columnsToSelect = columnsParam ? columnsParam.split(",").map((c) => c.trim()).filter((c) => c) : [];
1000
+ if (columnsToSelect.length > 0) {
1001
+ const quotedColumns = columnsToSelect.map((col) => dialect.quoteId(col));
1002
+ const keyColumn = quotedColumns[0];
1003
+ const orderByColumn = quotedColumns.length > 1 ? quotedColumns[1] : quotedColumns[0];
1004
+ query = `SELECT DISTINCT ${quotedColumns.join(", ")} FROM ${quotedSchema}.${quotedTable}`;
1005
+ if (searchQuery && searchQuery.trim()) {
1006
+ const searchCols = quotedColumns.map((col) => `${dialect.tryCastToNVarChar(col)} LIKE ${dialect.param(1)}`).join(" OR ");
1007
+ query += ` WHERE (${searchCols}) AND ${keyColumn} IS NOT NULL`;
1008
+ params.push({ name: "search", value: `%${searchQuery.trim()}%` });
1009
+ } else {
1010
+ query += ` WHERE ${keyColumn} IS NOT NULL`;
1011
+ }
1012
+ query += ` ORDER BY ${orderByColumn} ${dialect.limitOffset(0, 1e3)}`;
1013
+ } else {
1014
+ query = `SELECT DISTINCT ${quotedColumn} FROM ${quotedSchema}.${quotedTable}`;
1015
+ if (searchQuery && searchQuery.trim()) {
1016
+ if (["varchar", "nvarchar", "char", "nchar", "text", "ntext"].some((t) => dataType.includes(t))) {
1017
+ query += ` WHERE ${quotedColumn} LIKE ${dialect.param(1)}`;
1018
+ params.push({ name: "search", value: `%${searchQuery.trim()}%` });
1019
+ query += ` AND ${quotedColumn} IS NOT NULL`;
1020
+ } else {
1021
+ query += ` WHERE ${quotedColumn} IS NOT NULL`;
1022
+ }
1023
+ } else {
1024
+ query += ` WHERE ${quotedColumn} IS NOT NULL`;
1025
+ }
1026
+ query += ` ORDER BY ${quotedColumn} ${dialect.limitOffset(0, 1e3)}`;
1027
+ }
1028
+ }
1029
+ const result = await executeQuery(query, params);
1030
+ res.json(result);
1031
+ } catch (error) {
1032
+ console.error("Error fetching distinct values:", error);
1033
+ const errorMessage = error.message || "";
1034
+ if (errorMessage.includes("Login failed") || errorMessage.includes("authentication") || errorMessage.includes("password authentication")) {
1035
+ const { disconnect: disconnect2 } = await import("./db-OIJ2PJK6.js");
1036
+ await disconnect2();
1037
+ }
1038
+ res.status(500).json({ error: error.message || "Failed to fetch distinct values" });
1039
+ }
1040
+ });
642
1041
 
643
1042
  // src/server/routes/query.ts
644
1043
  import { Router as Router3 } from "express";
645
1044
  var queryRoutes = Router3();
646
1045
  queryRoutes.post("/", async (req, res) => {
647
1046
  try {
648
- const { query: sqlQuery } = req.body;
1047
+ const { query: sqlQuery, queryId } = req.body;
649
1048
  if (!sqlQuery || typeof sqlQuery !== "string") {
650
1049
  return res.status(400).json({ error: "Query is required" });
651
1050
  }
1051
+ const activeQueryId = queryId || generateQueryId();
652
1052
  const startTime = Date.now();
653
- const { recordsets: resultSets, columnMetadata } = await executeQueryMultiple(sqlQuery);
1053
+ const { recordsets: resultSets, columnMetadata } = await executeQueryMultiple(sqlQuery, void 0, activeQueryId);
654
1054
  const executionTime = Date.now() - startTime;
655
1055
  res.json({
656
1056
  data: resultSets[0] || [],
657
1057
  resultSets: resultSets.length > 0 ? resultSets : [],
658
1058
  executionTime,
659
- columnMetadata
1059
+ columnMetadata,
660
1060
  // Include column metadata for empty result sets
1061
+ queryId: activeQueryId
1062
+ // Return queryId so client can track it
661
1063
  });
662
1064
  } catch (error) {
1065
+ if (error.cancelled || error.code === "ECANCEL") {
1066
+ return res.status(499).json({
1067
+ error: "Query was cancelled",
1068
+ cancelled: true
1069
+ });
1070
+ }
663
1071
  const errorMessage = error.message || "";
664
- if (errorMessage.includes("Login failed") || errorMessage.includes("authentication")) {
665
- const { disconnect: disconnect2 } = await import("./mssql-AYS72PRQ.js");
1072
+ if (errorMessage.includes("Login failed") || errorMessage.includes("authentication") || errorMessage.includes("password authentication")) {
1073
+ const { disconnect: disconnect2 } = await import("./db-OIJ2PJK6.js");
666
1074
  await disconnect2();
667
1075
  }
668
1076
  res.status(500).json({
@@ -671,6 +1079,24 @@ queryRoutes.post("/", async (req, res) => {
671
1079
  });
672
1080
  }
673
1081
  });
1082
+ queryRoutes.post("/cancel", async (req, res) => {
1083
+ try {
1084
+ const { queryId } = req.body;
1085
+ if (!queryId || typeof queryId !== "string") {
1086
+ return res.status(400).json({ error: "Query ID is required" });
1087
+ }
1088
+ const cancelled = cancelQuery(queryId);
1089
+ if (cancelled) {
1090
+ res.json({ success: true, message: "Query cancellation requested" });
1091
+ } else {
1092
+ res.status(404).json({ error: "Query not found or already completed" });
1093
+ }
1094
+ } catch (error) {
1095
+ res.status(500).json({
1096
+ error: error.message || "Failed to cancel query"
1097
+ });
1098
+ }
1099
+ });
674
1100
 
675
1101
  // src/server/index.ts
676
1102
  var __filename = fileURLToPath(import.meta.url);