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