datapeek 0.1.11 → 0.1.13

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 (97) hide show
  1. package/README.md +38 -9
  2. package/dist/cli/chunk-2I4MNNVK.js +628 -0
  3. package/dist/cli/chunk-4GDQ7VJZ.js +662 -0
  4. package/dist/cli/chunk-4MIQHH6K.js +47 -0
  5. package/dist/cli/chunk-6K3WSEIM.js +375 -0
  6. package/dist/cli/chunk-6PMCDR7J.js +628 -0
  7. package/dist/cli/chunk-B7K46745.js +605 -0
  8. package/dist/cli/chunk-CK2O76SG.js +713 -0
  9. package/dist/cli/chunk-FXOMCTFV.js +696 -0
  10. package/dist/cli/chunk-G4ID5SFT.js +628 -0
  11. package/dist/cli/chunk-GCVFEHSZ.js +708 -0
  12. package/dist/cli/chunk-LGE2JQ3S.js +628 -0
  13. package/dist/cli/chunk-NDLKLB5A.js +710 -0
  14. package/dist/cli/chunk-PG6I26XT.js +614 -0
  15. package/dist/cli/chunk-RK2Q2AX5.js +582 -0
  16. package/dist/cli/chunk-S5LRCCK6.js +582 -0
  17. package/dist/cli/chunk-UBFQXPPF.js +701 -0
  18. package/dist/cli/chunk-X2DQBOP6.js +712 -0
  19. package/dist/cli/chunk-XRMPVZIS.js +709 -0
  20. package/dist/cli/chunk-Z5G3UEXN.js +711 -0
  21. package/dist/cli/chunk-ZMP7S3G6.js +696 -0
  22. package/dist/cli/db-32TDDTFP.js +28 -0
  23. package/dist/cli/db-47O74DN5.js +34 -0
  24. package/dist/cli/db-4U22OWGB.js +29 -0
  25. package/dist/cli/db-CL72XDNO.js +34 -0
  26. package/dist/cli/db-CZCZOEID.js +28 -0
  27. package/dist/cli/db-IX3DXZ2C.js +34 -0
  28. package/dist/cli/db-LJCRTZTY.js +34 -0
  29. package/dist/cli/db-LNX4UMRF.js +28 -0
  30. package/dist/cli/db-NESFXDWL.js +28 -0
  31. package/dist/cli/db-OIJ2PJK6.js +34 -0
  32. package/dist/cli/db-OPAF6ZO3.js +28 -0
  33. package/dist/cli/db-PQURQHSK.js +28 -0
  34. package/dist/cli/db-QN5MTDYB.js +28 -0
  35. package/dist/cli/db-RBMUR3OK.js +34 -0
  36. package/dist/cli/db-REMUYLPP.js +34 -0
  37. package/dist/cli/db-RTHQ4ZAU.js +28 -0
  38. package/dist/cli/db-SHFLGGWD.js +28 -0
  39. package/dist/cli/db-ULMGZXQ5.js +34 -0
  40. package/dist/cli/db-YOGJ4LXE.js +28 -0
  41. package/dist/cli/dev.js +449 -374
  42. package/dist/cli/index.js +452 -376
  43. package/dist/cli/queryCancellation-4CMKYTFU.js +46 -0
  44. package/dist/cli/queryCancellation-E5O4FBUY.js +14 -0
  45. package/dist/client/assets/index-H7ji6dtA.js +385 -0
  46. package/dist/client/assets/index-TFw4Z1Ky.css +1 -0
  47. package/dist/client/index.html +2 -2
  48. package/dist/client/screenshots/dark1.png +0 -0
  49. package/dist/client/screenshots/dark2.png +0 -0
  50. package/dist/client/screenshots/light1.png +0 -0
  51. package/dist/client/screenshots/light2.png +0 -0
  52. package/dist/server/chunk-26GSUAI4.js +710 -0
  53. package/dist/server/chunk-36OOXHKI.js +659 -0
  54. package/dist/server/chunk-3DAIYH42.js +44 -0
  55. package/dist/server/chunk-4ELMZYWA.js +611 -0
  56. package/dist/server/chunk-5ESS5YBD.js +707 -0
  57. package/dist/server/chunk-7HIBWXBL.js +625 -0
  58. package/dist/server/chunk-BH22Q2FV.js +705 -0
  59. package/dist/server/chunk-CFU2CLKS.js +693 -0
  60. package/dist/server/chunk-CXA3HXTK.js +698 -0
  61. package/dist/server/chunk-DAUUXYQF.js +706 -0
  62. package/dist/server/chunk-FMSIEQ2T.js +579 -0
  63. package/dist/server/chunk-G6A463RM.js +625 -0
  64. package/dist/server/chunk-H6DUOXOK.js +625 -0
  65. package/dist/server/chunk-JCRZ6H7P.js +579 -0
  66. package/dist/server/chunk-L6LL3NE7.js +602 -0
  67. package/dist/server/chunk-TH6TUILG.js +709 -0
  68. package/dist/server/chunk-UJ2LRK25.js +373 -0
  69. package/dist/server/chunk-YI67PW64.js +625 -0
  70. package/dist/server/chunk-ZDZ2C5ZQ.js +693 -0
  71. package/dist/server/chunk-ZJOVVCPT.js +708 -0
  72. package/dist/server/db-22DQ6YG7.js +32 -0
  73. package/dist/server/db-3CBO6RHU.js +26 -0
  74. package/dist/server/db-3XN2KWYT.js +32 -0
  75. package/dist/server/db-3Y6K4EDP.js +26 -0
  76. package/dist/server/db-57HXNWPD.js +26 -0
  77. package/dist/server/db-5GCTDKYH.js +27 -0
  78. package/dist/server/db-5VQOTJ52.js +26 -0
  79. package/dist/server/db-B5L7VQ7E.js +32 -0
  80. package/dist/server/db-CJPCGHL3.js +32 -0
  81. package/dist/server/db-DAQ4BVCU.js +32 -0
  82. package/dist/server/db-EEA6EWHL.js +26 -0
  83. package/dist/server/db-KR7Z5M5V.js +32 -0
  84. package/dist/server/db-LMSBISDM.js +26 -0
  85. package/dist/server/db-LSOQE7N7.js +32 -0
  86. package/dist/server/db-NHBP6YLH.js +26 -0
  87. package/dist/server/db-OWVJVBBD.js +26 -0
  88. package/dist/server/db-TTVXKX7P.js +26 -0
  89. package/dist/server/db-YJ753EQV.js +26 -0
  90. package/dist/server/db-ZV6GZHFU.js +32 -0
  91. package/dist/server/dev.js +449 -374
  92. package/dist/server/index.js +449 -374
  93. package/dist/server/queryCancellation-M56DISJX.js +43 -0
  94. package/dist/server/queryCancellation-T2HSNMIV.js +12 -0
  95. package/package.json +3 -1
  96. package/dist/client/assets/index-CPoX5Biw.css +0 -1
  97. package/dist/client/assets/index-KtK9Gzwi.js +0 -375
