@quillsql/node 0.5.8 → 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.
@@ -1,10 +1,8 @@
1
1
  import { Pool } from "pg";
2
- import { Client } from "../models/Client";
3
- import { disconnect } from "process";
2
+ // import { Client } from "../models/Client";
4
3
  import { QuillQueryResults } from "./DatabaseHelper";
5
4
  import { capitalize, depluralize } from "../utils/textProcessing";
6
5
  import { PG_TYPES } from "../assets/pgtypes";
7
- import { run } from "node:test";
8
6
 
9
7
  export type PostgresConnectionConfig = {
10
8
  connectionString: string;
@@ -26,7 +24,7 @@ export function disconnectFromPostgres(pool: Pool) {
26
24
 
27
25
  export async function runQueryPostgres(
28
26
  sql: string,
29
- pool: Pool
27
+ pool: Pool,
30
28
  ): Promise<QuillQueryResults> {
31
29
  const results = await pool.query(sql);
32
30
  return {
@@ -47,7 +45,7 @@ export async function getSchemasPostgres(pool: Pool): Promise<string[]> {
47
45
 
48
46
  export async function getTablesBySchemaPostgres(
49
47
  pool: Pool,
50
- schemaNames: string[]
48
+ schemaNames: string[],
51
49
  ): Promise<{ tableName: string; schemaName: string }[]> {
52
50
  const allColumns = await Promise.all(
53
51
  schemaNames.map(async (schema) => {
@@ -56,7 +54,7 @@ export async function getTablesBySchemaPostgres(
56
54
  return results.rows.map((row) => {
57
55
  return { tableName: row.table_name, schemaName: row.table_schema };
58
56
  });
59
- })
57
+ }),
60
58
  );
61
59
  return allColumns.flat();
62
60
  }
@@ -64,7 +62,7 @@ export async function getTablesBySchemaPostgres(
64
62
  export async function getColumnsByTablePostgres(
65
63
  pool: Pool,
66
64
  schemaName: string,
67
- tableName: string
65
+ tableName: string,
68
66
  ): Promise<string[]> {
69
67
  const sql = `SELECT column_name FROM information_schema.columns WHERE table_schema = '${schemaName}' and table_name = '${tableName}'`;
70
68
  const results = await runQueryPostgres(sql, pool);
@@ -75,7 +73,7 @@ export async function getForeignKeysPostgres(
75
73
  pool: Pool,
76
74
  schemaName: string,
77
75
  tableName: string,
78
- primaryKey: string
76
+ primaryKey: string,
79
77
  ): Promise<string[]> {
80
78
  const depluralizedTableName = depluralize(tableName);
81
79
  let sql = `SELECT column_name FROM information_schema.columns
@@ -89,7 +87,7 @@ export async function getForeignKeysPostgres(
89
87
  return key.column_name;
90
88
  });
91
89
  foreignKeysString = foreignKeysString.filter(
92
- (key) => key !== "id" && key !== "_id_"
90
+ (key) => key !== "id" && key !== "_id_",
93
91
  );
94
92
  foreignKeysString = [...new Set(foreignKeysString)];
95
93
  if (foreignKeysString.length === 0) {
@@ -113,7 +111,7 @@ export async function getForeignKeysPostgres(
113
111
  export async function getSchemaColumnInfoPostgress(
114
112
  pool: Pool,
115
113
  schemaName: string,
116
- tableNames: { tableName: string; schemaName: string }[]
114
+ tableNames: { tableName: string; schemaName: string }[],
117
115
  ): Promise<
118
116
  { tableName: string; columns: { columnName: string; dataTypeID: number }[] }[]
119
117
  > {
@@ -145,43 +143,43 @@ export async function getSchemaColumnInfoPostgress(
145
143
  };
146
144
  }),
147
145
  };
148
- })
146
+ }),
149
147
  );
150
148
  return allColumns;
151
149
  }
152
150
 
153
151
  export function formatPostgresConfig(
154
- connectionString: string
152
+ connectionString: string,
155
153
  ): PostgresConnectionConfig {
156
154
  return { connectionString, ssl: { rejectUnauthorized: false } };
157
155
  }
158
156
 
159
157
  // CURRENTLY UNUSED BUT MAYBE USEFUL IN THE FUTURE
160
- function getSslConfig(client: Client):
161
- | {
162
- rejectUnauthorized: false;
163
- ca?: string;
164
- key?: string;
165
- cert?: string;
166
- }
167
- | undefined {
168
- if (!client.useSsl) {
169
- return undefined;
170
- }
171
- if (client.serverCa && client.clientKey && client.clientCert) {
172
- return {
173
- rejectUnauthorized: false,
174
- ca: client.serverCa,
175
- key: client.clientKey,
176
- cert: client.clientCert,
177
- };
178
- }
179
- if (client.serverCa) {
180
- return {
181
- rejectUnauthorized: false,
182
- ca: client.serverCa,
183
- };
184
- }
185
- // if using ssl with no certificates
186
- return { rejectUnauthorized: false };
187
- }
158
+ // function getSslConfig(client: Client):
159
+ // | {
160
+ // rejectUnauthorized: false;
161
+ // ca?: string;
162
+ // key?: string;
163
+ // cert?: string;
164
+ // }
165
+ // | undefined {
166
+ // if (!client.useSsl) {
167
+ // return undefined;
168
+ // }
169
+ // if (client.serverCa && client.clientKey && client.clientCert) {
170
+ // return {
171
+ // rejectUnauthorized: false,
172
+ // ca: client.serverCa,
173
+ // key: client.clientKey,
174
+ // cert: client.clientCert,
175
+ // };
176
+ // }
177
+ // if (client.serverCa) {
178
+ // return {
179
+ // rejectUnauthorized: false,
180
+ // ca: client.serverCa,
181
+ // };
182
+ // }
183
+ // // if using ssl with no certificates
184
+ // return { rejectUnauthorized: false };
185
+ // }
@@ -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, conn) => {
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
- let depluralizedTableName = depluralize(tableName);
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.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,
@@ -76,13 +75,13 @@ export class Quill {
76
75
  if (databaseConnectionString) {
77
76
  credentials = getDatabaseCredentials(
78
77
  databaseType,
79
- databaseConnectionString
78
+ databaseConnectionString,
80
79
  );
81
80
  }
82
81
  this.targetConnection = new CachedConnection(
83
82
  databaseType,
84
83
  credentials,
85
- cache || {}
84
+ cache || {},
86
85
  );
87
86
  }
88
87
 
@@ -92,13 +91,18 @@ export class Quill {
92
91
  }: QuillQueryParams): Promise<QuillQueryResult> {
93
92
  this.targetConnection.orgId = orgId;
94
93
  let responseMetadata: any = {};
94
+
95
+ if (!metadata.task) {
96
+ return { error: "Missing task.", status: "error", data: {} };
97
+ }
98
+
95
99
  try {
96
100
  const preQueryResults = metadata.preQueries
97
101
  ? await this.runQueries(
98
102
  metadata.preQueries,
99
103
  this.targetConnection.databaseType,
100
104
  metadata.databaseType,
101
- metadata.runQueryConfig
105
+ metadata.runQueryConfig,
102
106
  )
103
107
  : {};
104
108
  if (metadata.runQueryConfig?.overridePost) {
@@ -114,7 +118,11 @@ export class Quill {
114
118
  viewQuery: metadata.preQueries ? metadata.preQueries[0] : undefined,
115
119
  });
116
120
  if (response.error) {
117
- return { status: "error", error: response.error };
121
+ return {
122
+ status: "error",
123
+ error: response.error,
124
+ data: response.metadata || {},
125
+ };
118
126
  }
119
127
  // if there is no metadata object in the response, create one
120
128
  if (response.metadata) {
@@ -124,7 +132,7 @@ export class Quill {
124
132
  response.queries,
125
133
  this.targetConnection.databaseType,
126
134
  metadata.databaseType,
127
- responseMetadata.runQueryConfig
135
+ responseMetadata.runQueryConfig,
128
136
  );
129
137
  // QUICK JANKY FIX TO UPDATE METADATA AFTER GETTING MAPPED ARRAYS
130
138
  if (results.mappedArray && responseMetadata.runQueryConfig?.arrayToMap) {
@@ -153,8 +161,8 @@ export class Quill {
153
161
  } catch (err) {
154
162
  return {
155
163
  status: "error",
156
- error: (err as any).message,
157
- data: responseMetadata,
164
+ error: (err as any).response?.data?.error ?? (err as any).message,
165
+ data: responseMetadata || {},
158
166
  };
159
167
  }
160
168
  }
@@ -163,7 +171,7 @@ export class Quill {
163
171
  queries: any[] | undefined,
164
172
  pkDatabaseType: "postgresql" | "snowflake" | "bigquery" | "mysql",
165
173
  databaseType?: string,
166
- runQueryConfig?: AdditionalProcessing
174
+ runQueryConfig?: AdditionalProcessing,
167
175
  ) {
168
176
  let results: any;
169
177
  if (!queries) return { ...results, queryResults: [] };
@@ -177,12 +185,13 @@ export class Quill {
177
185
  queryResults: [],
178
186
  };
179
187
  }
188
+
180
189
  if (runQueryConfig?.arrayToMap) {
181
190
  const mappedArray = await mapQueries(queries, this.targetConnection);
182
191
  return { ...results, queryResults: [], mappedArray };
183
192
  } else if (runQueryConfig?.getColumns) {
184
193
  const queryResult = await this.targetConnection.query(
185
- `${queries[0].replace(/;/, "")} limit 1`
194
+ `${queries[0].replace(/;/, "")} limit 1`,
186
195
  );
187
196
  const columns = queryResult.fields.map((field: any) => {
188
197
  return {
@@ -209,7 +218,7 @@ export class Quill {
209
218
  }
210
219
  try {
211
220
  const queryResult = await this.targetConnection.query(
212
- `${table.viewQuery.replace(/;/, "")} ${limit}`
221
+ `${table.viewQuery.replace(/;/, "")} ${limit}`,
213
222
  );
214
223
  const columns = queryResult.fields.map((field: any) => {
215
224
  return {
@@ -221,10 +230,15 @@ export class Quill {
221
230
  };
222
231
  });
223
232
  return { ...table, columns: columns, rows: queryResult.rows };
224
- } catch (err) {
225
- return { ...table, error: "Error fetching columns" };
233
+ } catch (err: any) {
234
+ return {
235
+ ...table,
236
+ error: err.message
237
+ ? `Error fetching columns: ${err.message}`
238
+ : "Error fetching columns",
239
+ };
226
240
  }
227
- })
241
+ }),
228
242
  );
229
243
  results = { ...results, queryResults };
230
244
  if (runQueryConfig?.fieldsToRemove) {
@@ -241,15 +255,16 @@ export class Quill {
241
255
  } else if (runQueryConfig?.getTables) {
242
256
  const queryResult = await getTablesBySchemaByDatabase(
243
257
  this.targetConnection.databaseType,
244
- this.targetConnection.pool,
245
- runQueryConfig.schemaNames! || runQueryConfig.schema
258
+ this.targetConnection.getPool(),
259
+ runQueryConfig.schemaNames! || runQueryConfig.schema,
246
260
  );
247
261
  const schemaInfo = await getColumnInfoBySchemaByDatabase(
248
262
  this.targetConnection.databaseType,
249
- this.targetConnection.pool,
263
+ this.targetConnection.getPool(),
250
264
  runQueryConfig.schema!,
251
- queryResult!
265
+ queryResult!,
252
266
  );
267
+ this.targetConnection.close();
253
268
  return schemaInfo;
254
269
  } else {
255
270
  if (runQueryConfig?.limitThousand) {
@@ -264,7 +279,7 @@ export class Quill {
264
279
  const queryResults = await Promise.all(
265
280
  queries.map(async (query) => {
266
281
  return await this.targetConnection.query(query);
267
- })
282
+ }),
268
283
  );
269
284
  results = { ...results, queryResults };
270
285
  if (runQueryConfig?.fieldsToRemove) {
@@ -298,12 +313,12 @@ export class Quill {
298
313
 
299
314
  private async postQuill(
300
315
  path: string,
301
- payload: any
316
+ payload: any,
302
317
  ): Promise<QuillClientResponse> {
303
318
  const response = await axios.post(
304
319
  `${this.baseUrl}/sdk/${path}`,
305
320
  payload,
306
- this.config
321
+ this.config,
307
322
  );
308
323
  return response.data;
309
324
  }
@@ -4,7 +4,7 @@ export interface Mapable {
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
+ }
@@ -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 baseProps = Object.getOwnPropertyNames(baseClass.prototype);
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 (!obj.hasOwnProperty(prop)) {
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++) {
@@ -10,4 +10,4 @@ export function depluralize(text: string): string {
10
10
  return text.slice(0, -1);
11
11
  }
12
12
  return text;
13
- }
13
+ }