@quillsql/node 0.6.6 → 0.6.9
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 → cjs/assets}/pgtypes.js +1 -0
- package/dist/cjs/assets/pgtypes.js.map +1 -0
- package/dist/{clients → cjs/clients}/QuillServerClient.js +1 -0
- package/dist/cjs/clients/QuillServerClient.js.map +1 -0
- package/dist/{db → cjs/db}/BigQuery.js +1 -0
- package/dist/cjs/db/BigQuery.js.map +1 -0
- package/dist/{db → cjs/db}/CachedConnection.js +1 -0
- package/dist/cjs/db/CachedConnection.js.map +1 -0
- package/dist/{db → cjs/db}/DatabaseHelper.js +1 -0
- package/dist/cjs/db/DatabaseHelper.js.map +1 -0
- package/dist/{db → cjs/db}/Mysql.js +1 -0
- package/dist/cjs/db/Mysql.js.map +1 -0
- package/dist/{db → cjs/db}/Postgres.js +1 -0
- package/dist/cjs/db/Postgres.js.map +1 -0
- package/dist/{db → cjs/db}/Snowflake.js +43 -14
- package/dist/cjs/db/Snowflake.js.map +1 -0
- package/dist/{index.d.ts → cjs/index.d.ts} +1 -1
- package/dist/{index.ispec.js → cjs/index.ispec.js} +1 -0
- package/dist/cjs/index.ispec.js.map +1 -0
- package/dist/{index.js → cjs/index.js} +4 -2
- package/dist/cjs/index.js.map +1 -0
- package/dist/{index.uspec.js → cjs/index.uspec.js} +1 -0
- package/dist/cjs/index.uspec.js.map +1 -0
- package/dist/{models → cjs/models}/Cache.js +1 -0
- package/dist/cjs/models/Cache.js.map +1 -0
- package/dist/{models → cjs/models}/Client.js +1 -0
- package/dist/cjs/models/Client.js.map +1 -0
- package/dist/{models → cjs/models}/Database.js +1 -0
- package/dist/cjs/models/Database.js.map +1 -0
- package/dist/cjs/models/Filters.d.ts +117 -0
- package/dist/cjs/models/Filters.js +100 -0
- package/dist/cjs/models/Filters.js.map +1 -0
- package/dist/{models → cjs/models}/Formats.js +1 -0
- package/dist/cjs/models/Formats.js.map +1 -0
- package/dist/{models → cjs/models}/Quill.d.ts +2 -0
- package/dist/{models → cjs/models}/Quill.js +1 -0
- package/dist/cjs/models/Quill.js.map +1 -0
- package/dist/{utils → cjs/utils}/Error.js +1 -0
- package/dist/cjs/utils/Error.js.map +1 -0
- package/dist/{utils → cjs/utils}/RunQueryProcesses.js +1 -0
- package/dist/cjs/utils/RunQueryProcesses.js.map +1 -0
- package/dist/{utils → cjs/utils}/schemaConversion.js +1 -0
- package/dist/cjs/utils/schemaConversion.js.map +1 -0
- package/dist/{utils → cjs/utils}/textProcessing.js +1 -0
- package/dist/cjs/utils/textProcessing.js.map +1 -0
- package/dist/esm/assets/pgtypes.d.ts +4 -0
- package/dist/esm/assets/pgtypes.js +2783 -0
- package/dist/esm/assets/pgtypes.js.map +1 -0
- package/dist/esm/clients/QuillServerClient.d.ts +8 -0
- package/dist/esm/clients/QuillServerClient.js +24 -0
- package/dist/esm/clients/QuillServerClient.js.map +1 -0
- package/dist/esm/db/BigQuery.d.ts +27 -0
- package/dist/esm/db/BigQuery.js +201 -0
- package/dist/esm/db/BigQuery.js.map +1 -0
- package/dist/esm/db/CachedConnection.d.ts +23 -0
- package/dist/esm/db/CachedConnection.js +80 -0
- package/dist/esm/db/CachedConnection.js.map +1 -0
- package/dist/esm/db/DatabaseHelper.d.ts +50 -0
- package/dist/esm/db/DatabaseHelper.js +188 -0
- package/dist/esm/db/DatabaseHelper.js.map +1 -0
- package/dist/esm/db/Mysql.d.ts +30 -0
- package/dist/esm/db/Mysql.js +219 -0
- package/dist/esm/db/Mysql.js.map +1 -0
- package/dist/esm/db/Postgres.d.ts +32 -0
- package/dist/esm/db/Postgres.js +157 -0
- package/dist/esm/db/Postgres.js.map +1 -0
- package/dist/esm/db/Snowflake.d.ts +33 -0
- package/dist/esm/db/Snowflake.js +203 -0
- package/dist/esm/db/Snowflake.js.map +1 -0
- package/dist/esm/index.d.ts +41 -0
- package/dist/esm/index.ispec.d.ts +0 -0
- package/{src/index.ispec.ts → dist/esm/index.ispec.js} +2 -6
- package/dist/esm/index.ispec.js.map +1 -0
- package/dist/esm/index.js +266 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/index.uspec.d.ts +0 -0
- package/{src/index.uspec.ts → dist/esm/index.uspec.js} +2 -6
- package/dist/esm/index.uspec.js.map +1 -0
- package/dist/esm/models/Cache.d.ts +12 -0
- package/dist/esm/models/Cache.js +2 -0
- package/dist/esm/models/Cache.js.map +1 -0
- package/dist/esm/models/Client.d.ts +29 -0
- package/dist/esm/models/Client.js +2 -0
- package/dist/esm/models/Client.js.map +1 -0
- package/dist/esm/models/Database.d.ts +5 -0
- package/dist/esm/models/Database.js +2 -0
- package/dist/esm/models/Database.js.map +1 -0
- package/dist/esm/models/Filters.d.ts +117 -0
- package/dist/esm/models/Filters.js +97 -0
- package/dist/esm/models/Filters.js.map +1 -0
- package/dist/esm/models/Formats.d.ts +7 -0
- package/dist/esm/models/Formats.js +2 -0
- package/dist/esm/models/Formats.js.map +1 -0
- package/dist/esm/models/Quill.d.ts +73 -0
- package/dist/esm/models/Quill.js +2 -0
- package/dist/esm/models/Quill.js.map +1 -0
- package/dist/esm/utils/Error.d.ts +8 -0
- package/dist/esm/utils/Error.js +23 -0
- package/dist/esm/utils/Error.js.map +1 -0
- package/dist/esm/utils/RunQueryProcesses.d.ts +9 -0
- package/dist/esm/utils/RunQueryProcesses.js +30 -0
- package/dist/esm/utils/RunQueryProcesses.js.map +1 -0
- package/dist/esm/utils/schemaConversion.d.ts +1 -0
- package/dist/esm/utils/schemaConversion.js +12 -0
- package/dist/esm/utils/schemaConversion.js.map +1 -0
- package/dist/esm/utils/textProcessing.d.ts +2 -0
- package/dist/esm/utils/textProcessing.js +13 -0
- package/dist/esm/utils/textProcessing.js.map +1 -0
- package/package.json +11 -6
- package/eslint.config.mjs +0 -16
- package/examples/mysql-node/app.ts +0 -61
- package/examples/node-server/app.ts +0 -65
- package/jest.config.js +0 -19
- package/src/assets/pgtypes.ts +0 -2782
- package/src/clients/QuillServerClient.ts +0 -23
- package/src/db/BigQuery.ts +0 -220
- package/src/db/CachedConnection.ts +0 -109
- package/src/db/DatabaseHelper.ts +0 -373
- package/src/db/Mysql.ts +0 -262
- package/src/db/Postgres.ts +0 -185
- package/src/db/Snowflake.ts +0 -205
- package/src/index.ts +0 -390
- package/src/models/Cache.ts +0 -18
- package/src/models/Client.ts +0 -29
- package/src/models/Database.ts +0 -5
- package/src/models/Formats.ts +0 -19
- package/src/models/Quill.ts +0 -75
- package/src/utils/Error.ts +0 -35
- package/src/utils/RunQueryProcesses.ts +0 -33
- package/src/utils/schemaConversion.ts +0 -11
- package/src/utils/textProcessing.ts +0 -13
- package/tsconfig.json +0 -15
- /package/dist/{assets → cjs/assets}/pgtypes.d.ts +0 -0
- /package/dist/{clients → cjs/clients}/QuillServerClient.d.ts +0 -0
- /package/dist/{db → cjs/db}/BigQuery.d.ts +0 -0
- /package/dist/{db → cjs/db}/CachedConnection.d.ts +0 -0
- /package/dist/{db → cjs/db}/DatabaseHelper.d.ts +0 -0
- /package/dist/{db → cjs/db}/Mysql.d.ts +0 -0
- /package/dist/{db → cjs/db}/Postgres.d.ts +0 -0
- /package/dist/{db → cjs/db}/Snowflake.d.ts +0 -0
- /package/dist/{index.ispec.d.ts → cjs/index.ispec.d.ts} +0 -0
- /package/dist/{index.uspec.d.ts → cjs/index.uspec.d.ts} +0 -0
- /package/dist/{models → cjs/models}/Cache.d.ts +0 -0
- /package/dist/{models → cjs/models}/Client.d.ts +0 -0
- /package/dist/{models → cjs/models}/Database.d.ts +0 -0
- /package/dist/{models → cjs/models}/Formats.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/Error.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/RunQueryProcesses.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/schemaConversion.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/textProcessing.d.ts +0 -0
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import axios from "axios";
|
|
2
|
-
|
|
3
|
-
/** This client is currently not used but is a good design pratice */
|
|
4
|
-
|
|
5
|
-
class QuillServerClient {
|
|
6
|
-
private baseUrl: string;
|
|
7
|
-
private config: {
|
|
8
|
-
headers: {
|
|
9
|
-
Authorization: string;
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
constructor(privateKey: string) {
|
|
14
|
-
this.baseUrl = "";
|
|
15
|
-
this.config = { headers: { Authorization: `Bearer ${privateKey}` } };
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
public async postQuill(route: string, payload: any): Promise<any> {
|
|
19
|
-
return axios.post(`${this.baseUrl}/${route}`, payload, this.config);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default QuillServerClient;
|
package/src/db/BigQuery.ts
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import { BigQuery } from "@google-cloud/bigquery";
|
|
2
|
-
import { QuillQueryResults } from "./DatabaseHelper";
|
|
3
|
-
import { capitalize, depluralize } from "../utils/textProcessing";
|
|
4
|
-
|
|
5
|
-
export interface BigQueryConfig {
|
|
6
|
-
datasetName: string;
|
|
7
|
-
projectId: string;
|
|
8
|
-
credentials: any;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function formatBigQueryConfig(connectionString: string): BigQueryConfig {
|
|
12
|
-
const jsonStartIndex = connectionString.indexOf("{");
|
|
13
|
-
if (jsonStartIndex === -1) {
|
|
14
|
-
throw new Error("Invalid input string. No JSON data found.");
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const datasetName = connectionString.substring(0, jsonStartIndex).trim();
|
|
18
|
-
const jsonString = connectionString.substring(jsonStartIndex);
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
const serviceAccount = JSON.parse(jsonString);
|
|
22
|
-
|
|
23
|
-
// Validate if required fields are present
|
|
24
|
-
if (!serviceAccount.project_id || !serviceAccount.private_key) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
"Invalid service account JSON. Required fields are missing.",
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
datasetName,
|
|
32
|
-
projectId: serviceAccount.project_id,
|
|
33
|
-
credentials: serviceAccount,
|
|
34
|
-
};
|
|
35
|
-
} catch (error) {
|
|
36
|
-
throw new Error("Failed to parse JSON string: " + error);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function connectToBigQuery(config: BigQueryConfig) {
|
|
41
|
-
return new BigQuery(config);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export async function runQueryBigQuery(
|
|
45
|
-
sql: string,
|
|
46
|
-
bigQuery: BigQuery,
|
|
47
|
-
): Promise<QuillQueryResults> {
|
|
48
|
-
const rows = await bigQuery.query(sql);
|
|
49
|
-
if (!rows[0] || rows[0].length === 0) return { fields: [], rows: [] };
|
|
50
|
-
const typedRows = rows[0] as { [fieldName: string]: any }[];
|
|
51
|
-
const fields = Object.keys(typedRows[0]).map((name: string) => ({
|
|
52
|
-
name,
|
|
53
|
-
dataTypeID: 1043,
|
|
54
|
-
}));
|
|
55
|
-
fields.forEach((field) => {
|
|
56
|
-
typedRows.some((row) => {
|
|
57
|
-
if (row[field.name] === null) return false;
|
|
58
|
-
field.dataTypeID = inferType(row[field.name]);
|
|
59
|
-
return true;
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
return {
|
|
63
|
-
fields: fields,
|
|
64
|
-
rows: typedRows,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function getSchemaBigQuery(bigQuery: BigQuery): Promise<string[]> {
|
|
69
|
-
const [datasets] = await bigQuery.getDatasets();
|
|
70
|
-
const definedDatasets = datasets.map((dataset) => dataset.id);
|
|
71
|
-
const filtered: string[] = [];
|
|
72
|
-
definedDatasets.forEach((dataset) => {
|
|
73
|
-
if (dataset !== undefined) {
|
|
74
|
-
filtered.push(dataset);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
return filtered;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export async function getTablesBySchemaBigQuery(
|
|
81
|
-
bigQuery: BigQuery,
|
|
82
|
-
schemaNames: string[],
|
|
83
|
-
): Promise<{ tableName: string; schemaName: string }[]> {
|
|
84
|
-
const allColumns = await Promise.all(
|
|
85
|
-
schemaNames.map(async (schema) => {
|
|
86
|
-
const sql = `SELECT table_name FROM ${schema}.INFORMATION_SCHEMA.TABLES WHERE table_type = 'BASE TABLE' OR table_type = 'VIEW' OR table_type = 'MATERIALIZED VIEW'`;
|
|
87
|
-
const rows = await bigQuery.query(sql);
|
|
88
|
-
return rows[0].map((row) => {
|
|
89
|
-
return { tableName: row.table_name, schemaName: schema };
|
|
90
|
-
});
|
|
91
|
-
}),
|
|
92
|
-
);
|
|
93
|
-
return allColumns.flat();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export async function getColumnsByTableBigQuery(
|
|
97
|
-
bigQuery: BigQuery,
|
|
98
|
-
schemaName: string,
|
|
99
|
-
tableName: string,
|
|
100
|
-
): Promise<string[]> {
|
|
101
|
-
const sql = `SELECT column_name FROM ${schemaName}.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${tableName}'`;
|
|
102
|
-
const rows = await bigQuery.query(sql);
|
|
103
|
-
return rows[0].map((row: any) => row.column_name);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export async function getForeignKeysBigQuery(
|
|
107
|
-
connection: BigQuery,
|
|
108
|
-
schemaName: string,
|
|
109
|
-
tableName: string,
|
|
110
|
-
primaryKey: string,
|
|
111
|
-
): Promise<string[]> {
|
|
112
|
-
const depluralizedTableName = depluralize(tableName);
|
|
113
|
-
let sql = `SELECT column_name FROM ${schemaName}.INFORMATION_SCHEMA.COLUMNS
|
|
114
|
-
WHERE table_name != '${tableName}'
|
|
115
|
-
and (column_name = '${primaryKey}'
|
|
116
|
-
or column_name = '${depluralizedTableName}_${primaryKey}'
|
|
117
|
-
or column_name = '${depluralizedTableName}${capitalize(primaryKey)}')`;
|
|
118
|
-
const results = await runQueryBigQuery(sql, connection);
|
|
119
|
-
let foreignKeysString = results.rows.map((key) => {
|
|
120
|
-
return key.column_name;
|
|
121
|
-
});
|
|
122
|
-
foreignKeysString = foreignKeysString.filter(
|
|
123
|
-
(key) => key !== "id" && key !== "_id_",
|
|
124
|
-
);
|
|
125
|
-
foreignKeysString = [...new Set(foreignKeysString)];
|
|
126
|
-
if (foreignKeysString.length === 0) {
|
|
127
|
-
sql = `SELECT column_name FROM ${schemaName}.INFORMATION_SCHEMA.COLUMNS
|
|
128
|
-
WHERE table_name != '${tableName}'
|
|
129
|
-
and (column_name like '${depluralizedTableName}%'
|
|
130
|
-
or column_name like '%_id'
|
|
131
|
-
or column_name like '%Id'
|
|
132
|
-
or column_name like '%_${primaryKey}'
|
|
133
|
-
or column_name like '%${capitalize(primaryKey)}')`;
|
|
134
|
-
const results = await runQueryBigQuery(sql, connection);
|
|
135
|
-
foreignKeysString = results.rows.map((key) => {
|
|
136
|
-
return key.column_name;
|
|
137
|
-
});
|
|
138
|
-
foreignKeysString = [...new Set(foreignKeysString)];
|
|
139
|
-
}
|
|
140
|
-
return foreignKeysString;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export async function getSchemaColumnInfoBigQuery(
|
|
144
|
-
connection: BigQuery,
|
|
145
|
-
schemaName: string,
|
|
146
|
-
tableNames: { tableName: string; schemaName: string }[],
|
|
147
|
-
): Promise<
|
|
148
|
-
{ tableName: string; columns: { columnName: string; dataTypeID: number }[] }[]
|
|
149
|
-
> {
|
|
150
|
-
const allColumns = await Promise.all(
|
|
151
|
-
tableNames.map(async (tableName) => {
|
|
152
|
-
const query = `
|
|
153
|
-
SELECT column_name as columnName, data_type as dataType
|
|
154
|
-
FROM ${tableName.schemaName}.INFORMATION_SCHEMA.COLUMNS
|
|
155
|
-
WHERE table_name = '${tableName.tableName}'
|
|
156
|
-
ORDER BY ordinal_position;
|
|
157
|
-
`;
|
|
158
|
-
const results = await runQueryBigQuery(query, connection);
|
|
159
|
-
return {
|
|
160
|
-
tableName: `${tableName.schemaName}.${tableName.tableName}`,
|
|
161
|
-
displayName: `${tableName.schemaName}.${tableName.tableName}`,
|
|
162
|
-
columns: results.rows.map((row: any) => ({
|
|
163
|
-
columnName: row.columnName,
|
|
164
|
-
displayName: row.columnName,
|
|
165
|
-
dataTypeID: convertBigQueryTypeToPostgresOID(row.dataType),
|
|
166
|
-
fieldType: row.dataType,
|
|
167
|
-
})),
|
|
168
|
-
};
|
|
169
|
-
}),
|
|
170
|
-
);
|
|
171
|
-
return allColumns;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function convertBigQueryTypeToPostgresOID(type: string): number {
|
|
175
|
-
const typeToOidMap: { [key: string]: number } = {
|
|
176
|
-
VARCHAR: 1043,
|
|
177
|
-
INTEGER: 23,
|
|
178
|
-
FLOAT: 700,
|
|
179
|
-
TIMESTAMP: 1114,
|
|
180
|
-
DATE: 1082,
|
|
181
|
-
BOOL: 16,
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
const postgresType = typeToOidMap[type.toUpperCase()] || "VARCHAR"; // Default to 'text' if the type is not recognized
|
|
185
|
-
return typeToOidMap[postgresType] || 1043; // Default to OID for 'text' if the type is not recognized
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function inferType(elem: any) {
|
|
189
|
-
if (typeof elem === "number") {
|
|
190
|
-
// Check if the number is a float or an integer
|
|
191
|
-
return Number.isInteger(elem) ? 23 : 700; // 23: integer, 700: real
|
|
192
|
-
}
|
|
193
|
-
// BIG QUERY places data into objects as well
|
|
194
|
-
if (typeof elem === "object") {
|
|
195
|
-
if (/^\d{4}-\d{2}-\d{2}$/.test(elem.value)) return 1082; // YYYY-MM-DD format
|
|
196
|
-
if (/^\d{2}\/\d{2}\/\d{2,4}$/.test(elem.value)) return 1082; // MM\DD\YYYY or MM\DD\YY format
|
|
197
|
-
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?$/.test(elem.value))
|
|
198
|
-
return 1114; // YYYY-MM-DDTHH:MM:SS[.fraction] format
|
|
199
|
-
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/.test(elem.value))
|
|
200
|
-
return 1184; // YYYY-MM-DDTHH:MM:SS[.fraction]Z format
|
|
201
|
-
if (/^\d{2}:\d{2}:\d{2}$/.test(elem.value)) return 1083; // HH:MM:SS format
|
|
202
|
-
}
|
|
203
|
-
if (typeof elem === "string") {
|
|
204
|
-
// Attempt to infer date, time, and timestamp formats
|
|
205
|
-
// Date in YYYY-MM-DD format
|
|
206
|
-
if (/^\d{4}-\d{2}-\d{2}$/.test(elem)) return 1082; // date
|
|
207
|
-
// Date in MM\DD\YYYY or MM\DD\YY format
|
|
208
|
-
if (/^\d{2}\/\d{2}\/\d{2,4}$/.test(elem)) return 1082; // date
|
|
209
|
-
// Timestamp in YYYY-MM-DDTHH:MM:SS[.fraction] format
|
|
210
|
-
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?$/.test(elem)) return 1114; // timestamp without timezone
|
|
211
|
-
// Timestamp in YYYY-MM-DDTHH:MM:SS[.fraction]Z format
|
|
212
|
-
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/.test(elem))
|
|
213
|
-
return 1184; // timestamp with timezone
|
|
214
|
-
// Time in HH:MM:SS format
|
|
215
|
-
if (/^\d{2}:\d{2}:\d{2}$/.test(elem)) return 1083; // time
|
|
216
|
-
return 1043; // varchar
|
|
217
|
-
}
|
|
218
|
-
// Add more specific cases or different data types as needed
|
|
219
|
-
return 1043; // default or unknown type
|
|
220
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { Mappable, CacheCredentials } from "../models/Cache";
|
|
2
|
-
import { QuillConfig } from "../models/Quill";
|
|
3
|
-
import { createClient } from "redis";
|
|
4
|
-
import { isSuperset, PgError } from "../utils/Error";
|
|
5
|
-
import {
|
|
6
|
-
DatabaseConnection,
|
|
7
|
-
connectToDatabase,
|
|
8
|
-
disconnectFromDatabase,
|
|
9
|
-
runQueryByDatabase,
|
|
10
|
-
} from "./DatabaseHelper";
|
|
11
|
-
import { PostgresConnectionConfig } from "./Postgres";
|
|
12
|
-
import { SnowflakeConnectionConfig } from "./Snowflake";
|
|
13
|
-
import { BigQueryConfig } from "./BigQuery";
|
|
14
|
-
import { MysqlConnectionConfig } from "./Mysql";
|
|
15
|
-
|
|
16
|
-
/** The TTL for new cache entries (default: 1h) */
|
|
17
|
-
const DEFAULT_CACHE_TTL = 24 * 60 * 60;
|
|
18
|
-
|
|
19
|
-
export class CachedConnection {
|
|
20
|
-
public databaseType: "postgresql" | "snowflake" | "bigquery" | "mysql";
|
|
21
|
-
public readonly pool: DatabaseConnection;
|
|
22
|
-
public orgId: any;
|
|
23
|
-
public ttl: number;
|
|
24
|
-
public cache: Mappable | null;
|
|
25
|
-
|
|
26
|
-
private _isClosed: boolean = false;
|
|
27
|
-
public get isClosed(): boolean {
|
|
28
|
-
return this._isClosed;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
constructor(
|
|
32
|
-
databaseType: "postgresql" | "snowflake" | "bigquery" | "mysql",
|
|
33
|
-
config:
|
|
34
|
-
| PostgresConnectionConfig
|
|
35
|
-
| SnowflakeConnectionConfig
|
|
36
|
-
| BigQueryConfig
|
|
37
|
-
| MysqlConnectionConfig,
|
|
38
|
-
cacheConfig: Partial<CacheCredentials> = {},
|
|
39
|
-
) {
|
|
40
|
-
this.databaseType = databaseType;
|
|
41
|
-
this.pool = connectToDatabase(databaseType, config);
|
|
42
|
-
this.ttl = cacheConfig?.ttl ?? DEFAULT_CACHE_TTL;
|
|
43
|
-
this.cache = this.getCache(cacheConfig);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
public async query(text: string): Promise<any> {
|
|
47
|
-
try {
|
|
48
|
-
if (this.isClosed) {
|
|
49
|
-
throw new Error("Connection is closed");
|
|
50
|
-
}
|
|
51
|
-
if (!this.cache) {
|
|
52
|
-
return await runQueryByDatabase(this.databaseType, this.pool, text);
|
|
53
|
-
}
|
|
54
|
-
const key: string = `${this.orgId}:${text}`;
|
|
55
|
-
const cachedResult: string | null = await this.cache.get(key);
|
|
56
|
-
if (cachedResult) {
|
|
57
|
-
return JSON.parse(cachedResult);
|
|
58
|
-
} else {
|
|
59
|
-
const newResult = await runQueryByDatabase(
|
|
60
|
-
this.databaseType,
|
|
61
|
-
this.pool,
|
|
62
|
-
text,
|
|
63
|
-
);
|
|
64
|
-
const newResultString: string = JSON.stringify(newResult);
|
|
65
|
-
await this.cache.set(key, newResultString, "EX", DEFAULT_CACHE_TTL);
|
|
66
|
-
return newResult;
|
|
67
|
-
}
|
|
68
|
-
} catch (err) {
|
|
69
|
-
if (isSuperset(err, PgError)) {
|
|
70
|
-
throw new PgError(
|
|
71
|
-
(err as any).message,
|
|
72
|
-
(err as any).detail,
|
|
73
|
-
(err as any).hint,
|
|
74
|
-
(err as any).position,
|
|
75
|
-
);
|
|
76
|
-
} else if (err instanceof Error) {
|
|
77
|
-
throw new Error(err.message);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Configures and returns a cache instance or null if none could be created.
|
|
84
|
-
*/
|
|
85
|
-
private getCache({
|
|
86
|
-
username,
|
|
87
|
-
password,
|
|
88
|
-
host,
|
|
89
|
-
port,
|
|
90
|
-
cacheType,
|
|
91
|
-
}: QuillConfig["cache"]): Mappable | null {
|
|
92
|
-
if (cacheType === "redis" || cacheType === "rediss") {
|
|
93
|
-
const redisURL = `${cacheType}://${username}:${password}@${host}:${port}`;
|
|
94
|
-
const client = createClient({ url: redisURL });
|
|
95
|
-
client.connect();
|
|
96
|
-
return client as Mappable;
|
|
97
|
-
}
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
public getPool() {
|
|
102
|
-
return this.pool;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async close() {
|
|
106
|
-
disconnectFromDatabase(this.databaseType, this.pool);
|
|
107
|
-
this._isClosed = true;
|
|
108
|
-
}
|
|
109
|
-
}
|