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