@quillsql/node 0.3.7 → 0.4.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 +2785 -0
- package/dist/db/BigQuery.js +201 -0
- package/dist/db/{CachedPools.js → CachedConnection.js} +11 -23
- package/dist/db/DatabaseHelper.js +187 -0
- package/dist/db/Mysql.js +192 -0
- package/dist/db/Postgres.js +161 -0
- package/dist/db/Snowflake.js +189 -0
- package/dist/index.js +80 -24
- package/dist/index.uspec.js +3 -2
- package/dist/models/Client.js +2 -0
- package/dist/utils/RunQueryProcesses.js +3 -18
- package/dist/utils/schemaConversion.js +15 -0
- package/dist/utils/textProcessing.js +17 -0
- package/examples/node-server/app.ts +40 -9
- package/package.json +6 -2
- package/src/assets/pgtypes.ts +2782 -0
- package/src/db/BigQuery.ts +213 -0
- package/src/db/{CachedPools.ts → CachedConnection.ts} +25 -21
- package/src/db/DatabaseHelper.ts +352 -0
- package/src/db/Mysql.ts +216 -0
- package/src/db/Postgres.ts +187 -0
- package/src/db/Snowflake.ts +203 -0
- package/src/index.ts +136 -34
- package/src/index.uspec.ts +9 -2
- package/src/models/Client.ts +29 -0
- package/src/models/Quill.ts +10 -6
- package/src/utils/RunQueryProcesses.ts +3 -26
- package/src/utils/schemaConversion.ts +11 -0
- package/src/utils/textProcessing.ts +13 -0
package/src/index.ts
CHANGED
|
@@ -5,14 +5,22 @@ import {
|
|
|
5
5
|
QuillClientResponse,
|
|
6
6
|
QuillQueryParams,
|
|
7
7
|
} from "./models/Quill";
|
|
8
|
-
import {
|
|
8
|
+
import { CachedConnection } from "./db/CachedConnection";
|
|
9
9
|
import axios from "axios";
|
|
10
10
|
import "dotenv/config";
|
|
11
|
+
import { mapQueries, removeFields } from "./utils/RunQueryProcesses";
|
|
11
12
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
DatabaseType,
|
|
14
|
+
connectToDatabase,
|
|
15
|
+
getColumnInfoBySchemaByDatabase,
|
|
16
|
+
getColumnsByTableByDatabase,
|
|
17
|
+
getDatabaseCredentials,
|
|
18
|
+
getForiegnKeysByDatabase,
|
|
19
|
+
getSchemasByDatabase,
|
|
20
|
+
getTablesBySchemaByDatabase,
|
|
21
|
+
runQueryByDatabase,
|
|
22
|
+
} from "./db/DatabaseHelper";
|
|
23
|
+
import { convertTypeToPostgres } from "./utils/schemaConversion";
|
|
16
24
|
|
|
17
25
|
const HOST =
|
|
18
26
|
process.env.ENV === "development"
|
|
@@ -25,9 +33,7 @@ const HOST =
|
|
|
25
33
|
|
|
26
34
|
export default class QuillClass {
|
|
27
35
|
// Configure cached connection pools with the given config.
|
|
28
|
-
|
|
29
|
-
private ssl = { rejectUnauthorized: false };
|
|
30
|
-
public targetPool;
|
|
36
|
+
public targetConnection;
|
|
31
37
|
private baseUrl: string;
|
|
32
38
|
private config: {
|
|
33
39
|
headers: {
|
|
@@ -37,29 +43,50 @@ export default class QuillClass {
|
|
|
37
43
|
|
|
38
44
|
constructor(
|
|
39
45
|
privateKey: string,
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
databaseType: DatabaseType,
|
|
47
|
+
databaseConnectionString?: string,
|
|
48
|
+
databaseCredentials?: any,
|
|
49
|
+
cache: Partial<CacheCredentials> = {},
|
|
50
|
+
metadataServerURL?: string
|
|
42
51
|
) {
|
|
43
|
-
this.baseUrl = HOST;
|
|
52
|
+
this.baseUrl = metadataServerURL ? metadataServerURL : HOST;
|
|
44
53
|
this.config = { headers: { Authorization: `Bearer ${privateKey}` } };
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
let credentials = databaseCredentials;
|
|
55
|
+
if (databaseConnectionString) {
|
|
56
|
+
credentials = getDatabaseCredentials(
|
|
57
|
+
databaseType,
|
|
58
|
+
databaseConnectionString
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
this.targetConnection = new CachedConnection(
|
|
62
|
+
databaseType,
|
|
63
|
+
credentials,
|
|
49
64
|
cache
|
|
50
65
|
);
|
|
51
66
|
}
|
|
52
67
|
|
|
53
68
|
public async query({ orgId, metadata }: QuillQueryParams): Promise<any> {
|
|
54
|
-
this.
|
|
55
|
-
|
|
69
|
+
this.targetConnection.orgId = orgId;
|
|
56
70
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
71
|
+
const preQueryResults = metadata.preQueries
|
|
72
|
+
? await this.runQueries(
|
|
73
|
+
metadata.preQueries,
|
|
74
|
+
this.targetConnection.databaseType,
|
|
75
|
+
metadata.databaseType,
|
|
76
|
+
metadata.runQueryConfig
|
|
77
|
+
)
|
|
78
|
+
: {};
|
|
79
|
+
if (metadata.runQueryConfig?.overridePost) {
|
|
80
|
+
return {
|
|
81
|
+
data: { queryResults: preQueryResults },
|
|
82
|
+
status: "success",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
59
85
|
const response = await this.postQuill(metadata.task, {
|
|
60
86
|
...metadata,
|
|
87
|
+
...preQueryResults,
|
|
61
88
|
orgId,
|
|
62
|
-
|
|
89
|
+
viewQuery: metadata.preQueries ? metadata.preQueries[0] : undefined,
|
|
63
90
|
});
|
|
64
91
|
// if there is no metadata object in the response, create one
|
|
65
92
|
if (!response.metadata) {
|
|
@@ -67,6 +94,8 @@ export default class QuillClass {
|
|
|
67
94
|
}
|
|
68
95
|
const results = await this.runQueries(
|
|
69
96
|
response.queries,
|
|
97
|
+
this.targetConnection.databaseType,
|
|
98
|
+
metadata.databaseType,
|
|
70
99
|
response.metadata.runQueryConfig
|
|
71
100
|
);
|
|
72
101
|
// QUICK JANKY FIX TO UPDATE METADATA AFTER GETTING MAPPED ARRAYS
|
|
@@ -103,36 +132,87 @@ export default class QuillClass {
|
|
|
103
132
|
|
|
104
133
|
private async runQueries(
|
|
105
134
|
queries: string[] | undefined,
|
|
135
|
+
pkDatabaseType: DatabaseType,
|
|
136
|
+
databaseType?: string,
|
|
106
137
|
runQueryConfig?: AdditionalProcessing
|
|
107
138
|
) {
|
|
108
139
|
let results: any;
|
|
109
140
|
if (!queries) return { ...results, queryResults: [] };
|
|
141
|
+
if (
|
|
142
|
+
databaseType &&
|
|
143
|
+
databaseType.toLowerCase() !== pkDatabaseType.toLowerCase()
|
|
144
|
+
) {
|
|
145
|
+
return {
|
|
146
|
+
dbMismatched: true,
|
|
147
|
+
backendDatbaseType: pkDatabaseType,
|
|
148
|
+
queryResults: [],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
110
151
|
if (runQueryConfig?.arrayToMap) {
|
|
111
|
-
const mappedArray = await mapQueries(
|
|
112
|
-
queries,
|
|
113
|
-
runQueryConfig.arrayToMap,
|
|
114
|
-
this.targetPool
|
|
115
|
-
);
|
|
152
|
+
const mappedArray = await mapQueries(queries, this.targetConnection);
|
|
116
153
|
return { ...results, queryResults: [], mappedArray };
|
|
154
|
+
} else if (runQueryConfig?.getColumns) {
|
|
155
|
+
const queryResult = await this.targetConnection.query(
|
|
156
|
+
`${queries[0]} limit 1`
|
|
157
|
+
);
|
|
158
|
+
const columns = queryResult.fields.map((field: any) => {
|
|
159
|
+
return {
|
|
160
|
+
fieldType: convertTypeToPostgres(field.dataTypeID),
|
|
161
|
+
name: field.name,
|
|
162
|
+
displayName: field.name,
|
|
163
|
+
isVisible: true,
|
|
164
|
+
field: field.name,
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
return { columns };
|
|
168
|
+
} else if (runQueryConfig?.getTables) {
|
|
169
|
+
const queryResult = await getTablesBySchemaByDatabase(
|
|
170
|
+
this.targetConnection.databaseType,
|
|
171
|
+
this.targetConnection.pool,
|
|
172
|
+
runQueryConfig.schemaNames! || runQueryConfig.schema
|
|
173
|
+
);
|
|
174
|
+
const schemaInfo = await getColumnInfoBySchemaByDatabase(
|
|
175
|
+
this.targetConnection.databaseType,
|
|
176
|
+
this.targetConnection.pool,
|
|
177
|
+
runQueryConfig.schema!,
|
|
178
|
+
queryResult!
|
|
179
|
+
);
|
|
180
|
+
return schemaInfo;
|
|
117
181
|
} else {
|
|
182
|
+
if (runQueryConfig?.limitThousand) {
|
|
183
|
+
queries = queries.map((query) => {
|
|
184
|
+
return query.replace(/;/, "") + " limit 1000;";
|
|
185
|
+
});
|
|
186
|
+
}
|
|
118
187
|
const queryResults = await Promise.all(
|
|
119
188
|
queries.map(async (query) => {
|
|
120
|
-
return await this.
|
|
189
|
+
return await this.targetConnection.query(query);
|
|
121
190
|
})
|
|
122
191
|
);
|
|
123
192
|
results = { ...results, queryResults };
|
|
124
|
-
if (runQueryConfig?.getSchema) {
|
|
125
|
-
results = {
|
|
126
|
-
...results,
|
|
127
|
-
columns: await getTableSchema(queryResults[0], this.targetPool),
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
193
|
if (runQueryConfig?.removeFields) {
|
|
131
194
|
results = {
|
|
132
195
|
...results,
|
|
133
196
|
queryResults: removeFields(queryResults, runQueryConfig.removeFields),
|
|
134
197
|
};
|
|
135
198
|
}
|
|
199
|
+
if (runQueryConfig?.convertDatatypes) {
|
|
200
|
+
results = queryResults.map((result) => {
|
|
201
|
+
return {
|
|
202
|
+
fields: result.fields.map((field: any) => {
|
|
203
|
+
return {
|
|
204
|
+
...field,
|
|
205
|
+
fieldType: convertTypeToPostgres(field.dataTypeID),
|
|
206
|
+
isVisible: true,
|
|
207
|
+
field: field.name,
|
|
208
|
+
displayName: field.name,
|
|
209
|
+
name: field.name,
|
|
210
|
+
};
|
|
211
|
+
}),
|
|
212
|
+
rows: result.rows,
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
}
|
|
136
216
|
}
|
|
137
217
|
return results;
|
|
138
218
|
}
|
|
@@ -150,22 +230,44 @@ export default class QuillClass {
|
|
|
150
230
|
}
|
|
151
231
|
|
|
152
232
|
public async close() {
|
|
153
|
-
await this.
|
|
233
|
+
await this.targetConnection.close();
|
|
154
234
|
}
|
|
155
235
|
}
|
|
156
236
|
|
|
157
237
|
const Quill = ({
|
|
158
238
|
privateKey,
|
|
159
239
|
databaseConnectionString,
|
|
240
|
+
databaseConfig,
|
|
160
241
|
cache,
|
|
242
|
+
databaseType,
|
|
243
|
+
metadataServerURL,
|
|
161
244
|
}: {
|
|
162
245
|
privateKey: string;
|
|
163
246
|
databaseConnectionString: string;
|
|
164
247
|
cache?: Partial<CacheCredentials>;
|
|
248
|
+
databaseType: DatabaseType;
|
|
249
|
+
databaseConfig: any;
|
|
250
|
+
metadataServerURL?: string;
|
|
165
251
|
}) => {
|
|
166
|
-
return new QuillClass(
|
|
252
|
+
return new QuillClass(
|
|
253
|
+
privateKey,
|
|
254
|
+
databaseType,
|
|
255
|
+
databaseConnectionString,
|
|
256
|
+
databaseConfig,
|
|
257
|
+
cache,
|
|
258
|
+
metadataServerURL
|
|
259
|
+
);
|
|
167
260
|
};
|
|
168
261
|
|
|
169
262
|
module.exports = Quill;
|
|
170
263
|
module.exports.Quill = Quill;
|
|
171
264
|
module.exports.default = Quill;
|
|
265
|
+
module.exports.getTablesBySchemaByDatabase = getTablesBySchemaByDatabase;
|
|
266
|
+
module.exports.getDatabaseCredentials = getDatabaseCredentials;
|
|
267
|
+
module.exports.getColumnsByTableByDatabase = getColumnsByTableByDatabase;
|
|
268
|
+
module.exports.getForiegnKeysByDatabase = getForiegnKeysByDatabase;
|
|
269
|
+
module.exports.getSchemasByDatabase = getSchemasByDatabase;
|
|
270
|
+
module.exports.getColumnInfoBySchemaByDatabase =
|
|
271
|
+
getColumnInfoBySchemaByDatabase;
|
|
272
|
+
module.exports.connectToDatabase = connectToDatabase;
|
|
273
|
+
module.exports.runQueryByDatabase = runQueryByDatabase;
|
package/src/index.uspec.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Quill from ".";
|
|
2
|
+
import { DatabaseType } from "./db/DatabaseHelper";
|
|
2
3
|
|
|
3
4
|
jest.mock(".");
|
|
4
5
|
|
|
@@ -6,8 +7,14 @@ describe("Quill", () => {
|
|
|
6
7
|
let quill: Quill;
|
|
7
8
|
|
|
8
9
|
beforeEach(() => {
|
|
9
|
-
quill = new Quill(
|
|
10
|
-
|
|
10
|
+
quill = new Quill(
|
|
11
|
+
"dummy_private_key",
|
|
12
|
+
DatabaseType.postgres,
|
|
13
|
+
"dummy_db_url",
|
|
14
|
+
{},
|
|
15
|
+
undefined
|
|
16
|
+
);
|
|
17
|
+
quill.targetConnection.query = jest.fn().mockResolvedValue([]);
|
|
11
18
|
});
|
|
12
19
|
|
|
13
20
|
describe("query", () => {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface Client {
|
|
2
|
+
name: string;
|
|
3
|
+
databaseConnectionString: string;
|
|
4
|
+
etlDatabaseConnectionString: string;
|
|
5
|
+
stagingDatabaseConnectionString: string;
|
|
6
|
+
customerTableTitleFieldName: string;
|
|
7
|
+
databaseType: string;
|
|
8
|
+
// foreign key
|
|
9
|
+
customerFieldName: string;
|
|
10
|
+
// native key, ex: uuid
|
|
11
|
+
customerTableFieldName: string;
|
|
12
|
+
// table with all customers, ex: company_company
|
|
13
|
+
customerTableName: string;
|
|
14
|
+
customerView: string;
|
|
15
|
+
// sql type. ex: INT
|
|
16
|
+
customerFieldType: string;
|
|
17
|
+
// does db use ssl
|
|
18
|
+
useSsl: boolean;
|
|
19
|
+
serverCa: string;
|
|
20
|
+
clientCert: string;
|
|
21
|
+
clientKey: string;
|
|
22
|
+
defaultQuery: string;
|
|
23
|
+
ignoreDarkMode: boolean;
|
|
24
|
+
domainName: string;
|
|
25
|
+
hideSqlEditor: boolean;
|
|
26
|
+
adminCustomerId: string;
|
|
27
|
+
stagingAdminCustomerId: string;
|
|
28
|
+
cacheCloudConfig: { type: { cacheQueries: boolean }; default: null };
|
|
29
|
+
}
|
package/src/models/Quill.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { CachedPool } from "../db/CachedPools";
|
|
2
1
|
import { CacheCredentials } from "./Cache";
|
|
3
2
|
import { DatabaseCredentials } from "./Database";
|
|
4
3
|
import { FieldFormat, FormattedColumn } from "./Formats";
|
|
@@ -8,6 +7,7 @@ export interface QuillRequestMetadata {
|
|
|
8
7
|
// a query to be run
|
|
9
8
|
queries?: string[];
|
|
10
9
|
preQueries?: string[];
|
|
10
|
+
runQueryConfig?: AdditionalProcessing;
|
|
11
11
|
query?: string;
|
|
12
12
|
// a report to be fetched
|
|
13
13
|
id?: string;
|
|
@@ -26,6 +26,7 @@ export interface QuillRequestMetadata {
|
|
|
26
26
|
template?: boolean;
|
|
27
27
|
clientId?: string;
|
|
28
28
|
deleted?: boolean;
|
|
29
|
+
databaseType?: string
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export interface QuillQueryParams {
|
|
@@ -34,11 +35,6 @@ export interface QuillQueryParams {
|
|
|
34
35
|
environment?: string;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
export interface QuillTaskHandlerParams extends QuillQueryParams {
|
|
38
|
-
privateKey: string;
|
|
39
|
-
targetPool: CachedPool;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
38
|
export interface QuillConfig {
|
|
43
39
|
privateKey: string;
|
|
44
40
|
db: Partial<DatabaseCredentials>;
|
|
@@ -57,8 +53,16 @@ export interface QuillConfig {
|
|
|
57
53
|
|
|
58
54
|
export interface AdditionalProcessing {
|
|
59
55
|
getSchema?: boolean;
|
|
56
|
+
getColumns?: boolean;
|
|
57
|
+
getTables?: boolean;
|
|
58
|
+
schema?: string,
|
|
59
|
+
schemaNames?: string[];
|
|
60
|
+
table?: string,
|
|
60
61
|
removeFields?: string[];
|
|
61
62
|
arrayToMap?: { arrayName: string; field: string };
|
|
63
|
+
overridePost?: boolean;
|
|
64
|
+
convertDatatypes?: boolean
|
|
65
|
+
limitThousand?: boolean;
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
export interface QuillClientResponse {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CachedConnection } from "../db/CachedConnection";
|
|
2
2
|
|
|
3
3
|
interface TableSchemaInfo {
|
|
4
4
|
fieldType: string;
|
|
@@ -7,28 +7,6 @@ interface TableSchemaInfo {
|
|
|
7
7
|
isVisible: boolean;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export async function getTableSchema(
|
|
11
|
-
queryResults: any,
|
|
12
|
-
targetPool: CachedPool
|
|
13
|
-
) {
|
|
14
|
-
const typesQuery = await targetPool.query(
|
|
15
|
-
"select typname, oid, typarray from pg_type order by oid;"
|
|
16
|
-
);
|
|
17
|
-
const schema: TableSchemaInfo[] = queryResults[0].fields.map(
|
|
18
|
-
(field: { dataTypeID: any; name: any }) => {
|
|
19
|
-
return {
|
|
20
|
-
fieldType: typesQuery.rows.filter(
|
|
21
|
-
(type: { oid: any }) => field.dataTypeID === type.oid
|
|
22
|
-
)[0].typname,
|
|
23
|
-
name: field.name,
|
|
24
|
-
displayName: field.name,
|
|
25
|
-
isVisible: true,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
);
|
|
29
|
-
return schema;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
10
|
export function removeFields(queryResults: any, fieldsToRemove: string[]): any {
|
|
33
11
|
const fields = queryResults.fields.filter((field: { name: any }) =>
|
|
34
12
|
fieldsToRemove.includes(field.name)
|
|
@@ -43,12 +21,11 @@ export function removeFields(queryResults: any, fieldsToRemove: string[]): any {
|
|
|
43
21
|
|
|
44
22
|
export async function mapQueries(
|
|
45
23
|
queries: string[],
|
|
46
|
-
|
|
47
|
-
targetPool: CachedPool
|
|
24
|
+
targetConnection: CachedConnection
|
|
48
25
|
): Promise<any[]> {
|
|
49
26
|
const mappedArray = [];
|
|
50
27
|
for (let i = 0; i < queries.length; i++) {
|
|
51
|
-
const queryResult = await
|
|
28
|
+
const queryResult = await targetConnection.query(queries[i]);
|
|
52
29
|
mappedArray.push(queryResult.rows);
|
|
53
30
|
}
|
|
54
31
|
return mappedArray;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PG_TYPES } from "../assets/pgtypes";
|
|
2
|
+
|
|
3
|
+
export function convertTypeToPostgres(data_type_id: number): string {
|
|
4
|
+
const type = PG_TYPES.find((type) => data_type_id === type.oid)
|
|
5
|
+
? PG_TYPES.find((type) => data_type_id === type.oid)?.typname
|
|
6
|
+
: undefined;
|
|
7
|
+
if (!type) {
|
|
8
|
+
return "varchar";
|
|
9
|
+
}
|
|
10
|
+
return type;
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function capitalize(text: string): string {
|
|
2
|
+
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function depluralize(text: string): string {
|
|
6
|
+
if (text.endsWith("ies")) {
|
|
7
|
+
return text.slice(0, -3) + "y";
|
|
8
|
+
}
|
|
9
|
+
if (text.endsWith("s")) {
|
|
10
|
+
return text.slice(0, -1);
|
|
11
|
+
}
|
|
12
|
+
return text;
|
|
13
|
+
}
|