@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/src/index.ts CHANGED
@@ -5,14 +5,22 @@ import {
5
5
  QuillClientResponse,
6
6
  QuillQueryParams,
7
7
  } from "./models/Quill";
8
- import { CachedPool } from "./db/CachedPools";
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
- getTableSchema,
13
- mapQueries,
14
- removeFields,
15
- } from "./utils/RunQueryProcesses";
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
- private connectionString;
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
- databaseConnectionString: string,
41
- cache: Partial<CacheCredentials> = {}
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
- this.connectionString = databaseConnectionString;
46
- this.ssl = { rejectUnauthorized: false };
47
- this.targetPool = new CachedPool(
48
- { connectionString: this.connectionString, ssl: this.ssl },
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.targetPool.orgId = orgId;
55
-
69
+ this.targetConnection.orgId = orgId;
56
70
  try {
57
- // Initial Query Request
58
- const preQueryResults = await this.runQueries(metadata.preQueries);
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
- preQueryResults,
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.targetPool.query(query);
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.targetPool.close();
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(privateKey, databaseConnectionString, cache);
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;
@@ -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("dummy_private_key", "dummy_db_url");
10
- quill.targetPool.query = jest.fn().mockResolvedValue([]);
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
+ }
@@ -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 { CachedPool } from "../db/CachedPools";
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
- arrayToMap: { arrayName: string; field: string },
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 targetPool.query(queries[i]);
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
+ }