@@ -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) {
120
141
  return res.status(400).json({ error: "Not connected to database" });
121
142
  }
143
+ const isConnected = "connected" in pool ? pool.connected === true : !pool.ended;
144
+ if (!isConnected) {
145
+ return res.status(400).json({ error: "Not connected to database" });
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) {
146
174
  return res.status(400).json({ error: "Not connected to database" });
147
175
  }
176
+ const isConnected = "connected" in pool ? pool.connected === true : !pool.ended;
177
+ if (!isConnected) {
178
+ return res.status(400).json({ error: "Not connected to database" });
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" });
@@ -262,28 +295,35 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
262
295
  }
263
296
  console.log("Parsed filters:", parsedFilters);
264
297
  const pool = getConnection();
265
- 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) {
266
303
  return res.status(400).json({ error: "Not connected to database" });
267
304
  }
305
+ const dialect = getDialect();
268
306
  const columnMetadata = {};
269
307
  if (parsedFilters.length > 0) {
270
308
  try {
271
309
  const columnNames = [...new Set(parsedFilters.map((f) => f.column))];
272
- const placeholders = columnNames.map((_, i) => `@col${i}`).join(", ");
310
+ const placeholders = columnNames.map((_, i) => dialect.param(i + 3)).join(", ");
273
311
  const validateQuery = `
274
- SELECT COLUMN_NAME, DATA_TYPE
275
- FROM INFORMATION_SCHEMA.COLUMNS
276
- 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})
277
315
  `;
278
316
  const validateParams = [
279
- { name: "schema", value: schema, type: sql.NVarChar },
280
- { name: "table", value: table, type: sql.NVarChar },
281
- ...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 }))
282
320
  ];
283
321
  const validateResult = await executeQuery(validateQuery, validateParams);
284
322
  validateResult.forEach((r) => {
285
- columnMetadata[r.COLUMN_NAME] = {
286
- dataType: r.DATA_TYPE,
323
+ const colName = r.column_name || r.COLUMN_NAME;
324
+ const dataType = r.data_type || r.DATA_TYPE;
325
+ columnMetadata[colName] = {
326
+ dataType,
287
327
  exists: true
288
328
  };
289
329
  });
@@ -292,24 +332,9 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
292
332
  console.error("Error validating filter columns:", e);
293
333
  }
294
334
  }
295
- const getSqlType = (dataType) => {
296
- const dt = dataType.toLowerCase();
297
- if (dt === "int" || dt === "integer") return sql.Int;
298
- if (dt === "bigint") return sql.BigInt;
299
- if (dt === "smallint") return sql.SmallInt;
300
- if (dt === "tinyint") return sql.TinyInt;
301
- if (dt === "bit") return sql.Bit;
302
- if (dt === "float" || dt === "real" || dt === "double precision") return sql.Float;
303
- if (dt === "decimal" || dt === "numeric" || dt === "money" || dt === "smallmoney") return sql.Decimal(18, 2);
304
- if (dt === "datetime" || dt === "datetime2" || dt === "smalldatetime") return sql.DateTime;
305
- if (dt === "date") return sql.Date;
306
- if (dt === "time") return sql.Time;
307
- if (dt === "uniqueidentifier") return sql.UniqueIdentifier;
308
- return sql.NVarChar;
309
- };
310
335
  let whereClause = "";
311
336
  const filterParams = [];
