datapeek 0.1.9 → 0.1.10

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.
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env node
2
+
3
+
4
+ // src/server/db/mssql.ts
5
+ import sql from "mssql";
6
+ var pool = null;
7
+ function parseConnectionString(connectionString) {
8
+ const config = {
9
+ server: "",
10
+ database: "",
11
+ options: {
12
+ encrypt: true,
13
+ trustServerCertificate: false,
14
+ enableArithAbort: true
15
+ }
16
+ };
17
+ const parts = connectionString.split(";");
18
+ for (const part of parts) {
19
+ const [key, ...valueParts] = part.split("=");
20
+ const value = valueParts.join("=").trim();
21
+ const keyLower = key.trim().toLowerCase();
22
+ switch (keyLower) {
23
+ case "server":
24
+ case "data source":
25
+ let serverValue = value;
26
+ if (serverValue.startsWith("tcp:")) {
27
+ serverValue = serverValue.substring(4);
28
+ }
29
+ const [serverHost, serverPort] = serverValue.split(",");
30
+ config.server = serverHost.trim();
31
+ if (serverPort) {
32
+ config.port = parseInt(serverPort.trim(), 10);
33
+ }
34
+ break;
35
+ case "database":
36
+ case "initial catalog":
37
+ config.database = value;
38
+ break;
39
+ case "user id":
40
+ case "userid":
41
+ case "uid":
42
+ config.user = value;
43
+ break;
44
+ case "password":
45
+ case "pwd":
46
+ config.password = value;
47
+ break;
48
+ case "port":
49
+ config.port = parseInt(value, 10);
50
+ break;
51
+ case "encrypt":
52
+ config.options.encrypt = value.toLowerCase() === "true";
53
+ break;
54
+ case "trustservercertificate":
55
+ case "trust server certificate":
56
+ config.options.trustServerCertificate = value.toLowerCase() === "true";
57
+ break;
58
+ }
59
+ }
60
+ return config;
61
+ }
62
+ async function testConnection(config) {
63
+ const testPool = typeof config === "string" ? new sql.ConnectionPool(parseConnectionString(config)) : new sql.ConnectionPool(config);
64
+ try {
65
+ await testPool.connect();
66
+ await testPool.close();
67
+ } catch (error) {
68
+ throw error;
69
+ }
70
+ }
71
+ async function connect(config) {
72
+ await disconnect();
73
+ const connectionConfig = typeof config === "string" ? parseConnectionString(config) : config;
74
+ const poolConfig = {
75
+ ...connectionConfig,
76
+ connectionTimeout: 3e4,
77
+ // 30 seconds for connection
78
+ pool: {
79
+ max: 10,
80
+ min: 0,
81
+ idleTimeoutMillis: 3e4,
82
+ acquireTimeoutMillis: 3e4
83
+ },
84
+ options: {
85
+ ...connectionConfig.options,
86
+ requestTimeout: 12e4
87
+ // 2 minutes for queries (increased for complex queries with JOINs)
88
+ }
89
+ };
90
+ pool = new sql.ConnectionPool(poolConfig);
91
+ try {
92
+ await pool.connect();
93
+ } catch (error) {
94
+ pool = null;
95
+ throw error;
96
+ }
97
+ }
98
+ async function disconnect() {
99
+ if (pool) {
100
+ try {
101
+ await pool.close();
102
+ } catch (error) {
103
+ }
104
+ pool = null;
105
+ }
106
+ }
107
+ function getConnection() {
108
+ return pool;
109
+ }
110
+ async function executeQuery(query, parameters) {
111
+ if (!pool || !pool.connected) {
112
+ throw new Error("Not connected to database");
113
+ }
114
+ const request = pool.request();
115
+ request.timeout = 12e4;
116
+ if (parameters) {
117
+ for (const param of parameters) {
118
+ if (param.type) {
119
+ request.input(param.name, param.type, param.value);
120
+ } else {
121
+ request.input(param.name, param.value);
122
+ }
123
+ }
124
+ }
125
+ try {
126
+ const result = await request.query(query);
127
+ return result.recordset || [];
128
+ } catch (error) {
129
+ if (error.code === "ETIMEOUT" || error.code === "ESOCKET" || error.message?.includes("timeout") || error.message?.includes("ETIMEDOUT")) {
130
+ const timeoutError = new Error("Query execution timeout. The query took too long to execute. Try disabling foreign key displays or reducing the page size.");
131
+ timeoutError.code = "ETIMEOUT";
132
+ timeoutError.originalError = error;
133
+ throw timeoutError;
134
+ }
135
+ throw error;
136
+ }
137
+ }
138
+ async function executeQueryMultiple(query, parameters) {
139
+ if (!pool || !pool.connected) {
140
+ throw new Error("Not connected to database");
141
+ }
142
+ const request = pool.request();
143
+ request.timeout = 12e4;
144
+ if (parameters) {
145
+ for (const param of parameters) {
146
+ if (param.type) {
147
+ request.input(param.name, param.type, param.value);
148
+ } else {
149
+ request.input(param.name, param.value);
150
+ }
151
+ }
152
+ }
153
+ try {
154
+ const result = await request.query(query);
155
+ const recordsets = result.recordsets || [];
156
+ const columnMetadata = [];
157
+ if (recordsets.length > 0) {
158
+ for (let index = 0; index < recordsets.length; index++) {
159
+ const recordset = recordsets[index];
160
+ if (recordset.length === 0) {
161
+ let columns = [];
162
+ const resultSet = index === 0 ? result.recordset : result.recordsets?.[index] || null;
163
+ if (resultSet) {
164
+ try {
165
+ const recordsetObj = resultSet;
166
+ if (recordsetObj.columns && typeof recordsetObj.columns === "object") {
167
+ columns = Object.keys(recordsetObj.columns);
168
+ } else if (recordsetObj.recordset && recordsetObj.recordset.columns) {
169
+ columns = Object.keys(recordsetObj.recordset.columns);
170
+ }
171
+ if (columns.length === 0 && result.recordset) {
172
+ if (index === 0 && result.recordset.columns) {
173
+ columns = Object.keys(result.recordset.columns);
174
+ }
175
+ }
176
+ } catch (e) {
177
+ }
178
+ }
179
+ if (columns.length === 0) {
180
+ try {
181
+ const trimmedQuery = query.trim().toUpperCase();
182
+ if (trimmedQuery.startsWith("SELECT")) {
183
+ const metadataRequest = pool.request();
184
+ metadataRequest.timeout = 5e3;
185
+ let metadataQuery = query;
186
+ if (!trimmedQuery.match(/\bTOP\s+\d+/i)) {
187
+ metadataQuery = query.replace(/^(\s*SELECT\s+)(.*)$/i, "$1TOP 0 $2");
188
+ } else {
189
+ metadataQuery = query.replace(/\bTOP\s+\d+/i, "TOP 0");
190
+ }
191
+ const metadataResult = await metadataRequest.query(metadataQuery);
192
+ if (metadataResult.recordset) {
193
+ const metadataRecordset = metadataResult.recordset;
194
+ if (metadataRecordset.columns) {
195
+ columns = Object.keys(metadataRecordset.columns);
196
+ }
197
+ }
198
+ }
199
+ } catch (metadataError) {
200
+ }
201
+ }
202
+ if (columns.length > 0) {
203
+ columnMetadata.push({ resultSetIndex: index, columns });
204
+ }
205
+ }
206
+ }
207
+ }
208
+ return { recordsets, columnMetadata: columnMetadata.length > 0 ? columnMetadata : void 0 };
209
+ } catch (error) {
210
+ if (error.code === "ETIMEOUT" || error.code === "ESOCKET" || error.message?.includes("timeout") || error.message?.includes("ETIMEDOUT")) {
211
+ const timeoutError = new Error("Query execution timeout. The query took too long to execute. Try simplifying your query or reducing the result set size.");
212
+ timeoutError.code = "ETIMEOUT";
213
+ timeoutError.originalError = error;
214
+ throw timeoutError;
215
+ }
216
+ throw error;
217
+ }
218
+ }
219
+
220
+ export {
221
+ parseConnectionString,
222
+ testConnection,
223
+ connect,
224
+ disconnect,
225
+ getConnection,
226
+ executeQuery,
227
+ executeQueryMultiple
228
+ };
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env node
2
+
3
+
4
+ // src/server/db/mssql.ts
5
+ import sql from "mssql";
6
+ var pool = null;
7
+ function parseConnectionString(connectionString) {
8
+ const config = {
9
+ server: "",
10
+ database: "",
11
+ options: {
12
+ encrypt: true,
13
+ trustServerCertificate: false,
14
+ enableArithAbort: true
15
+ }
16
+ };
17
+ const parts = connectionString.split(";");
18
+ for (const part of parts) {
19
+ const [key, ...valueParts] = part.split("=");
20
+ const value = valueParts.join("=").trim();
21
+ const keyLower = key.trim().toLowerCase();
22
+ switch (keyLower) {
23
+ case "server":
24
+ case "data source":
25
+ let serverValue = value;
26
+ if (serverValue.startsWith("tcp:")) {
27
+ serverValue = serverValue.substring(4);
28
+ }
29
+ const [serverHost, serverPort] = serverValue.split(",");
30
+ config.server = serverHost.trim();
31
+ if (serverPort) {
32
+ config.port = parseInt(serverPort.trim(), 10);
33
+ }
34
+ break;
35
+ case "database":
36
+ case "initial catalog":
37
+ config.database = value;
38
+ break;
39
+ case "user id":
40
+ case "userid":
41
+ case "uid":
42
+ config.user = value;
43
+ break;
44
+ case "password":
45
+ case "pwd":
46
+ config.password = value;
47
+ break;
48
+ case "port":
49
+ config.port = parseInt(value, 10);
50
+ break;
51
+ case "encrypt":
52
+ config.options.encrypt = value.toLowerCase() === "true";
53
+ break;
54
+ case "trustservercertificate":
55
+ case "trust server certificate":
56
+ config.options.trustServerCertificate = value.toLowerCase() === "true";
57
+ break;
58
+ }
59
+ }
60
+ return config;
61
+ }
62
+ async function testConnection(config) {
63
+ const testPool = typeof config === "string" ? new sql.ConnectionPool(parseConnectionString(config)) : new sql.ConnectionPool(config);
64
+ try {
65
+ await testPool.connect();
66
+ await testPool.close();
67
+ } catch (error) {
68
+ throw error;
69
+ }
70
+ }
71
+ async function connect(config) {
72
+ await disconnect();
73
+ const connectionConfig = typeof config === "string" ? parseConnectionString(config) : config;
74
+ const poolConfig = {
75
+ ...connectionConfig,
76
+ connectionTimeout: 3e4,
77
+ // 30 seconds for connection
78
+ pool: {
79
+ max: 10,
80
+ min: 0,
81
+ idleTimeoutMillis: 3e4,
82
+ acquireTimeoutMillis: 3e4
83
+ },
84
+ options: {
85
+ ...connectionConfig.options,
86
+ requestTimeout: 12e4
87
+ // 2 minutes for queries (increased for complex queries with JOINs)
88
+ }
89
+ };
90
+ pool = new sql.ConnectionPool(poolConfig);
91
+ try {
92
+ await pool.connect();
93
+ } catch (error) {
94
+ pool = null;
95
+ throw error;
96
+ }
97
+ }
98
+ async function disconnect() {
99
+ if (pool) {
100
+ try {
101
+ await pool.close();
102
+ } catch (error) {
103
+ }
104
+ pool = null;
105
+ }
106
+ }
107
+ function getConnection() {
108
+ return pool;
109
+ }
110
+ async function executeQuery(query, parameters) {
111
+ if (!pool || !pool.connected) {
112
+ throw new Error("Not connected to database");
113
+ }
114
+ const request = pool.request();
115
+ request.timeout = 12e4;
116
+ if (parameters) {
117
+ for (const param of parameters) {
118
+ if (param.type) {
119
+ request.input(param.name, param.type, param.value);
120
+ } else {
121
+ request.input(param.name, param.value);
122
+ }
123
+ }
124
+ }
125
+ try {
126
+ const result = await request.query(query);
127
+ return result.recordset || [];
128
+ } catch (error) {
129
+ if (error.code === "ETIMEOUT" || error.code === "ESOCKET" || error.message?.includes("timeout") || error.message?.includes("ETIMEDOUT")) {
130
+ const timeoutError = new Error("Query execution timeout. The query took too long to execute. Try disabling foreign key displays or reducing the page size.");
131
+ timeoutError.code = "ETIMEOUT";
132
+ timeoutError.originalError = error;
133
+ throw timeoutError;
134
+ }
135
+ throw error;
136
+ }
137
+ }
138
+ async function executeQueryMultiple(query, parameters) {
139
+ if (!pool || !pool.connected) {
140
+ throw new Error("Not connected to database");
141
+ }
142
+ const request = pool.request();
143
+ request.timeout = 12e4;
144
+ if (parameters) {
145
+ for (const param of parameters) {
146
+ if (param.type) {
147
+ request.input(param.name, param.type, param.value);
148
+ } else {
149
+ request.input(param.name, param.value);
150
+ }
151
+ }
152
+ }
153
+ try {
154
+ const result = await request.query(query);
155
+ const recordsets = result.recordsets || [];
156
+ const columnMetadata = [];
157
+ const emptyResultSetIndices = [];
158
+ recordsets.forEach((recordset, index) => {
159
+ if (recordset.length === 0) {
160
+ emptyResultSetIndices.push(index);
161
+ }
162
+ });
163
+ if (emptyResultSetIndices.length > 0) {
164
+ try {
165
+ const trimmedQuery = query.trim().toUpperCase();
166
+ if (trimmedQuery.startsWith("SELECT")) {
167
+ const metadataRequest = pool.request();
168
+ metadataRequest.timeout = 5e3;
169
+ let metadataQuery = query;
170
+ if (!trimmedQuery.includes("TOP ")) {
171
+ metadataQuery = query.replace(/^(\s*SELECT\s+)(.*)$/i, "$1TOP 0 $2");
172
+ } else {
173
+ metadataQuery = query.replace(/TOP\s+\d+/i, "TOP 0");
174
+ }
175
+ const metadataResult = await metadataRequest.query(metadataQuery);
176
+ if (metadataResult.recordset) {
177
+ const metadataRecordset = metadataResult.recordset;
178
+ if (metadataRecordset.columns && typeof metadataRecordset.columns === "object") {
179
+ const cols = Object.keys(metadataRecordset.columns);
180
+ if (cols.length > 0) {
181
+ emptyResultSetIndices.forEach((index) => {
182
+ columnMetadata.push({ resultSetIndex: index, columns: cols });
183
+ });
184
+ }
185
+ }
186
+ if (columnMetadata.length === 0 && metadataResult.recordset.columns) {
187
+ const cols = Object.keys(metadataResult.recordset.columns);
188
+ if (cols.length > 0) {
189
+ emptyResultSetIndices.forEach((index) => {
190
+ columnMetadata.push({ resultSetIndex: index, columns: cols });
191
+ });
192
+ }
193
+ }
194
+ }
195
+ }
196
+ } catch (metadataError) {
197
+ console.debug("Could not extract column metadata for empty result set:", metadataError);
198
+ }
199
+ }
200
+ return { recordsets, columnMetadata: columnMetadata.length > 0 ? columnMetadata : void 0 };
201
+ } catch (error) {
202
+ if (error.code === "ETIMEOUT" || error.code === "ESOCKET" || error.message?.includes("timeout") || error.message?.includes("ETIMEDOUT")) {
203
+ const timeoutError = new Error("Query execution timeout. The query took too long to execute. Try simplifying your query or reducing the result set size.");
204
+ timeoutError.code = "ETIMEOUT";
205
+ timeoutError.originalError = error;
206
+ throw timeoutError;
207
+ }
208
+ throw error;
209
+ }
210
+ }
211
+
212
+ export {
213
+ parseConnectionString,
214
+ testConnection,
215
+ connect,
216
+ disconnect,
217
+ getConnection,
218
+ executeQuery,
219
+ executeQueryMultiple
220
+ };
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env node
2
+
3
+
4
+ // src/server/db/mssql.ts
5
+ import sql from "mssql";
6
+ var pool = null;
7
+ function parseConnectionString(connectionString) {
8
+ const config = {
9
+ server: "",
10
+ database: "",
11
+ options: {
12
+ encrypt: true,
13
+ trustServerCertificate: false,
14
+ enableArithAbort: true
15
+ }
16
+ };
17
+ const parts = connectionString.split(";");
18
+ for (const part of parts) {
19
+ const [key, ...valueParts] = part.split("=");
20
+ const value = valueParts.join("=").trim();
21
+ const keyLower = key.trim().toLowerCase();
22
+ switch (keyLower) {
23
+ case "server":
24
+ case "data source":
25
+ let serverValue = value;
26
+ if (serverValue.startsWith("tcp:")) {
27
+ serverValue = serverValue.substring(4);
28
+ }
29
+ const [serverHost, serverPort] = serverValue.split(",");
30
+ config.server = serverHost.trim();
31
+ if (serverPort) {
32
+ config.port = parseInt(serverPort.trim(), 10);
33
+ }
34
+ break;
35
+ case "database":
36
+ case "initial catalog":
37
+ config.database = value;
38
+ break;
39
+ case "user id":
40
+ case "userid":
41
+ case "uid":
42
+ config.user = value;
43
+ break;
44
+ case "password":
45
+ case "pwd":
46
+ config.password = value;
47
+ break;
48
+ case "port":
49
+ config.port = parseInt(value, 10);
50
+ break;
51
+ case "encrypt":
52
+ config.options.encrypt = value.toLowerCase() === "true";
53
+ break;
54
+ case "trustservercertificate":
55
+ case "trust server certificate":
56
+ config.options.trustServerCertificate = value.toLowerCase() === "true";
57
+ break;
58
+ }
59
+ }
60
+ return config;
61
+ }
62
+ async function testConnection(config) {
63
+ const testPool = typeof config === "string" ? new sql.ConnectionPool(parseConnectionString(config)) : new sql.ConnectionPool(config);
64
+ try {
65
+ await testPool.connect();
66
+ await testPool.close();
67
+ } catch (error) {
68
+ throw error;
69
+ }
70
+ }
71
+ async function connect(config) {
72
+ await disconnect();
73
+ const connectionConfig = typeof config === "string" ? parseConnectionString(config) : config;
74
+ const poolConfig = {
75
+ ...connectionConfig,
76
+ connectionTimeout: 3e4,
77
+ // 30 seconds for connection
78
+ pool: {
79
+ max: 10,
80
+ min: 0,
81
+ idleTimeoutMillis: 3e4,
82
+ acquireTimeoutMillis: 3e4
83
+ },
84
+ options: {
85
+ ...connectionConfig.options,
86
+ requestTimeout: 12e4
87
+ // 2 minutes for queries (increased for complex queries with JOINs)
88
+ }
89
+ };
90
+ pool = new sql.ConnectionPool(poolConfig);
91
+ try {
92
+ await pool.connect();
93
+ } catch (error) {
94
+ pool = null;
95
+ throw error;
96
+ }
97
+ }
98
+ async function disconnect() {
99
+ if (pool) {
100
+ try {
101
+ await pool.close();
102
+ } catch (error) {
103
+ }
104
+ pool = null;
105
+ }
106
+ }
107
+ function getConnection() {
108
+ return pool;
109
+ }
110
+ async function executeQuery(query, parameters) {
111
+ if (!pool || !pool.connected) {
112
+ throw new Error("Not connected to database");
113
+ }
114
+ const request = pool.request();
115
+ request.timeout = 12e4;
116
+ if (parameters) {
117
+ for (const param of parameters) {
118
+ if (param.type) {
119
+ request.input(param.name, param.type, param.value);
120
+ } else {
121
+ request.input(param.name, param.value);
122
+ }
123
+ }
124
+ }
125
+ try {
126
+ const result = await request.query(query);
127
+ return result.recordset || [];
128
+ } catch (error) {
129
+ if (error.code === "ETIMEOUT" || error.code === "ESOCKET" || error.message?.includes("timeout") || error.message?.includes("ETIMEDOUT")) {
130
+ const timeoutError = new Error("Query execution timeout. The query took too long to execute. Try disabling foreign key displays or reducing the page size.");
131
+ timeoutError.code = "ETIMEOUT";
132
+ timeoutError.originalError = error;
133
+ throw timeoutError;
134
+ }
135
+ throw error;
136
+ }
137
+ }
138
+ async function executeQueryMultiple(query, parameters) {
139
+ if (!pool || !pool.connected) {
140
+ throw new Error("Not connected to database");
141
+ }
142
+ const request = pool.request();
143
+ request.timeout = 12e4;
144
+ if (parameters) {
145
+ for (const param of parameters) {
146
+ if (param.type) {
147
+ request.input(param.name, param.type, param.value);
148
+ } else {
149
+ request.input(param.name, param.value);
150
+ }
151
+ }
152
+ }
153
+ try {
154
+ const result = await request.query(query);
155
+ const recordsets = result.recordsets || [];
156
+ const columnMetadata = [];
157
+ if (result.recordset && recordsets.length > 0) {
158
+ recordsets.forEach((recordset, index) => {
159
+ if (recordset.length === 0) {
160
+ const resultSet = index === 0 ? result.recordset : result.recordsets?.[index] || null;
161
+ if (resultSet && resultSet.columns) {
162
+ const columns = Object.keys(resultSet.columns);
163
+ if (columns.length > 0) {
164
+ columnMetadata.push({ resultSetIndex: index, columns });
165
+ }
166
+ }
167
+ }
168
+ });
169
+ }
170
+ return { recordsets, columnMetadata: columnMetadata.length > 0 ? columnMetadata : void 0 };
171
+ } catch (error) {
172
+ if (error.code === "ETIMEOUT" || error.code === "ESOCKET" || error.message?.includes("timeout") || error.message?.includes("ETIMEDOUT")) {
173
+ const timeoutError = new Error("Query execution timeout. The query took too long to execute. Try simplifying your query or reducing the result set size.");
174
+ timeoutError.code = "ETIMEOUT";
175
+ timeoutError.originalError = error;
176
+ throw timeoutError;
177
+ }
178
+ throw error;
179
+ }
180
+ }
181
+
182
+ export {
183
+ parseConnectionString,
184
+ testConnection,
185
+ connect,
186
+ disconnect,
187
+ getConnection,
188
+ executeQuery,
189
+ executeQueryMultiple
190
+ };