@quillsql/node 0.5.9 → 0.6.1
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.
- package/dist/assets/pgtypes.js +1391 -1391
- package/dist/db/BigQuery.js +1 -0
- package/dist/db/CachedConnection.d.ts +11 -6
- package/dist/db/CachedConnection.js +12 -26
- package/dist/db/DatabaseHelper.d.ts +3 -1
- package/dist/db/DatabaseHelper.js +21 -2
- package/dist/db/Postgres.js +28 -21
- package/dist/db/Snowflake.js +2 -2
- package/dist/index.d.ts +4 -3
- package/dist/index.ispec.js +3 -0
- package/dist/index.js +21 -7
- package/dist/index.uspec.js +3 -0
- package/dist/models/Cache.d.ts +1 -1
- package/dist/utils/Error.d.ts +1 -0
- package/dist/utils/Error.js +12 -3
- package/dist/utils/RunQueryProcesses.d.ts +6 -0
- package/eslint.config.mjs +16 -0
- package/examples/mysql-node/app.ts +62 -0
- package/examples/node-server/app.ts +8 -9
- package/package.json +16 -3
- package/src/assets/pgtypes.ts +1392 -1392
- package/src/db/BigQuery.ts +10 -10
- package/src/db/CachedConnection.ts +27 -37
- package/src/db/DatabaseHelper.ts +58 -33
- package/src/db/Mysql.ts +0 -2
- package/src/db/Postgres.ts +38 -40
- package/src/db/Snowflake.ts +14 -15
- package/src/index.ispec.ts +4 -0
- package/src/index.ts +30 -11
- package/src/index.uspec.ts +4 -0
- package/src/models/Cache.ts +3 -3
- package/src/utils/Error.ts +18 -4
- package/src/utils/RunQueryProcesses.ts +3 -3
- package/src/utils/textProcessing.ts +1 -1
package/src/db/Snowflake.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import snowflake from "snowflake-sdk";
|
|
2
|
-
import { Client } from "../models/Client";
|
|
3
2
|
import { QuillQueryResults } from "./DatabaseHelper";
|
|
4
3
|
import { capitalize, depluralize } from "../utils/textProcessing";
|
|
5
4
|
|
|
@@ -31,7 +30,7 @@ export type SnowflakeConnectionConfig = {
|
|
|
31
30
|
|
|
32
31
|
export async function runQuerySnowflake(
|
|
33
32
|
sql: string,
|
|
34
|
-
connection: snowflake.Connection
|
|
33
|
+
connection: snowflake.Connection,
|
|
35
34
|
): Promise<QuillQueryResults> {
|
|
36
35
|
const results = await new Promise((resolve, reject) => {
|
|
37
36
|
connection.execute({
|
|
@@ -56,7 +55,7 @@ export async function runQuerySnowflake(
|
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
export async function getSchemasSnowflake(
|
|
59
|
-
connection: snowflake.Connection
|
|
58
|
+
connection: snowflake.Connection,
|
|
60
59
|
): Promise<string[]> {
|
|
61
60
|
const sql = `SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
|
|
62
61
|
WHERE SCHEMA_NAME != 'INFORMATION_SCHEMA'`;
|
|
@@ -66,7 +65,7 @@ export async function getSchemasSnowflake(
|
|
|
66
65
|
|
|
67
66
|
export async function getTablesBySchemaSnowflake(
|
|
68
67
|
connection: snowflake.Connection,
|
|
69
|
-
schemaNames: string[]
|
|
68
|
+
schemaNames: string[],
|
|
70
69
|
): Promise<{ tableName: string; schemaName: string }[]> {
|
|
71
70
|
const allColumns = await Promise.all(
|
|
72
71
|
schemaNames.map(async (schema) => {
|
|
@@ -80,7 +79,7 @@ export async function getTablesBySchemaSnowflake(
|
|
|
80
79
|
return results.rows.map((row) => {
|
|
81
80
|
return { tableName: row.tableName, schemaName: row.schemaName };
|
|
82
81
|
});
|
|
83
|
-
})
|
|
82
|
+
}),
|
|
84
83
|
);
|
|
85
84
|
return allColumns.flat();
|
|
86
85
|
}
|
|
@@ -88,7 +87,7 @@ export async function getTablesBySchemaSnowflake(
|
|
|
88
87
|
export async function getColumnsByTableSnowflake(
|
|
89
88
|
connection: snowflake.Connection,
|
|
90
89
|
schemaName: string,
|
|
91
|
-
tableName: string
|
|
90
|
+
tableName: string,
|
|
92
91
|
): Promise<string[]> {
|
|
93
92
|
const sql = `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '${schemaName}' AND TABLE_NAME = '${tableName}'`;
|
|
94
93
|
const results = await runQuerySnowflake(sql, connection);
|
|
@@ -96,7 +95,7 @@ export async function getColumnsByTableSnowflake(
|
|
|
96
95
|
}
|
|
97
96
|
|
|
98
97
|
export function formatSnowflakeConfig(
|
|
99
|
-
connectionString: string
|
|
98
|
+
connectionString: string,
|
|
100
99
|
): SnowflakeConnectionConfig {
|
|
101
100
|
const parsed = new URL(connectionString);
|
|
102
101
|
return {
|
|
@@ -109,7 +108,7 @@ export function formatSnowflakeConfig(
|
|
|
109
108
|
}
|
|
110
109
|
|
|
111
110
|
export function connectToSnowflake(
|
|
112
|
-
config: SnowflakeConnectionConfig
|
|
111
|
+
config: SnowflakeConnectionConfig,
|
|
113
112
|
): snowflake.Connection {
|
|
114
113
|
const connection = snowflake.createConnection({
|
|
115
114
|
...config,
|
|
@@ -124,9 +123,9 @@ export function connectToSnowflake(
|
|
|
124
123
|
}
|
|
125
124
|
|
|
126
125
|
export async function disconnectFromSnowflake(
|
|
127
|
-
connection: snowflake.Connection
|
|
126
|
+
connection: snowflake.Connection,
|
|
128
127
|
) {
|
|
129
|
-
connection.destroy((err
|
|
128
|
+
connection.destroy((err) => {
|
|
130
129
|
if (err) {
|
|
131
130
|
console.error(`Failed to disconnect from Snowflake: ${err.message}`);
|
|
132
131
|
}
|
|
@@ -137,9 +136,9 @@ export async function getForeignKeysSnowflake(
|
|
|
137
136
|
connection: snowflake.Connection,
|
|
138
137
|
schemaName: string,
|
|
139
138
|
tableName: string,
|
|
140
|
-
primaryKey: string
|
|
139
|
+
primaryKey: string,
|
|
141
140
|
): Promise<string[]> {
|
|
142
|
-
|
|
141
|
+
const depluralizedTableName = depluralize(tableName);
|
|
143
142
|
let sql = `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
|
|
144
143
|
WHERE TABLE_SCHEMA = '${schemaName}'
|
|
145
144
|
AND TABLE_NAME = '${schemaName}'
|
|
@@ -152,7 +151,7 @@ export async function getForeignKeysSnowflake(
|
|
|
152
151
|
return key.COLUMN_NAME;
|
|
153
152
|
});
|
|
154
153
|
foreignKeysString = foreignKeysString.filter(
|
|
155
|
-
(key) => key !== "id" && key !== "_id_"
|
|
154
|
+
(key) => key !== "id" && key !== "_id_",
|
|
156
155
|
);
|
|
157
156
|
foreignKeysString = [...new Set(foreignKeysString)];
|
|
158
157
|
if (foreignKeysString.length === 0) {
|
|
@@ -177,7 +176,7 @@ export async function getForeignKeysSnowflake(
|
|
|
177
176
|
export async function getSchemaColumnInfoSnowflake(
|
|
178
177
|
connection: snowflake.Connection,
|
|
179
178
|
schemaName: string,
|
|
180
|
-
tableNames: { tableName: string; schemaName: string }[]
|
|
179
|
+
tableNames: { tableName: string; schemaName: string }[],
|
|
181
180
|
) {
|
|
182
181
|
const allColumns = await Promise.all(
|
|
183
182
|
tableNames.map(async (tableName) => {
|
|
@@ -200,7 +199,7 @@ export async function getSchemaColumnInfoSnowflake(
|
|
|
200
199
|
};
|
|
201
200
|
}),
|
|
202
201
|
};
|
|
203
|
-
})
|
|
202
|
+
}),
|
|
204
203
|
);
|
|
205
204
|
return allColumns;
|
|
206
205
|
}
|
package/src/index.ispec.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import QuillServerClient from "./clients/QuillServerClient";
|
|
2
1
|
import { CacheCredentials } from "./models/Cache";
|
|
3
2
|
import {
|
|
4
3
|
AdditionalProcessing,
|
|
@@ -10,7 +9,7 @@ import axios from "axios";
|
|
|
10
9
|
import "dotenv/config";
|
|
11
10
|
import { mapQueries, removeFields } from "./utils/RunQueryProcesses";
|
|
12
11
|
import {
|
|
13
|
-
|
|
12
|
+
connectAndRunQuery,
|
|
14
13
|
getColumnInfoBySchemaByDatabase,
|
|
15
14
|
getColumnsByTableByDatabase,
|
|
16
15
|
getDatabaseCredentials,
|
|
@@ -18,6 +17,7 @@ import {
|
|
|
18
17
|
getSchemasByDatabase,
|
|
19
18
|
getTablesBySchemaByDatabase,
|
|
20
19
|
runQueryByDatabase,
|
|
20
|
+
withConnection,
|
|
21
21
|
} from "./db/DatabaseHelper";
|
|
22
22
|
import { convertTypeToPostgres } from "./utils/schemaConversion";
|
|
23
23
|
|
|
@@ -44,9 +44,9 @@ export enum DatabaseType {
|
|
|
44
44
|
mysql = "mysql",
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export class Quill {
|
|
47
|
+
export class Quill implements AsyncDisposable {
|
|
48
48
|
// Configure cached connection pools with the given config.
|
|
49
|
-
|
|
49
|
+
private targetConnection;
|
|
50
50
|
private baseUrl: string;
|
|
51
51
|
private config: {
|
|
52
52
|
headers: {
|
|
@@ -92,6 +92,11 @@ export class Quill {
|
|
|
92
92
|
}: QuillQueryParams): Promise<QuillQueryResult> {
|
|
93
93
|
this.targetConnection.orgId = orgId;
|
|
94
94
|
let responseMetadata: any = {};
|
|
95
|
+
|
|
96
|
+
if (!metadata.task) {
|
|
97
|
+
return { error: "Missing task.", status: "error", data: {} };
|
|
98
|
+
}
|
|
99
|
+
|
|
95
100
|
try {
|
|
96
101
|
const preQueryResults = metadata.preQueries
|
|
97
102
|
? await this.runQueries(
|
|
@@ -114,7 +119,11 @@ export class Quill {
|
|
|
114
119
|
viewQuery: metadata.preQueries ? metadata.preQueries[0] : undefined,
|
|
115
120
|
});
|
|
116
121
|
if (response.error) {
|
|
117
|
-
return {
|
|
122
|
+
return {
|
|
123
|
+
status: "error",
|
|
124
|
+
error: response.error,
|
|
125
|
+
data: response.metadata || {},
|
|
126
|
+
};
|
|
118
127
|
}
|
|
119
128
|
// if there is no metadata object in the response, create one
|
|
120
129
|
if (response.metadata) {
|
|
@@ -153,8 +162,8 @@ export class Quill {
|
|
|
153
162
|
} catch (err) {
|
|
154
163
|
return {
|
|
155
164
|
status: "error",
|
|
156
|
-
error: (err as any).message,
|
|
157
|
-
data: responseMetadata,
|
|
165
|
+
error: (err as any).response?.data?.error ?? (err as any).message,
|
|
166
|
+
data: responseMetadata || {},
|
|
158
167
|
};
|
|
159
168
|
}
|
|
160
169
|
}
|
|
@@ -177,6 +186,7 @@ export class Quill {
|
|
|
177
186
|
queryResults: [],
|
|
178
187
|
};
|
|
179
188
|
}
|
|
189
|
+
|
|
180
190
|
if (runQueryConfig?.arrayToMap) {
|
|
181
191
|
const mappedArray = await mapQueries(queries, this.targetConnection);
|
|
182
192
|
return { ...results, queryResults: [], mappedArray };
|
|
@@ -221,8 +231,13 @@ export class Quill {
|
|
|
221
231
|
};
|
|
222
232
|
});
|
|
223
233
|
return { ...table, columns: columns, rows: queryResult.rows };
|
|
224
|
-
} catch (err) {
|
|
225
|
-
return {
|
|
234
|
+
} catch (err: any) {
|
|
235
|
+
return {
|
|
236
|
+
...table,
|
|
237
|
+
error: err.message
|
|
238
|
+
? `Error fetching columns: ${err.message}`
|
|
239
|
+
: "Error fetching columns",
|
|
240
|
+
};
|
|
226
241
|
}
|
|
227
242
|
}),
|
|
228
243
|
);
|
|
@@ -250,7 +265,6 @@ export class Quill {
|
|
|
250
265
|
runQueryConfig.schema!,
|
|
251
266
|
queryResult!,
|
|
252
267
|
);
|
|
253
|
-
this.targetConnection.close();
|
|
254
268
|
return schemaInfo;
|
|
255
269
|
} else {
|
|
256
270
|
if (runQueryConfig?.limitThousand) {
|
|
@@ -309,6 +323,10 @@ export class Quill {
|
|
|
309
323
|
return response.data;
|
|
310
324
|
}
|
|
311
325
|
|
|
326
|
+
public async [Symbol.asyncDispose](): Promise<void> {
|
|
327
|
+
await this.close();
|
|
328
|
+
}
|
|
329
|
+
|
|
312
330
|
public async close() {
|
|
313
331
|
await this.targetConnection.close();
|
|
314
332
|
}
|
|
@@ -341,6 +359,8 @@ const requireQuill = ({
|
|
|
341
359
|
|
|
342
360
|
module.exports = requireQuill;
|
|
343
361
|
module.exports.default = requireQuill;
|
|
362
|
+
module.exports.withConnection = withConnection;
|
|
363
|
+
module.exports.connectAndRunQuery = connectAndRunQuery;
|
|
344
364
|
module.exports.Quill = Quill;
|
|
345
365
|
module.exports.getTablesBySchemaByDatabase = getTablesBySchemaByDatabase;
|
|
346
366
|
module.exports.getDatabaseCredentials = getDatabaseCredentials;
|
|
@@ -349,7 +369,6 @@ module.exports.getForiegnKeysByDatabase = getForiegnKeysByDatabase;
|
|
|
349
369
|
module.exports.getSchemasByDatabase = getSchemasByDatabase;
|
|
350
370
|
module.exports.getColumnInfoBySchemaByDatabase =
|
|
351
371
|
getColumnInfoBySchemaByDatabase;
|
|
352
|
-
module.exports.connectToDatabase = connectToDatabase;
|
|
353
372
|
module.exports.runQueryByDatabase = runQueryByDatabase;
|
|
354
373
|
module.exports.DatabaseType = DatabaseType;
|
|
355
374
|
|
package/src/index.uspec.ts
CHANGED
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
// quill.targetConnection.query = jest.fn().mockResolvedValue([]);
|
|
18
18
|
// });
|
|
19
19
|
|
|
20
|
+
// afterEach(async () => {
|
|
21
|
+
// await quill.close();
|
|
22
|
+
// });
|
|
23
|
+
|
|
20
24
|
// describe("query", () => {
|
|
21
25
|
// it("return nothing when suppling no queries", () => {
|
|
22
26
|
// const metadata = {
|
package/src/models/Cache.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface Mappable {
|
|
2
2
|
get(key: string): Promise<string | null>;
|
|
3
3
|
set(
|
|
4
4
|
key: string,
|
|
5
5
|
value: string,
|
|
6
6
|
type?: string,
|
|
7
|
-
ttl?: number
|
|
7
|
+
ttl?: number,
|
|
8
8
|
): Promise<string | null>;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -15,4 +15,4 @@ export interface CacheCredentials {
|
|
|
15
15
|
port: string;
|
|
16
16
|
cacheType: string;
|
|
17
17
|
ttl?: number;
|
|
18
|
-
}
|
|
18
|
+
}
|
package/src/utils/Error.ts
CHANGED
|
@@ -4,18 +4,32 @@ export class PgError extends Error {
|
|
|
4
4
|
hint?: string;
|
|
5
5
|
position?: string;
|
|
6
6
|
// Add other properties if needed
|
|
7
|
+
constructor(
|
|
8
|
+
message: string,
|
|
9
|
+
detail?: string,
|
|
10
|
+
hint?: string,
|
|
11
|
+
position?: string,
|
|
12
|
+
code?: string,
|
|
13
|
+
) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.code = code;
|
|
16
|
+
this.detail = detail;
|
|
17
|
+
this.hint = hint;
|
|
18
|
+
this.position = position;
|
|
19
|
+
}
|
|
7
20
|
}
|
|
8
21
|
|
|
9
22
|
export function isSuperset(obj: any, baseClass: any): boolean {
|
|
10
|
-
// Get the property names of the base class
|
|
11
|
-
const
|
|
23
|
+
// Get the property names of the base class instance
|
|
24
|
+
const baseInstance = new baseClass();
|
|
25
|
+
const baseProps = Object.keys(baseInstance);
|
|
12
26
|
|
|
13
27
|
// Check if the object has all the properties of the base class
|
|
14
28
|
for (const prop of baseProps) {
|
|
15
|
-
if (!
|
|
29
|
+
if (!Object.prototype.hasOwnProperty.call(obj, prop)) {
|
|
16
30
|
return false;
|
|
17
31
|
}
|
|
18
32
|
}
|
|
19
33
|
|
|
20
34
|
return true;
|
|
21
|
-
}
|
|
35
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CachedConnection } from "../db/CachedConnection";
|
|
2
2
|
|
|
3
|
-
interface TableSchemaInfo {
|
|
3
|
+
export interface TableSchemaInfo {
|
|
4
4
|
fieldType: string;
|
|
5
5
|
name: string;
|
|
6
6
|
displayName: string;
|
|
@@ -9,7 +9,7 @@ interface TableSchemaInfo {
|
|
|
9
9
|
|
|
10
10
|
export function removeFields(queryResults: any, fieldsToRemove: string[]): any {
|
|
11
11
|
const fields = queryResults.fields.filter(
|
|
12
|
-
(field: { name: any }) => !fieldsToRemove.includes(field.name)
|
|
12
|
+
(field: { name: any }) => !fieldsToRemove.includes(field.name),
|
|
13
13
|
);
|
|
14
14
|
const rows = queryResults.rows.map((row: any) => {
|
|
15
15
|
fieldsToRemove.forEach((field) => {
|
|
@@ -22,7 +22,7 @@ export function removeFields(queryResults: any, fieldsToRemove: string[]): any {
|
|
|
22
22
|
|
|
23
23
|
export async function mapQueries(
|
|
24
24
|
queries: string[],
|
|
25
|
-
targetConnection: CachedConnection
|
|
25
|
+
targetConnection: CachedConnection,
|
|
26
26
|
): Promise<any[]> {
|
|
27
27
|
const mappedArray = [];
|
|
28
28
|
for (let i = 0; i < queries.length; i++) {
|