312
- let paramIndex = 0;
337
+ let paramIndex = 1;
313
338
  if (parsedFilters.length > 0) {
314
339
  const whereConditions = [];
315
340
  parsedFilters.forEach((filter) => {
@@ -325,83 +350,82 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
325
350
  if (value === null || value === void 0 || value === "") {
326
351
  return;
327
352
  }
328
- const sqlType = getSqlType(dataType);
329
- const paramName = `filter${paramIndex}`;
353
+ const quotedColumn = dialect.quoteId(columnName);
330
354
  try {
331
355
  let condition = "";
332
356
  switch (operator) {
333
357
  // Text operators
334
358
  case "contains":
335
- filterParams.push({ name: paramName, value: `%${String(value)}%`, type: sql.NVarChar });
336
- condition = `[${columnName}] LIKE @${paramName}`;
359
+ filterParams.push({ name: `filter${paramIndex}`, value: `%${String(value)}%` });
360
+ condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
337
361
  break;
338
362
  case "equals":
339
- filterParams.push({ name: paramName, value: String(value), type: sqlType });
340
- condition = `[${columnName}] = @${paramName}`;
363
+ filterParams.push({ name: `filter${paramIndex}`, value: String(value) });
364
+ condition = `${quotedColumn} = ${dialect.param(paramIndex)}`;
341
365
  break;
342
366
  case "startsWith":
343
- filterParams.push({ name: paramName, value: `${String(value)}%`, type: sql.NVarChar });
344
- condition = `[${columnName}] LIKE @${paramName}`;
367
+ filterParams.push({ name: `filter${paramIndex}`, value: `${String(value)}%` });
368
+ condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
345
369
  break;
346
370
  case "endsWith":
347
- filterParams.push({ name: paramName, value: `%${String(value)}`, type: sql.NVarChar });
348
- condition = `[${columnName}] LIKE @${paramName}`;
371
+ filterParams.push({ name: `filter${paramIndex}`, value: `%${String(value)}` });
372
+ condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
349
373
  break;
350
374
  case "notContains":
351
- filterParams.push({ name: paramName, value: `%${String(value)}%`, type: sql.NVarChar });
352
- condition = `[${columnName}] NOT LIKE @${paramName}`;
375
+ filterParams.push({ name: `filter${paramIndex}`, value: `%${String(value)}%` });
376
+ condition = `${quotedColumn} NOT LIKE ${dialect.param(paramIndex)}`;
353
377
  break;
354
378
  // Number operators
355
379
  case "eq":
356
- filterParams.push({ name: paramName, value: Number(value), type: sqlType });
357
- condition = `[${columnName}] = @${paramName}`;
380
+ filterParams.push({ name: `filter${paramIndex}`, value: Number(value) });
381
+ condition = `${quotedColumn} = ${dialect.param(paramIndex)}`;
358
382
  break;
359
383
  case "gt":
360
- filterParams.push({ name: paramName, value: Number(value), type: sqlType });
361
- condition = `[${columnName}] > @${paramName}`;
384
+ filterParams.push({ name: `filter${paramIndex}`, value: Number(value) });
385
+ condition = `${quotedColumn} > ${dialect.param(paramIndex)}`;
362
386
  break;
363
387
  case "gte":
364
- filterParams.push({ name: paramName, value: Number(value), type: sqlType });
365
- condition = `[${columnName}] >= @${paramName}`;
388
+ filterParams.push({ name: `filter${paramIndex}`, value: Number(value) });
389
+ condition = `${quotedColumn} >= ${dialect.param(paramIndex)}`;
366
390
  break;
367
391
  case "lt":
368
- filterParams.push({ name: paramName, value: Number(value), type: sqlType });
369
- condition = `[${columnName}] < @${paramName}`;
392
+ filterParams.push({ name: `filter${paramIndex}`, value: Number(value) });
393
+ condition = `${quotedColumn} < ${dialect.param(paramIndex)}`;
370
394
  break;
371
395
  case "lte":
372
- filterParams.push({ name: paramName, value: Number(value), type: sqlType });
373
- condition = `[${columnName}] <= @${paramName}`;
396
+ filterParams.push({ name: `filter${paramIndex}`, value: Number(value) });
397
+ condition = `${quotedColumn} <= ${dialect.param(paramIndex)}`;
374
398
  break;
375
399
  case "between":
376
400
  if (typeof value === "object" && "from" in value && "to" in value) {
377
- const fromParam = `filter${paramIndex}`;
378
- const toParam = `filter${paramIndex + 1}`;
379
- filterParams.push({ name: fromParam, value: Number(value.from), type: sqlType });
380
- filterParams.push({ name: toParam, value: Number(value.to), type: sqlType });
381
- condition = `[${columnName}] BETWEEN @${fromParam} AND @${toParam}`;
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)}`;
382
406
  paramIndex++;
383
407
  }
384
408
  break;
385
409
  // Date operators
386
410
  case "dateEq":
387
- filterParams.push({ name: paramName, value: String(value), type: sqlType });
388
- condition = `CAST([${columnName}] AS DATE) = CAST(@${paramName} AS DATE)`;
411
+ filterParams.push({ name: `filter${paramIndex}`, value: String(value) });
412
+ condition = `${dialect.castToDate(quotedColumn)} = ${dialect.castToDate(dialect.param(paramIndex))}`;
389
413
  break;
390
414
  case "dateAfter":
391
- filterParams.push({ name: paramName, value: String(value), type: sqlType });
392
- condition = `CAST([${columnName}] AS DATE) > CAST(@${paramName} AS DATE)`;
415
+ filterParams.push({ name: `filter${paramIndex}`, value: String(value) });
416
+ condition = `${dialect.castToDate(quotedColumn)} > ${dialect.castToDate(dialect.param(paramIndex))}`;
393
417
  break;
394
418
  case "dateBefore":
395
- filterParams.push({ name: paramName, value: String(value), type: sqlType });
396
- condition = `CAST([${columnName}] AS DATE) < CAST(@${paramName} AS DATE)`;
419
+ filterParams.push({ name: `filter${paramIndex}`, value: String(value) });
420
+ condition = `${dialect.castToDate(quotedColumn)} < ${dialect.castToDate(dialect.param(paramIndex))}`;
397
421
  break;
398
422
  case "dateBetween":
399
423
  if (typeof value === "object" && "from" in value && "to" in value) {
400
- const fromParam = `filter${paramIndex}`;
401
- const toParam = `filter${paramIndex + 1}`;
402
- filterParams.push({ name: fromParam, value: String(value.from), type: sqlType });
403
- filterParams.push({ name: toParam, value: String(value.to), type: sqlType });
404
- condition = `CAST([${columnName}] AS DATE) BETWEEN CAST(@${fromParam} AS DATE) AND CAST(@${toParam} AS DATE)`;
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))}`;
405
429
  paramIndex++;
406
430
  }
407
431
  break;
@@ -409,19 +433,21 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
409
433
  case "in":
410
434
  case "notIn":
411
435
  if (Array.isArray(value) && value.length > 0) {
412
- const placeholders = value.map((_, i) => `@${paramName}_${i}`).join(", ");
436
+ const placeholders = [];
413
437
  value.forEach((val, i) => {
414
- filterParams.push({ name: `${paramName}_${i}`, value: val, type: sqlType });
438
+ const currentIndex = paramIndex + i;
439
+ filterParams.push({ name: `filter${currentIndex}`, value: val });
440
+ placeholders.push(dialect.param(currentIndex));
415
441
  });
416
442
  const inOperator = operator === "in" ? "IN" : "NOT IN";
417
- condition = `[${columnName}] ${inOperator} (${placeholders})`;
443
+ condition = `${quotedColumn} ${inOperator} (${placeholders.join(", ")})`;
418
444
  paramIndex += value.length - 1;
419
445
  }
420
446
  break;
421
447
  default:
422
448
  console.warn(`Unknown filter operator: ${operator}, falling back to contains`);
423
- filterParams.push({ name: paramName, value: `%${String(value)}%`, type: sql.NVarChar });
424
- condition = `[${columnName}] LIKE @${paramName}`;
449
+ filterParams.push({ name: `filter${paramIndex}`, value: `%${String(value)}%` });
450
+ condition = `${quotedColumn} LIKE ${dialect.param(paramIndex)}`;
425
451
  }
426
452
  if (condition) {
427
453
  whereConditions.push(condition);
@@ -438,11 +464,13 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
438
464
  }
439
465
  }
440
466
  const qualifiedDataWhereClause = parsedFilters.reduce((clause, filter) => {
441
- const escapedColumn = filter.column.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
442
- const pattern = new RegExp(`\\[${escapedColumn}\\]`, "g");
443
- return clause.replace(pattern, `[t].[${filter.column}]`);
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);
444
470
  }, whereClause);
445
- const countQuery = `SELECT COUNT(*) as total FROM [${schema}].[${table}]${whereClause ? " " + 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 : ""}`;
446
474
  const countResult = await executeQuery(countQuery, filterParams.length > 0 ? filterParams : []);
447
475
  const total = countResult[0]?.total || 0;
448
476
  let orderByColumn = sortColumn || "";
