@quillsql/node 0.5.9 → 0.6.0
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 +3 -1
- package/dist/db/CachedConnection.js +11 -14
- package/dist/db/Postgres.js +28 -21
- package/dist/db/Snowflake.js +2 -2
- package/dist/index.js +14 -5
- 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 +11 -19
- package/src/db/DatabaseHelper.ts +29 -30
- package/src/db/Mysql.ts +0 -2
- package/src/db/Postgres.ts +38 -40
- package/src/db/Snowflake.ts +14 -15
- package/src/index.ts +20 -6
- package/src/models/Cache.ts +2 -2
- package/src/utils/Error.ts +18 -4
- package/src/utils/RunQueryProcesses.ts +3 -3
- package/src/utils/textProcessing.ts +1 -1
package/dist/db/BigQuery.js
CHANGED
|
@@ -164,6 +164,7 @@ function convertBigQueryTypeToPostgresOID(type) {
|
|
|
164
164
|
FLOAT: 700,
|
|
165
165
|
TIMESTAMP: 1114,
|
|
166
166
|
DATE: 1082,
|
|
167
|
+
BOOL: 16,
|
|
167
168
|
};
|
|
168
169
|
const postgresType = typeToOidMap[type.toUpperCase()] || "VARCHAR"; // Default to 'text' if the type is not recognized
|
|
169
170
|
return typeToOidMap[postgresType] || 1043; // Default to OID for 'text' if the type is not recognized
|
|
@@ -7,8 +7,10 @@ export declare class CachedConnection {
|
|
|
7
7
|
ttl: number;
|
|
8
8
|
cache: Mapable | null;
|
|
9
9
|
private config;
|
|
10
|
+
private activeQueries;
|
|
11
|
+
private readonly MAX_ACTIVE_QUERIES;
|
|
10
12
|
constructor(databaseType: "postgresql" | "snowflake" | "bigquery" | "mysql", config: any, cacheConfig?: Partial<CacheCredentials>);
|
|
11
|
-
query(text: string
|
|
13
|
+
query(text: string): Promise<any>;
|
|
12
14
|
/**
|
|
13
15
|
* Configures and returns a cache instance or null if none could be created.
|
|
14
16
|
*/
|
|
@@ -13,29 +13,23 @@ exports.CachedConnection = void 0;
|
|
|
13
13
|
const redis_1 = require("redis");
|
|
14
14
|
const Error_1 = require("../utils/Error");
|
|
15
15
|
const DatabaseHelper_1 = require("./DatabaseHelper");
|
|
16
|
-
class PgError extends Error {
|
|
17
|
-
// Add other properties if needed
|
|
18
|
-
constructor(detail, hint, position) {
|
|
19
|
-
super();
|
|
20
|
-
this.detail = detail;
|
|
21
|
-
this.hint = hint;
|
|
22
|
-
this.position = position;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
16
|
/** The TTL for new cache entries (default: 1h) */
|
|
26
17
|
const DEFAULT_CACHE_TTL = 24 * 60 * 60;
|
|
27
18
|
class CachedConnection {
|
|
28
19
|
constructor(databaseType, config, cacheConfig = {}) {
|
|
29
20
|
var _a;
|
|
21
|
+
this.activeQueries = 0;
|
|
22
|
+
this.MAX_ACTIVE_QUERIES = 0;
|
|
30
23
|
this.databaseType = databaseType;
|
|
31
24
|
this.pool = (0, DatabaseHelper_1.connectToDatabase)(databaseType, config);
|
|
32
25
|
this.config = config;
|
|
33
26
|
this.ttl = (_a = cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.ttl) !== null && _a !== void 0 ? _a : DEFAULT_CACHE_TTL;
|
|
34
27
|
this.cache = this.getCache(cacheConfig);
|
|
35
28
|
}
|
|
36
|
-
query(text
|
|
29
|
+
query(text) {
|
|
37
30
|
return __awaiter(this, void 0, void 0, function* () {
|
|
38
31
|
try {
|
|
32
|
+
this.activeQueries++;
|
|
39
33
|
this.pool = this.getPool();
|
|
40
34
|
if (!this.cache) {
|
|
41
35
|
return yield (0, DatabaseHelper_1.runQueryByDatabase)(this.databaseType, this.pool, text);
|
|
@@ -53,16 +47,19 @@ class CachedConnection {
|
|
|
53
47
|
}
|
|
54
48
|
}
|
|
55
49
|
catch (err) {
|
|
56
|
-
if ((0, Error_1.isSuperset)(err, PgError)) {
|
|
57
|
-
throw new PgError(err.detail, err.hint, err.position);
|
|
50
|
+
if ((0, Error_1.isSuperset)(err, Error_1.PgError)) {
|
|
51
|
+
throw new Error_1.PgError(err.message, err.detail, err.hint, err.position);
|
|
58
52
|
}
|
|
59
53
|
else if (err instanceof Error) {
|
|
60
54
|
throw new Error(err.message);
|
|
61
55
|
}
|
|
62
56
|
}
|
|
63
57
|
finally {
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
this.activeQueries--;
|
|
59
|
+
if (this.activeQueries <= this.MAX_ACTIVE_QUERIES) {
|
|
60
|
+
if (this.databaseType.toLowerCase() === "mysql") {
|
|
61
|
+
this.close();
|
|
62
|
+
}
|
|
66
63
|
}
|
|
67
64
|
}
|
|
68
65
|
});
|
package/dist/db/Postgres.js
CHANGED
|
@@ -138,24 +138,31 @@ function formatPostgresConfig(connectionString) {
|
|
|
138
138
|
}
|
|
139
139
|
exports.formatPostgresConfig = formatPostgresConfig;
|
|
140
140
|
// CURRENTLY UNUSED BUT MAYBE USEFUL IN THE FUTURE
|
|
141
|
-
function getSslConfig(client)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
141
|
+
// function getSslConfig(client: Client):
|
|
142
|
+
// | {
|
|
143
|
+
// rejectUnauthorized: false;
|
|
144
|
+
// ca?: string;
|
|
145
|
+
// key?: string;
|
|
146
|
+
// cert?: string;
|
|
147
|
+
// }
|
|
148
|
+
// | undefined {
|
|
149
|
+
// if (!client.useSsl) {
|
|
150
|
+
// return undefined;
|
|
151
|
+
// }
|
|
152
|
+
// if (client.serverCa && client.clientKey && client.clientCert) {
|
|
153
|
+
// return {
|
|
154
|
+
// rejectUnauthorized: false,
|
|
155
|
+
// ca: client.serverCa,
|
|
156
|
+
// key: client.clientKey,
|
|
157
|
+
// cert: client.clientCert,
|
|
158
|
+
// };
|
|
159
|
+
// }
|
|
160
|
+
// if (client.serverCa) {
|
|
161
|
+
// return {
|
|
162
|
+
// rejectUnauthorized: false,
|
|
163
|
+
// ca: client.serverCa,
|
|
164
|
+
// };
|
|
165
|
+
// }
|
|
166
|
+
// // if using ssl with no certificates
|
|
167
|
+
// return { rejectUnauthorized: false };
|
|
168
|
+
// }
|
package/dist/db/Snowflake.js
CHANGED
|
@@ -116,7 +116,7 @@ function connectToSnowflake(config) {
|
|
|
116
116
|
exports.connectToSnowflake = connectToSnowflake;
|
|
117
117
|
function disconnectFromSnowflake(connection) {
|
|
118
118
|
return __awaiter(this, void 0, void 0, function* () {
|
|
119
|
-
connection.destroy((err
|
|
119
|
+
connection.destroy((err) => {
|
|
120
120
|
if (err) {
|
|
121
121
|
console.error(`Failed to disconnect from Snowflake: ${err.message}`);
|
|
122
122
|
}
|
|
@@ -126,7 +126,7 @@ function disconnectFromSnowflake(connection) {
|
|
|
126
126
|
exports.disconnectFromSnowflake = disconnectFromSnowflake;
|
|
127
127
|
function getForeignKeysSnowflake(connection, schemaName, tableName, primaryKey) {
|
|
128
128
|
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
-
|
|
129
|
+
const depluralizedTableName = (0, textProcessing_1.depluralize)(tableName);
|
|
130
130
|
let sql = `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
|
|
131
131
|
WHERE TABLE_SCHEMA = '${schemaName}'
|
|
132
132
|
AND TABLE_NAME = '${schemaName}'
|
package/dist/index.js
CHANGED
|
@@ -41,10 +41,13 @@ class Quill {
|
|
|
41
41
|
this.targetConnection = new CachedConnection_1.CachedConnection(databaseType, credentials, cache || {});
|
|
42
42
|
}
|
|
43
43
|
query({ orgId, metadata, }) {
|
|
44
|
-
var _a, _b;
|
|
44
|
+
var _a, _b, _c, _d, _e;
|
|
45
45
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
46
|
this.targetConnection.orgId = orgId;
|
|
47
47
|
let responseMetadata = {};
|
|
48
|
+
if (!metadata.task) {
|
|
49
|
+
return { error: "Missing task.", status: "error", data: {} };
|
|
50
|
+
}
|
|
48
51
|
try {
|
|
49
52
|
const preQueryResults = metadata.preQueries
|
|
50
53
|
? yield this.runQueries(metadata.preQueries, this.targetConnection.databaseType, metadata.databaseType, metadata.runQueryConfig)
|
|
@@ -57,7 +60,11 @@ class Quill {
|
|
|
57
60
|
}
|
|
58
61
|
const response = yield this.postQuill(metadata.task, Object.assign(Object.assign(Object.assign({}, metadata), preQueryResults), { orgId, viewQuery: metadata.preQueries ? metadata.preQueries[0] : undefined }));
|
|
59
62
|
if (response.error) {
|
|
60
|
-
return {
|
|
63
|
+
return {
|
|
64
|
+
status: "error",
|
|
65
|
+
error: response.error,
|
|
66
|
+
data: response.metadata || {},
|
|
67
|
+
};
|
|
61
68
|
}
|
|
62
69
|
// if there is no metadata object in the response, create one
|
|
63
70
|
if (response.metadata) {
|
|
@@ -92,8 +99,8 @@ class Quill {
|
|
|
92
99
|
catch (err) {
|
|
93
100
|
return {
|
|
94
101
|
status: "error",
|
|
95
|
-
error: err.message,
|
|
96
|
-
data: responseMetadata,
|
|
102
|
+
error: (_e = (_d = (_c = err.response) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.error) !== null && _e !== void 0 ? _e : err.message,
|
|
103
|
+
data: responseMetadata || {},
|
|
97
104
|
};
|
|
98
105
|
}
|
|
99
106
|
});
|
|
@@ -152,7 +159,9 @@ class Quill {
|
|
|
152
159
|
return Object.assign(Object.assign({}, table), { columns: columns, rows: queryResult.rows });
|
|
153
160
|
}
|
|
154
161
|
catch (err) {
|
|
155
|
-
return Object.assign(Object.assign({}, table), { error:
|
|
162
|
+
return Object.assign(Object.assign({}, table), { error: err.message
|
|
163
|
+
? `Error fetching columns: ${err.message}`
|
|
164
|
+
: "Error fetching columns" });
|
|
156
165
|
}
|
|
157
166
|
})));
|
|
158
167
|
results = Object.assign(Object.assign({}, results), { queryResults });
|
package/dist/utils/Error.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ export declare class PgError extends Error {
|
|
|
3
3
|
detail?: string;
|
|
4
4
|
hint?: string;
|
|
5
5
|
position?: string;
|
|
6
|
+
constructor(message: string, detail?: string, hint?: string, position?: string, code?: string);
|
|
6
7
|
}
|
|
7
8
|
export declare function isSuperset(obj: any, baseClass: any): boolean;
|
package/dist/utils/Error.js
CHANGED
|
@@ -2,14 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isSuperset = exports.PgError = void 0;
|
|
4
4
|
class PgError extends Error {
|
|
5
|
+
// Add other properties if needed
|
|
6
|
+
constructor(message, detail, hint, position, code) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.detail = detail;
|
|
10
|
+
this.hint = hint;
|
|
11
|
+
this.position = position;
|
|
12
|
+
}
|
|
5
13
|
}
|
|
6
14
|
exports.PgError = PgError;
|
|
7
15
|
function isSuperset(obj, baseClass) {
|
|
8
|
-
// Get the property names of the base class
|
|
9
|
-
const
|
|
16
|
+
// Get the property names of the base class instance
|
|
17
|
+
const baseInstance = new baseClass();
|
|
18
|
+
const baseProps = Object.keys(baseInstance);
|
|
10
19
|
// Check if the object has all the properties of the base class
|
|
11
20
|
for (const prop of baseProps) {
|
|
12
|
-
if (!
|
|
21
|
+
if (!Object.prototype.hasOwnProperty.call(obj, prop)) {
|
|
13
22
|
return false;
|
|
14
23
|
}
|
|
15
24
|
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
import { CachedConnection } from "../db/CachedConnection";
|
|
2
|
+
export interface TableSchemaInfo {
|
|
3
|
+
fieldType: string;
|
|
4
|
+
name: string;
|
|
5
|
+
displayName: string;
|
|
6
|
+
isVisible: boolean;
|
|
7
|
+
}
|
|
2
8
|
export declare function removeFields(queryResults: any, fieldsToRemove: string[]): any;
|
|
3
9
|
export declare function mapQueries(queries: string[], targetConnection: CachedConnection): Promise<any[]>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import globals from "globals";
|
|
2
|
+
import pluginJs from "@eslint/js";
|
|
3
|
+
import tseslint from "typescript-eslint";
|
|
4
|
+
|
|
5
|
+
export default [
|
|
6
|
+
{ files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"] },
|
|
7
|
+
{ languageOptions: { globals: globals.node } },
|
|
8
|
+
pluginJs.configs.recommended,
|
|
9
|
+
...tseslint.configs.recommended,
|
|
10
|
+
{
|
|
11
|
+
rules: {
|
|
12
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
13
|
+
"@typescript-eslint/no-require-imports": "off",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
];
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Write a simple node server to test the SDK
|
|
2
|
+
|
|
3
|
+
import express from "express";
|
|
4
|
+
import cors from "cors";
|
|
5
|
+
import requireQuill from "../../src/index";
|
|
6
|
+
|
|
7
|
+
const app = express();
|
|
8
|
+
const port = 3005;
|
|
9
|
+
|
|
10
|
+
// postgresqlConfigExample {
|
|
11
|
+
// connectionString: process.env.DB_URL,
|
|
12
|
+
// ssl: {
|
|
13
|
+
// rejectUnauthorized: false,
|
|
14
|
+
// },
|
|
15
|
+
// };
|
|
16
|
+
|
|
17
|
+
// bigqueryConfigExample {
|
|
18
|
+
// projectId: process.env.PROJECT_ID,
|
|
19
|
+
// credentials: serviceAccount // You need to make the serviceAccount JSON
|
|
20
|
+
// }
|
|
21
|
+
|
|
22
|
+
// snowflakeConfigExample {
|
|
23
|
+
// account: process.env.ACCOUNT,
|
|
24
|
+
// username: process.env.USERNAME,
|
|
25
|
+
// password: process.env.PASSWORD,
|
|
26
|
+
// warehouse: process.env.WAREHOUSE,
|
|
27
|
+
// database: process.env.DATABASE,
|
|
28
|
+
// }
|
|
29
|
+
|
|
30
|
+
// mysqlConfigExample {
|
|
31
|
+
// host: process.env.HOST,
|
|
32
|
+
// user: process.env.USER,
|
|
33
|
+
// password: process.env.PASSWORD,
|
|
34
|
+
// database: process.env.DATABASE,
|
|
35
|
+
// }
|
|
36
|
+
|
|
37
|
+
app.use(cors());
|
|
38
|
+
app.use(express.json());
|
|
39
|
+
|
|
40
|
+
app.get("/", (req, res) => {
|
|
41
|
+
res.send("Hello World!");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const quill = requireQuill({
|
|
45
|
+
privateKey: process.env.MYSQL_PRIVATE_KEY ?? "",
|
|
46
|
+
databaseConnectionString: process.env.MYSQL_DB_URL ?? "",
|
|
47
|
+
databaseConfig: {}, // TODO: Add database config
|
|
48
|
+
databaseType: "mysql",
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
app.post("/quill", async (req, res) => {
|
|
52
|
+
const { orgId, metadata } = req.body;
|
|
53
|
+
const result = await quill.query({
|
|
54
|
+
orgId: orgId ?? metadata.orgId,
|
|
55
|
+
metadata,
|
|
56
|
+
});
|
|
57
|
+
res.send(result);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
app.listen(port, () => {
|
|
61
|
+
console.log(`Example app listening at http://localhost:${port}`);
|
|
62
|
+
});
|
|
@@ -34,15 +34,14 @@ const port = 3001;
|
|
|
34
34
|
// }
|
|
35
35
|
|
|
36
36
|
const quill = require("../../src/index")({
|
|
37
|
-
privateKey: process.env.PRIVATE_KEY,
|
|
38
|
-
databaseConnectionString: process.env.DB_URL,
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
databaseType: process.env.DB_TYPE,
|
|
37
|
+
privateKey: process.env.PRIVATE_KEY ?? "",
|
|
38
|
+
databaseConnectionString: process.env.DB_URL ?? "",
|
|
39
|
+
databaseConfig: {}, // TODO: Add database config
|
|
40
|
+
databaseType: process.env.DB_TYPE as
|
|
41
|
+
| "postgresql"
|
|
42
|
+
| "snowflake"
|
|
43
|
+
| "bigquery"
|
|
44
|
+
| "mysql",
|
|
46
45
|
});
|
|
47
46
|
|
|
48
47
|
app.use(cors());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quillsql/node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Quill Server SDK for Node.js",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -8,12 +8,18 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "tsc --outDir dist",
|
|
10
10
|
"start:dev": "nodemon ./examples/node-server/app.ts",
|
|
11
|
+
"mysql:dev": "nodemon ./examples/mysql-node/app.ts",
|
|
11
12
|
"integration-tests": "jest '.*\\.ispec\\.ts$'",
|
|
12
|
-
"test": "tsc src && jest --detectOpenHandles"
|
|
13
|
+
"test": "tsc src && jest --detectOpenHandles",
|
|
14
|
+
"style-check": "prettier --check \"**/*.{ts,tsx,md}\"",
|
|
15
|
+
"style-fix": "prettier --write \"**/*.{ts,tsx,md}\"",
|
|
16
|
+
"lint-check": "eslint \"**/*.{ts,tsx}\"",
|
|
17
|
+
"lint-fix": "eslint '**/*.{ts,tsx}' --fix"
|
|
13
18
|
},
|
|
14
19
|
"author": "lagambino",
|
|
15
20
|
"license": "ISC",
|
|
16
21
|
"devDependencies": {
|
|
22
|
+
"@eslint/js": "^9.9.0",
|
|
17
23
|
"@types/cors": "^2.8.17",
|
|
18
24
|
"@types/express": "^4.17.21",
|
|
19
25
|
"@types/jest": "^29.5.11",
|
|
@@ -21,11 +27,18 @@
|
|
|
21
27
|
"@types/pg": "^8.10.9",
|
|
22
28
|
"@types/snowflake-sdk": "^1.6.20",
|
|
23
29
|
"cors": "^2.8.5",
|
|
30
|
+
"eslint": "^9.9.0",
|
|
31
|
+
"eslint-config-prettier": "^9.1.0",
|
|
32
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
33
|
+
"eslint-plugin-react": "^7.35.0",
|
|
24
34
|
"express": "^4.18.2",
|
|
35
|
+
"globals": "^15.9.0",
|
|
25
36
|
"jest": "^29.7.0",
|
|
26
37
|
"nodemon": "^3.0.2",
|
|
38
|
+
"prettier": "^3.3.3",
|
|
27
39
|
"ts-node": "^10.9.2",
|
|
28
|
-
"typescript": "^5.3.3"
|
|
40
|
+
"typescript": "^5.3.3",
|
|
41
|
+
"typescript-eslint": "^8.1.0"
|
|
29
42
|
},
|
|
30
43
|
"dependencies": {
|
|
31
44
|
"@google-cloud/bigquery": "^7.4.0",
|