@@ -450,17 +478,19 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
450
478
  if (orderByColumn) {
451
479
  try {
452
480
  const validateQuery = `
453
- SELECT COLUMN_NAME
454
- FROM INFORMATION_SCHEMA.COLUMNS
455
- 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)}
456
484
  `;
457
485
  const validateResult = await executeQuery(validateQuery, [
458
- { name: "schema", value: schema, type: sql.NVarChar },
459
- { name: "table", value: table, type: sql.NVarChar },
460
- { name: "column", value: orderByColumn, type: sql.NVarChar }
486
+ { name: "schema", value: schema },
487
+ { name: "table", value: table },
488
+ { name: "column", value: orderByColumn }
461
489
  ]);
462
490
  if (validateResult.length === 0) {
463
491
  orderByColumn = "";
492
+ } else {
493
+ orderByColumn = validateResult[0].column_name || validateResult[0].COLUMN_NAME || orderByColumn;
464
494
  }
465
495
  } catch (e) {
466
496
  orderByColumn = "";
@@ -468,18 +498,20 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
468
498
  }
469
499
  if (!orderByColumn) {
470
500
  try {
501
+ const topClause = dialect.topN(1);
471
502
  const structureQuery = `
472
- SELECT TOP 1 COLUMN_NAME
473
- FROM INFORMATION_SCHEMA.COLUMNS
474
- WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table
475
- 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) : ""}
476
508
  `;
477
509
  const structureResult = await executeQuery(structureQuery, [
478
- { name: "schema", value: schema, type: sql.NVarChar },
479
- { name: "table", value: table, type: sql.NVarChar }
510
+ { name: "schema", value: schema },
511
+ { name: "table", value: table }
480
512
  ]);
481
513
  if (structureResult.length > 0) {
482
- orderByColumn = structureResult[0].COLUMN_NAME;
514
+ orderByColumn = structureResult[0].column_name || structureResult[0].COLUMN_NAME;
483
515
  }
484
516
  } catch (e) {
485
517
  }
@@ -489,48 +521,48 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
489
521
  const fkDisplayColumns = {};
490
522
  const fkQuery = `
491
523
  SELECT
492
- kcu1.COLUMN_NAME as fkColumnName,
493
- kcu2.TABLE_SCHEMA as referencedSchema,
494
- kcu2.TABLE_NAME as referencedTable,
495
- kcu2.COLUMN_NAME as referencedColumn
496
- FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
497
- INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu1
498
- ON rc.CONSTRAINT_CATALOG = kcu1.CONSTRAINT_CATALOG
499
- AND rc.CONSTRAINT_SCHEMA = kcu1.CONSTRAINT_SCHEMA
500
- AND rc.CONSTRAINT_NAME = kcu1.CONSTRAINT_NAME
501
- INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu2
502
- ON rc.UNIQUE_CONSTRAINT_CATALOG = kcu2.CONSTRAINT_CATALOG
503
- AND rc.UNIQUE_CONSTRAINT_SCHEMA = kcu2.CONSTRAINT_SCHEMA
504
- AND rc.UNIQUE_CONSTRAINT_NAME = kcu2.CONSTRAINT_NAME
505
- AND kcu1.ORDINAL_POSITION = kcu2.ORDINAL_POSITION
506
- WHERE kcu1.TABLE_SCHEMA = @schema
507
- 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)}
508
540
  `;
509
541
  console.log("Fetching foreign keys with query:", fkQuery);
510
542
  const foreignKeys = await executeQuery(fkQuery, [
511
- { name: "schema", value: schema, type: sql.NVarChar },
512
- { name: "table", value: table, type: sql.NVarChar }
543
+ { name: "schema", value: schema },
544
+ { name: "table", value: table }
513
545
  ]);
514
546
  console.log(`Found ${foreignKeys.length} foreign key(s)`);
515
547
  if (foreignKeys.length > 0) {
516
548
  const uniqueRefTables = Array.from(
517
- new Set(foreignKeys.map((fk) => `${fk.referencedSchema}.${fk.referencedTable}`))
549
+ new Set(foreignKeys.map((fk) => `${fk.referencedSchema || fk.referenced_schema}.${fk.referencedTable || fk.referenced_table}`))
518
550
  );
519
551
  const tableConditions = uniqueRefTables.map((tableRef, idx) => {
520
552
  const [refSchema, refTable] = tableRef.split(".");
521
- return `(TABLE_SCHEMA = @refSchema${idx} AND TABLE_NAME = @refTable${idx})`;
553
+ return `(table_schema = ${dialect.param(idx * 2 + 1)} AND table_name = ${dialect.param(idx * 2 + 2)})`;
522
554
  }).join(" OR ");
523
555
  const batchColumnsQuery = `
524
- SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, ORDINAL_POSITION
525
- FROM INFORMATION_SCHEMA.COLUMNS
556
+ SELECT table_schema, table_name, column_name, data_type, ordinal_position
557
+ FROM information_schema.columns
526
558
  WHERE ${tableConditions}
527
- ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION
559
+ ORDER BY table_schema, table_name, ordinal_position
528
560
  `;
529
- const batchParams = uniqueRefTables.flatMap((tableRef, idx) => {
561
+ const batchParams = uniqueRefTables.flatMap((tableRef) => {
530
562
  const [refSchema, refTable] = tableRef.split(".");
531
563
  return [
532
- { name: `refSchema${idx}`, value: refSchema, type: sql.NVarChar },
533
- { name: `refTable${idx}`, value: refTable, type: sql.NVarChar }
564
+ { name: "refSchema", value: refSchema },
565
+ { name: "refTable", value: refTable }
534
566
  ];
535
567
  });
536
568
  console.log("Fetching referenced table columns with query:", batchColumnsQuery);
@@ -539,37 +571,41 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
539
571
  console.log(`Found columns for ${uniqueRefTables.length} referenced table(s)`);
540
572
  const columnsByTable = {};
541
573
  allRefColumns.forEach((col) => {
542
- const key = `${col.TABLE_SCHEMA}.${col.TABLE_NAME}`;
574
+ const schemaName = col.table_schema || col.TABLE_SCHEMA;
575
+ const tableName = col.table_name || col.TABLE_NAME;
576
+ const key = `${schemaName}.${tableName}`;
543
577
  if (!columnsByTable[key]) {
544
578
  columnsByTable[key] = [];
545
579
  }
546
580
  columnsByTable[key].push(col);
547
581
  });
548
582
  for (const fk of foreignKeys) {
549
- const fkColumn = fk.fkColumnName;
550
- const refSchema = fk.referencedSchema;
551
- const refTable = fk.referencedTable;
552
- const refColumn = fk.referencedColumn;
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;
553
587
  const tableKey = `${refSchema}.${refTable}`;
554
588
  const refColumns = columnsByTable[tableKey] || [];
555
589
  const preferredNames = ["name", "title", "description", "code"];
556
590
  let displayColumn = null;
557
591
  for (const preferredName of preferredNames) {
558
- const found = refColumns.find(
559
- (col) => col.COLUMN_NAME.toLowerCase() === preferredName.toLowerCase()
560
- );
592
+ const found = refColumns.find((col) => {
593
+ const colName = col.column_name || col.COLUMN_NAME;
594
+ return colName.toLowerCase() === preferredName.toLowerCase();
595
+ });
561
596
  if (found) {
562
- displayColumn = found.COLUMN_NAME;
597
+ displayColumn = found.column_name || found.COLUMN_NAME;
563
598
  break;
564
599
  }
565
600
  }
566
601
  if (!displayColumn) {
567
602
  const stringTypes = ["varchar", "nvarchar", "char", "nchar", "text", "ntext"];
568
- const found = refColumns.find(
569
- (col) => stringTypes.some((type) => col.DATA_TYPE.toLowerCase().includes(type))
570
- );
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
+ });
571
607
  if (found) {
572
- displayColumn = found.COLUMN_NAME;
608
+ displayColumn = found.column_name || found.COLUMN_NAME;
573
609
  }
574
610
  }
575
611
  if (displayColumn) {
@@ -583,89 +619,79 @@ tableRoutes.get("/:schema/:table/data", async (req, res) => {
583
619
  refColumn,
584
620
  displayColumn
585
621
  });
586
- fkSelects.push(`${alias}.[${displayColumn}] as [${fkColumn}_display]`);
622
+ fkSelects.push(`${dialect.quoteId(alias)}.${dialect.quoteId(displayColumn)} as ${dialect.quoteId(`${fkColumn}_display`)}`);
587
623
  }
588
624
  fkDisplayColumns[fkColumn] = displayColumn;
589
625
  }
590
626
  }
591
627
  }
592
628
  const baseTableAlias = "t";
593
- let baseSelects = `[${baseTableAlias}].*`;
629
+ const quotedTableAlias = dialect.quoteId(baseTableAlias);
630
+ let baseSelects = `${quotedTableAlias}.*`;
594
631
  if (fkDisplayMode === "display-only") {
595
632
  const fkColumnNames = fkJoins.map((fk) => fk.fkColumn);
596
633
  if (fkColumnNames.length > 0) {
597
- baseSelects = `[${baseTableAlias}].*`;
634
+ baseSelects = `${quotedTableAlias}.*`;
598
635
  }
599
636
  }
600
637
  const allSelects = `${baseSelects}${fkSelects.length > 0 ? ", " + fkSelects.join(", ") : ""}`;
601
638
  const buildJoinClauses = (tableAlias) => {
602
- return fkJoins.map(
603
- (fk) => `LEFT JOIN [${fk.refSchema}].[${fk.refTable}] ${fk.alias} ON [${tableAlias}].[${fk.fkColumn}] = ${fk.alias}.[${fk.refColumn}]`
604
- ).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 ");
605
648
  };
606
649
  let data;
607
650
  let generatedQuery = "";
651
+ const offsetParamIndex = filterParams.length + 1;
652
+ const pageSizeParamIndex = filterParams.length + 2;
608
653
  if (orderByColumn) {
654
+ const quotedOrderByColumn = dialect.quoteId(orderByColumn);
655
+ const limitOffsetClause = dialect.limitOffset(offset, pageSize);
609
656
  const dataQuery = `
610
657
  SELECT ${allSelects}
611
- FROM [${schema}].[${table}] ${baseTableAlias}
658
+ FROM ${quotedSchema}.${quotedTable} ${quotedTableAlias}
612
659
  ${buildJoinClauses(baseTableAlias)}
613
660
  ${qualifiedDataWhereClause}
614
- ORDER BY ${baseTableAlias}.[${orderByColumn}] ${orderByDirection}
615
- OFFSET @offset ROWS
616
- FETCH NEXT @pageSize ROWS ONLY
661
+ ORDER BY ${quotedTableAlias}.${quotedOrderByColumn} ${orderByDirection}
662
+ ${limitOffsetClause}
617
663
  `;
618
664
  generatedQuery = `SELECT ${allSelects}
619
- FROM [${schema}].[${table}] ${baseTableAlias}${fkJoins.length > 0 ? "\n" + buildJoinClauses(baseTableAlias) : ""}${qualifiedDataWhereClause ? "\n" + qualifiedDataWhereClause : ""}
620
- ORDER BY ${baseTableAlias}.[${orderByColumn}] ${orderByDirection}
621
- OFFSET ${offset} ROWS
622
- 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}`;
623
668
  console.log("Executing SQL query:", dataQuery);
624
669
  console.log("Query parameters:", {
625
670
  offset,
626
671
  pageSize,
627
672
  filterParams: filterParams.map((p) => ({ name: p.name, value: p.value }))
628
673
  });
629
- data = await executeQuery(dataQuery, [
630
- { name: "offset", value: offset, type: sql.Int },
631
- { name: "pageSize", value: pageSize, type: sql.Int },
632
- ...filterParams
633
- ]);
674
+ data = await executeQuery(dataQuery, filterParams);
634
675
  } else {
635
- const innerQuery = `
636
- SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as rn
637
- FROM [${schema}].[${table}]
638
- ${whereClause}
639
- `;
676
+ const dbType = getDbType();
677
+ const limitOffsetClause = dialect.limitOffset(offset, pageSize);
640
678
  const dataQuery = `
641
679
  SELECT ${allSelects}
642
- FROM (${innerQuery}) ${baseTableAlias}
680
+ FROM ${quotedSchema}.${quotedTable} ${quotedTableAlias}
643
681
  ${buildJoinClauses(baseTableAlias)}
644
- WHERE ${baseTableAlias}.rn > @offset AND ${baseTableAlias}.rn <= @offset + @pageSize
645
- ORDER BY ${baseTableAlias}.rn
682
+ ${qualifiedDataWhereClause}
683
+ ${limitOffsetClause}
646
684
  `;
647
685
  generatedQuery = `SELECT ${allSelects}
648
- FROM (
649
- SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as rn
650
- FROM [${schema}].[${table}]${whereClause ? "\n " + whereClause : ""}
651
- ) ${baseTableAlias}${fkJoins.length > 0 ? "\n" + buildJoinClauses(baseTableAlias) : ""}
652
- WHERE ${baseTableAlias}.rn > ${offset} AND ${baseTableAlias}.rn <= ${offset + pageSize}
653
- ORDER BY ${baseTableAlias}.rn`;
686
+ FROM ${quotedSchema}.${quotedTable} ${quotedTableAlias}${fkJoins.length > 0 ? "\n" + buildJoinClauses(baseTableAlias) : ""}${qualifiedDataWhereClause ? "\n" + qualifiedDataWhereClause : ""}
687
+ ${limitOffsetClause}`;
654
688
  console.log("Executing SQL query:", dataQuery);
655
689
  console.log("Query parameters:", {
656
690
  offset,
657
691
  pageSize,
658
692
  filterParams: filterParams.map((p) => ({ name: p.name, value: p.value }))
659
693
  });
660
- data = await executeQuery(dataQuery, [
661
- { name: "offset", value: offset, type: sql.Int },
662
- { name: "pageSize", value: pageSize, type: sql.Int },
663
- ...filterParams
664
- ]);
665
- data = data.map((row) => {
666
- const { rn, ...rest } = row;
667
- return rest;
668
- });
694
+ data = await executeQuery(dataQuery, filterParams);
669
695
  }
670
696
  if (fkDisplayMode === "display-only") {
671
697
  const fkColumnNames = fkJoins.map((fk) => fk.fkColumn);
@@ -693,10 +719,22 @@ ORDER BY ${baseTableAlias}.rn`;
693
719
  const paramValues = new Map(
694
720
  filterParams.map((p) => [p.name, p.value])
695
721
  );
696
- generatedQuery = generatedQuery.replace(/@([A-Za-z0-9_]+)/g, (full, name) => {
697
- if (!paramValues.has(name)) return full;
698
- return formatSqlLiteral(paramValues.get(name));
699
- });
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
+ }
700
738
  }
701
739
  res.json({
702
740
  data,
@@ -713,8 +751,8 @@ ORDER BY ${baseTableAlias}.rn`;
713
751
  } catch (error) {
714
752
  console.error("Error fetching table data:", error);
715
753
  const errorMessage = error.message || "";
716
- if (errorMessage.includes("Login failed") || errorMessage.includes("authentication")) {
717
- 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");
718
756
  await disconnect2();
719
757
  }
720
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";
@@ -741,73 +779,68 @@ tableRoutes.post("/:schema/:table/related-data", async (req, res) => {
741
779
  return res.status(400).json({ error: "Missing required parameters" });
742
780
  }
743
781
  const pool = getConnection();
744
- if (!pool || !pool.connected) {
782
+ if (!pool) {
745
783
  return res.status(400).json({ error: "Not connected to database" });
746
784
  }
785
+ const isConnected = "connected" in pool ? pool.connected === true : !pool.ended;
786
+ if (!isConnected) {
787
+ return res.status(400).json({ error: "Not connected to database" });
788
+ }
789
+ const dialect = getDialect();
747
790
  const columnsQuery = `
748
- SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH
749
- FROM INFORMATION_SCHEMA.COLUMNS
750
- WHERE TABLE_SCHEMA = @refSchema
751
- AND TABLE_NAME = @refTable
752
- 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
753
796
  `;
754
797
  const columns = await executeQuery(columnsQuery, [
755
- { name: "refSchema", value: referencedSchema, type: sql.NVarChar },
756
- { name: "refTable", value: referencedTable, type: sql.NVarChar }
798
+ { name: "refSchema", value: referencedSchema },
799
+ { name: "refTable", value: referencedTable }
757
800
  ]);
758
- const referencedColInfo = columns.find(
759
- (col) => col.COLUMN_NAME === referencedColumn
760
- );
801
+ const referencedColInfo = columns.find((col) => {
802
+ const colName = col.column_name || col.COLUMN_NAME;
803
+ return colName === referencedColumn;
804
+ });
761
805
  if (!referencedColInfo) {
762
806
  return res.status(400).json({ error: `Referenced column '${referencedColumn}' not found` });
763
807
  }
764
- const getSqlType = (dataType) => {
765
- const dt = dataType.toLowerCase();
766
- if (dt === "int" || dt === "integer") return sql.Int;
767
- if (dt === "bigint") return sql.BigInt;
768
- if (dt === "smallint") return sql.SmallInt;
769
- if (dt === "tinyint") return sql.TinyInt;
770
- if (dt === "bit") return sql.Bit;
771
- if (dt === "float" || dt === "real" || dt === "double precision") return sql.Float;
772
- if (dt === "decimal" || dt === "numeric" || dt === "money" || dt === "smallmoney") return sql.Decimal(18, 0);
773
- if (dt === "datetime" || dt === "datetime2" || dt === "smalldatetime") return sql.DateTime;
774
- if (dt === "date") return sql.Date;
775
- if (dt === "time") return sql.Time;
776
- if (dt === "uniqueidentifier") return sql.UniqueIdentifier;
777
- return sql.NVarChar;
778
- };
779
- const referencedColumnType = getSqlType(referencedColInfo.DATA_TYPE);
780
808
  const preferredNames = ["name", "title", "description", "code"];
781
809
  let displayColumn = null;
782
810
  for (const preferredName of preferredNames) {
783
- const found = columns.find(
784
- (col) => col.COLUMN_NAME.toLowerCase() === preferredName.toLowerCase()
785
- );
811
+ const found = columns.find((col) => {
812
+ const colName = col.column_name || col.COLUMN_NAME;
813
+ return colName.toLowerCase() === preferredName.toLowerCase();
814
+ });
786
815
  if (found) {
787
- displayColumn = found.COLUMN_NAME;
816
+ displayColumn = found.column_name || found.COLUMN_NAME;
788
817
  break;
789
818
  }
790
819
  }
791
820
  if (!displayColumn) {
792
821
  const stringTypes = ["varchar", "nvarchar", "char", "nchar", "text", "ntext"];
793
- const found = columns.find(
794
- (col) => stringTypes.some((type) => col.DATA_TYPE.toLowerCase().includes(type))
795
- );
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
+ });
796
826
  if (found) {
797
- displayColumn = found.COLUMN_NAME;
827
+ displayColumn = found.column_name || found.COLUMN_NAME;
798
828
  }
799
829
  }
800
- const placeholders = ids.map((_, i) => `@id${i}`).join(", ");
801
- 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;
802
836
  const dataQuery = `
803
837
  SELECT ${selectColumns}
804
- FROM [${referencedSchema}].[${referencedTable}]
805
- WHERE [${referencedColumn}] IN (${placeholders})
838
+ FROM ${quotedRefSchema}.${quotedRefTable}
839
+ WHERE ${quotedRefColumn} IN (${placeholders})
806
840
  `;
807
- const params = ids.map((id, i) => ({
808
- name: `id${i}`,
809
- value: id,
810
- type: referencedColumnType
841
+ const params = ids.map((id) => ({
842
+ name: "id",
843
+ value: id
811
844
  }));
812
845
  const result = await executeQuery(dataQuery, params);
813
846
  const dataMap = {};
@@ -819,8 +852,8 @@ tableRoutes.post("/:schema/:table/related-data", async (req, res) => {
819
852
  } catch (error) {
820
853
  console.error("Error fetching related data:", error);
821
854
  const errorMessage = error.message || "";
822
- if (errorMessage.includes("Login failed") || errorMessage.includes("authentication")) {
823
- 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");
824
857
  await disconnect2();
825
858
  }
826
859
  res.status(500).json({ error: error.message || "Failed to fetch related data" });
@@ -832,148 +865,163 @@ tableRoutes.get("/:schema/:table/distinct-values/:column", async (req, res) => {
832
865
  const searchQuery = req.query.search;
833
866
  const columnsParam = req.query.columns;
834
867
  const pool = getConnection();
835
- if (!pool || !pool.connected) {
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) {
836
873
  return res.status(400).json({ error: "Not connected to database" });
837
874
  }
875
+ const dialect = getDialect();
838
876
  const columnQuery = `
839
877
  SELECT
840
- c.COLUMN_NAME,
841
- c.DATA_TYPE,
842
- fk.REFERENCED_TABLE_SCHEMA as referencedSchema,
843
- fk.REFERENCED_TABLE_NAME as referencedTable,
844
- fk.REFERENCED_COLUMN_NAME as referencedColumn
845
- FROM INFORMATION_SCHEMA.COLUMNS c
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
846
884
  LEFT JOIN (
847
885
  SELECT
848
- kcu1.TABLE_SCHEMA,
849
- kcu1.TABLE_NAME,
850
- kcu1.COLUMN_NAME,
851
- kcu2.TABLE_SCHEMA as REFERENCED_TABLE_SCHEMA,
852
- kcu2.TABLE_NAME as REFERENCED_TABLE_NAME,
853
- kcu2.COLUMN_NAME as REFERENCED_COLUMN_NAME
854
- FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
855
- INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu1
856
- ON rc.CONSTRAINT_CATALOG = kcu1.CONSTRAINT_CATALOG
857
- AND rc.CONSTRAINT_SCHEMA = kcu1.CONSTRAINT_SCHEMA
858
- AND rc.CONSTRAINT_NAME = kcu1.CONSTRAINT_NAME
859
- INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu2
860
- ON rc.UNIQUE_CONSTRAINT_CATALOG = kcu2.CONSTRAINT_CATALOG
861
- AND rc.UNIQUE_CONSTRAINT_SCHEMA = kcu2.CONSTRAINT_SCHEMA
862
- AND rc.UNIQUE_CONSTRAINT_NAME = kcu2.CONSTRAINT_NAME
863
- AND kcu1.ORDINAL_POSITION = kcu2.ORDINAL_POSITION
864
- ) fk ON c.TABLE_SCHEMA = fk.TABLE_SCHEMA
865
- AND c.TABLE_NAME = fk.TABLE_NAME
866
- AND c.COLUMN_NAME = fk.COLUMN_NAME
867
- WHERE c.TABLE_SCHEMA = @schema AND c.TABLE_NAME = @table AND c.COLUMN_NAME = @column
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)}
868
906
  `;
869
907
  const columnResult = await executeQuery(columnQuery, [
870
- { name: "schema", value: schema, type: sql.NVarChar },
871
- { name: "table", value: table, type: sql.NVarChar },
872
- { name: "column", value: column, type: sql.NVarChar }
908
+ { name: "schema", value: schema },
909
+ { name: "table", value: table },
910
+ { name: "column", value: column }
873
911
  ]);
874
912
  if (columnResult.length === 0) {
875
913
  return res.status(400).json({ error: "Column not found" });
876
914
  }
877
915
  const columnInfo = columnResult[0];
878
- const isForeignKey = !!columnInfo.referencedSchema && !!columnInfo.referencedTable;
916
+ const isForeignKey = !!(columnInfo.referencedSchema || columnInfo.referenced_schema) && !!(columnInfo.referencedTable || columnInfo.referenced_table);
879
917
  let query = "";
880
918
  const params = [];
881
919
  let displayColumn = null;
882
920
  if (isForeignKey) {
883
- const refSchema = columnInfo.referencedSchema;
884
- const refTable = columnInfo.referencedTable;
885
- const refColumn = columnInfo.referencedColumn;
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);
886
927
  let columnsToSelect = [];
887
928
  if (columnsParam) {
888
929
  columnsToSelect = columnsParam.split(",").map((c) => c.trim()).filter((c) => c);
889
930
  }
890
931
  if (columnsToSelect.length > 0) {
891
- const selectCols = columnsToSelect.map((col) => `[${col}]`).join(", ");
892
- query = `SELECT DISTINCT ${selectCols} FROM [${refSchema}].[${refTable}]`;
932
+ const selectCols = columnsToSelect.map((col) => dialect.quoteId(col)).join(", ");
933
+ query = `SELECT DISTINCT ${selectCols} FROM ${quotedRefSchema}.${quotedRefTable}`;
893
934
  if (searchQuery && searchQuery.trim()) {
894
- const searchCols = columnsToSelect.map((col) => `[${col}] LIKE @search`).join(" OR ");
895
- query += ` WHERE (${searchCols}) AND [${refColumn}] IS NOT NULL`;
896
- params.push({ name: "search", value: `%${searchQuery.trim()}%`, type: sql.NVarChar });
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()}%` });
897
938
  } else {
898
- query += ` WHERE [${refColumn}] IS NOT NULL`;
939
+ query += ` WHERE ${quotedRefColumn} IS NOT NULL`;
899
940
  }
900
941
  const orderByCol = columnsToSelect.length > 1 ? columnsToSelect[1] : columnsToSelect[0];
901
- query += ` ORDER BY [${orderByCol}] OFFSET 0 ROWS FETCH NEXT 1000 ROWS ONLY`;
942
+ query += ` ORDER BY ${dialect.quoteId(orderByCol)} ${dialect.limitOffset(0, 1e3)}`;
902
943
  } else {
903
944
  const refColumnsQuery = `
904
- SELECT COLUMN_NAME, DATA_TYPE
905
- FROM INFORMATION_SCHEMA.COLUMNS
906
- WHERE TABLE_SCHEMA = @refSchema AND TABLE_NAME = @refTable
907
- ORDER BY ORDINAL_POSITION
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
908
949
  `;
909
950
  const refColumns = await executeQuery(refColumnsQuery, [
910
- { name: "refSchema", value: refSchema, type: sql.NVarChar },
911
- { name: "refTable", value: refTable, type: sql.NVarChar }
951
+ { name: "refSchema", value: refSchema },
952
+ { name: "refTable", value: refTable }
912
953
  ]);
913
954
  const preferredNames = ["name", "title", "description", "code"];
914
955
  for (const preferredName of preferredNames) {
915
- const found = refColumns.find(
916
- (col) => col.COLUMN_NAME.toLowerCase() === preferredName.toLowerCase() && col.COLUMN_NAME.toLowerCase() !== refColumn.toLowerCase()
917
- );
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
+ });
918
960
  if (found) {
919
- displayColumn = found.COLUMN_NAME;
961
+ displayColumn = found.column_name || found.COLUMN_NAME;
920
962
  break;
921
963
  }
922
964
  }
923
965
  if (!displayColumn) {
924
966
  const stringTypes = ["varchar", "nvarchar", "char", "nchar", "text", "ntext"];
925
- const found = refColumns.find(
926
- (col) => col.COLUMN_NAME.toLowerCase() !== refColumn.toLowerCase() && stringTypes.some((type) => col.DATA_TYPE.toLowerCase().includes(type))
927
- );
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
+ });
928
972
  if (found) {
929
- displayColumn = found.COLUMN_NAME;
973
+ displayColumn = found.column_name || found.COLUMN_NAME;
930
974
  }
931
975
  }
932
- const selectCols = displayColumn ? `[${refColumn}], [${displayColumn}]` : `[${refColumn}]`;
933
- query = `SELECT DISTINCT ${selectCols} FROM [${refSchema}].[${refTable}]`;
976
+ const quotedDisplayColumn = displayColumn ? dialect.quoteId(displayColumn) : null;
977
+ const selectCols = displayColumn ? `${quotedRefColumn}, ${quotedDisplayColumn}` : quotedRefColumn;
978
+ query = `SELECT DISTINCT ${selectCols} FROM ${quotedRefSchema}.${quotedRefTable}`;
934
979
  if (searchQuery && searchQuery.trim()) {
935
980
  if (displayColumn) {
936
- query += ` WHERE [${displayColumn}] LIKE @search OR [${refColumn}] LIKE @search`;
981
+ query += ` WHERE ${quotedDisplayColumn} LIKE ${dialect.param(1)} OR ${quotedRefColumn} LIKE ${dialect.param(1)}`;
937
982
  } else {
938
- query += ` WHERE [${refColumn}] LIKE @search`;
983
+ query += ` WHERE ${quotedRefColumn} LIKE ${dialect.param(1)}`;
939
984
  }
940
- params.push({ name: "search", value: `%${searchQuery.trim()}%`, type: sql.NVarChar });
941
- query += ` AND [${refColumn}] IS NOT NULL`;
985
+ params.push({ name: "search", value: `%${searchQuery.trim()}%` });
986
+ query += ` AND ${quotedRefColumn} IS NOT NULL`;
942
987
  } else {
943
- query += ` WHERE [${refColumn}] IS NOT NULL`;
988
+ query += ` WHERE ${quotedRefColumn} IS NOT NULL`;
944
989
  }
945
- query += ` ORDER BY ${displayColumn ? `[${displayColumn}]` : `[${refColumn}]`} OFFSET 0 ROWS FETCH NEXT 1000 ROWS ONLY`;
990
+ query += ` ORDER BY ${displayColumn ? quotedDisplayColumn : quotedRefColumn} ${dialect.limitOffset(0, 1e3)}`;
946
991
  }
947
992
  } else {
948
- const dataType = columnInfo.DATA_TYPE.toLowerCase();
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);
949
997
  const columnsToSelect = columnsParam ? columnsParam.split(",").map((c) => c.trim()).filter((c) => c) : [];
950
998
  if (columnsToSelect.length > 0) {
951
- const escapedColumns = columnsToSelect.map((col) => col.replace(/]/g, "]]"));
952
- const keyColumn = escapedColumns[0];
953
- const orderByColumn = escapedColumns.length > 1 ? escapedColumns[1] : keyColumn;
954
- query = `SELECT DISTINCT ${escapedColumns.map((col) => `[${col}]`).join(", ")} FROM [${schema}].[${table}]`;
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}`;
955
1003
  if (searchQuery && searchQuery.trim()) {
956
- const searchCols = escapedColumns.map((col) => `TRY_CAST([${col}] AS NVARCHAR(4000)) LIKE @search`).join(" OR ");
957
- query += ` WHERE (${searchCols}) AND [${keyColumn}] IS NOT NULL`;
958
- params.push({ name: "search", value: `%${searchQuery.trim()}%`, type: sql.NVarChar });
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()}%` });
959
1007
  } else {
960
- query += ` WHERE [${keyColumn}] IS NOT NULL`;
1008
+ query += ` WHERE ${keyColumn} IS NOT NULL`;
961
1009
  }
962
- query += ` ORDER BY [${orderByColumn}] OFFSET 0 ROWS FETCH NEXT 1000 ROWS ONLY`;
1010
+ query += ` ORDER BY ${orderByColumn} ${dialect.limitOffset(0, 1e3)}`;
963
1011
  } else {
964
- query = `SELECT DISTINCT [${column}] FROM [${schema}].[${table}]`;
1012
+ query = `SELECT DISTINCT ${quotedColumn} FROM ${quotedSchema}.${quotedTable}`;
965
1013
  if (searchQuery && searchQuery.trim()) {
966
1014
  if (["varchar", "nvarchar", "char", "nchar", "text", "ntext"].some((t) => dataType.includes(t))) {
967
- query += ` WHERE [${column}] LIKE @search`;
968
- params.push({ name: "search", value: `%${searchQuery.trim()}%`, type: sql.NVarChar });
969
- query += ` AND [${column}] IS NOT NULL`;
1015
+ query += ` WHERE ${quotedColumn} LIKE ${dialect.param(1)}`;
1016
+ params.push({ name: "search", value: `%${searchQuery.trim()}%` });
1017
+ query += ` AND ${quotedColumn} IS NOT NULL`;
970
1018
  } else {
971
- query += ` WHERE [${column}] IS NOT NULL`;
1019
+ query += ` WHERE ${quotedColumn} IS NOT NULL`;
972
1020
  }
973
1021
  } else {
974
- query += ` WHERE [${column}] IS NOT NULL`;
1022
+ query += ` WHERE ${quotedColumn} IS NOT NULL`;
975
1023
  }
976
- query += ` ORDER BY [${column}] OFFSET 0 ROWS FETCH NEXT 1000 ROWS ONLY`;
1024
+ query += ` ORDER BY ${quotedColumn} ${dialect.limitOffset(0, 1e3)}`;
977
1025
  }
978
1026
  }
979
1027
  const result = await executeQuery(query, params);
@@ -981,8 +1029,8 @@ tableRoutes.get("/:schema/:table/distinct-values/:column", async (req, res) => {
981
1029
  } catch (error) {
982
1030
  console.error("Error fetching distinct values:", error);
983
1031
  const errorMessage = error.message || "";
984
- if (errorMessage.includes("Login failed") || errorMessage.includes("authentication")) {
985
- const { disconnect: disconnect2 } = await import("./mssql-UZUN227W.js");
1032
+ if (errorMessage.includes("Login failed") || errorMessage.includes("authentication") || errorMessage.includes("password authentication")) {
1033
+ const { disconnect: disconnect2 } = await import("./db-CJPCGHL3.js");
986
1034
  await disconnect2();
987
1035
  }
988
1036
  res.status(500).json({ error: error.message || "Failed to fetch distinct values" });
@@ -994,24 +1042,33 @@ import { Router as Router3 } from "express";
994
1042
  var queryRoutes = Router3();
995
1043
  queryRoutes.post("/", async (req, res) => {
996
1044
  try {
997
- const { query: sqlQuery } = req.body;
1045
+ const { query: sqlQuery, queryId } = req.body;
998
1046
  if (!sqlQuery || typeof sqlQuery !== "string") {
999
1047
  return res.status(400).json({ error: "Query is required" });
1000
1048
  }
1049
+ const activeQueryId = queryId || generateQueryId();
1001
1050
  const startTime = Date.now();
1002
- const { recordsets: resultSets, columnMetadata } = await executeQueryMultiple(sqlQuery);
1051
+ const { recordsets: resultSets, columnMetadata } = await executeQueryMultiple(sqlQuery, void 0, activeQueryId);
1003
1052
  const executionTime = Date.now() - startTime;
1004
1053
  res.json({
1005
1054
  data: resultSets[0] || [],
1006
1055
  resultSets: resultSets.length > 0 ? resultSets : [],
1007
1056
  executionTime,
1008
- columnMetadata
1057
+ columnMetadata,
1009
1058
  // Include column metadata for empty result sets
1059
+ queryId: activeQueryId
1060
+ // Return queryId so client can track it
1010
1061
  });
1011
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
+ }
1012
1069
  const errorMessage = error.message || "";
1013
- if (errorMessage.includes("Login failed") || errorMessage.includes("authentication")) {
1014
- 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");
1015
1072
  await disconnect2();
1016
1073
  }
1017
1074
  res.status(500).json({
@@ -1020,6 +1077,24 @@ queryRoutes.post("/", async (req, res) => {
1020
1077
  });
1021
1078
  }
1022
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
+ });
1023
1098
 
1024
1099
  // src/server/index.ts
1025
1100
  var __filename = fileURLToPath(import.meta.url);