@quillsql/node 0.3.7 → 0.3.8
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 +189 -0
- package/dist/db/{CachedPools.js → CachedConnection.js} +11 -23
- package/dist/db/DatabaseHelper.js +187 -0
- package/dist/db/Mysql.js +187 -0
- package/dist/db/Postgres.js +156 -0
- package/dist/db/Snowflake.js +179 -0
- package/dist/index.js +47 -18
- package/dist/index.uspec.js +3 -2
- package/dist/models/Client.js +2 -0
- package/dist/utils/RunQueryProcesses.js +4 -4
- package/dist/utils/textProcessing.js +17 -0
- package/examples/node-server/app.ts +6 -8
- package/package.json +5 -1
- package/src/assets/pgtypes.ts +2782 -0
- package/src/db/BigQuery.ts +201 -0
- package/src/db/{CachedPools.ts → CachedConnection.ts} +25 -21
- package/src/db/DatabaseHelper.ts +340 -0
- package/src/db/Mysql.ts +209 -0
- package/src/db/Postgres.ts +178 -0
- package/src/db/Snowflake.ts +191 -0
- package/src/index.ts +69 -18
- package/src/index.uspec.ts +9 -2
- package/src/models/Client.ts +29 -0
- package/src/models/Quill.ts +0 -6
- package/src/utils/RunQueryProcesses.ts +5 -5
- package/src/utils/textProcessing.ts +13 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.formatPostgresConfig = exports.getSchemaColumnInfoPostgress = exports.getForeignKeysPostgres = exports.getColumnsByTablePostgres = exports.getTablesBySchemaPostgres = exports.getSchemasPostgres = exports.runQueryPostgres = exports.disconnectFromPostgres = exports.connectToPostgres = void 0;
|
|
13
|
+
const pg_1 = require("pg");
|
|
14
|
+
const textProcessing_1 = require("../utils/textProcessing");
|
|
15
|
+
const pgtypes_1 = require("../assets/pgtypes");
|
|
16
|
+
function connectToPostgres(config) {
|
|
17
|
+
return new pg_1.Pool(config);
|
|
18
|
+
}
|
|
19
|
+
exports.connectToPostgres = connectToPostgres;
|
|
20
|
+
function disconnectFromPostgres(pool) {
|
|
21
|
+
pool.end();
|
|
22
|
+
}
|
|
23
|
+
exports.disconnectFromPostgres = disconnectFromPostgres;
|
|
24
|
+
function runQueryPostgres(sql, pool) {
|
|
25
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
const results = yield pool.query(sql);
|
|
27
|
+
return {
|
|
28
|
+
fields: results.fields.map((field) => ({
|
|
29
|
+
name: field.name,
|
|
30
|
+
dataTypeID: field.dataTypeID,
|
|
31
|
+
})),
|
|
32
|
+
rows: results.rows,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
exports.runQueryPostgres = runQueryPostgres;
|
|
37
|
+
function getSchemasPostgres(pool) {
|
|
38
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
const sql = `SELECT schema_name FROM information_schema.schemata
|
|
40
|
+
WHERE schema_name NOT LIKE 'pg_%' AND schema_name != 'information_schema';`;
|
|
41
|
+
const results = yield runQueryPostgres(sql, pool);
|
|
42
|
+
return results.rows.map((row) => row.schema_name);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
exports.getSchemasPostgres = getSchemasPostgres;
|
|
46
|
+
function getTablesBySchemaPostgres(pool, schemaName) {
|
|
47
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
const sql = `SELECT table_name FROM information_schema.tables WHERE table_schema = '${schemaName}'`;
|
|
49
|
+
const results = yield runQueryPostgres(sql, pool);
|
|
50
|
+
return results.rows.map((row) => row.table_name);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
exports.getTablesBySchemaPostgres = getTablesBySchemaPostgres;
|
|
54
|
+
function getColumnsByTablePostgres(pool, schemaName, tableName) {
|
|
55
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
+
const sql = `SELECT column_name FROM information_schema.columns WHERE table_schema = '${schemaName}' and table_name = '${tableName}'`;
|
|
57
|
+
const results = yield runQueryPostgres(sql, pool);
|
|
58
|
+
return results.rows.map((row) => row.column_name);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
exports.getColumnsByTablePostgres = getColumnsByTablePostgres;
|
|
62
|
+
function getForeignKeysPostgres(pool, schemaName, tableName, primaryKey) {
|
|
63
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
+
const depluralizedTableName = (0, textProcessing_1.depluralize)(tableName);
|
|
65
|
+
let sql = `SELECT column_name FROM information_schema.columns
|
|
66
|
+
WHERE table_schema = '${schemaName}'
|
|
67
|
+
and table_name != '${tableName}'
|
|
68
|
+
and (column_name = '${primaryKey}'
|
|
69
|
+
or column_name = '${depluralizedTableName}_${primaryKey}'
|
|
70
|
+
or column_name = '${depluralizedTableName}${(0, textProcessing_1.capitalize)(primaryKey)}')`;
|
|
71
|
+
const results = yield runQueryPostgres(sql, pool);
|
|
72
|
+
let foreignKeysString = results.rows.map((key) => {
|
|
73
|
+
return key.column_name;
|
|
74
|
+
});
|
|
75
|
+
foreignKeysString = foreignKeysString.filter((key) => key !== "id" && key !== "_id_");
|
|
76
|
+
foreignKeysString = [...new Set(foreignKeysString)];
|
|
77
|
+
if (foreignKeysString.length === 0) {
|
|
78
|
+
sql = `SELECT column_name FROM information_schema.columns
|
|
79
|
+
WHERE table_schema = '${schemaName}'
|
|
80
|
+
and table_name != '${tableName}'
|
|
81
|
+
and (column_name like '${tableName}%'
|
|
82
|
+
or column_name like '%\\_id'
|
|
83
|
+
or column_name like '%Id'
|
|
84
|
+
or column_name like '%\\_${primaryKey}'
|
|
85
|
+
or column_name like '%${(0, textProcessing_1.capitalize)(primaryKey)}')`;
|
|
86
|
+
const results = yield runQueryPostgres(sql, pool);
|
|
87
|
+
foreignKeysString = results.rows.map((key) => {
|
|
88
|
+
return key.column_name;
|
|
89
|
+
});
|
|
90
|
+
foreignKeysString = [...new Set(foreignKeysString)];
|
|
91
|
+
}
|
|
92
|
+
return foreignKeysString;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
exports.getForeignKeysPostgres = getForeignKeysPostgres;
|
|
96
|
+
function getSchemaColumnInfoPostgress(pool, schemaName, tableNames) {
|
|
97
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
const allColumns = yield Promise.all(tableNames.map((tableName) => __awaiter(this, void 0, void 0, function* () {
|
|
99
|
+
const query = `
|
|
100
|
+
SELECT column_name as "columnName", udt_name as "fieldType"
|
|
101
|
+
FROM information_schema.columns
|
|
102
|
+
WHERE table_schema = '${schemaName}'
|
|
103
|
+
AND table_name = '${tableName}'
|
|
104
|
+
ORDER BY ordinal_position;
|
|
105
|
+
`;
|
|
106
|
+
const results = yield runQueryPostgres(query, pool);
|
|
107
|
+
return {
|
|
108
|
+
tableName,
|
|
109
|
+
displayName: tableName,
|
|
110
|
+
columns: results.rows.map((row) => {
|
|
111
|
+
var _a;
|
|
112
|
+
let pgType = (_a = pgtypes_1.PG_TYPES.find((pgType) => {
|
|
113
|
+
return pgType.typname === row.fieldType;
|
|
114
|
+
})) === null || _a === void 0 ? void 0 : _a.oid;
|
|
115
|
+
if (!pgType) {
|
|
116
|
+
pgType = 1043;
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
columnName: row.columnName,
|
|
120
|
+
displayName: row.columnName,
|
|
121
|
+
dataTypeId: pgType,
|
|
122
|
+
fieldType: row.fieldType,
|
|
123
|
+
};
|
|
124
|
+
}),
|
|
125
|
+
};
|
|
126
|
+
})));
|
|
127
|
+
return allColumns;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
exports.getSchemaColumnInfoPostgress = getSchemaColumnInfoPostgress;
|
|
131
|
+
function formatPostgresConfig(connectionString) {
|
|
132
|
+
return { connectionString, ssl: { rejectUnauthorized: false } };
|
|
133
|
+
}
|
|
134
|
+
exports.formatPostgresConfig = formatPostgresConfig;
|
|
135
|
+
// CURRENTLY UNUSED BUT MAYBE USEFUL IN THE FUTURE
|
|
136
|
+
function getSslConfig(client) {
|
|
137
|
+
if (!client.useSsl) {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
if (client.serverCa && client.clientKey && client.clientCert) {
|
|
141
|
+
return {
|
|
142
|
+
rejectUnauthorized: false,
|
|
143
|
+
ca: client.serverCa,
|
|
144
|
+
key: client.clientKey,
|
|
145
|
+
cert: client.clientCert,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (client.serverCa) {
|
|
149
|
+
return {
|
|
150
|
+
rejectUnauthorized: false,
|
|
151
|
+
ca: client.serverCa,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// if using ssl with no certificates
|
|
155
|
+
return { rejectUnauthorized: false };
|
|
156
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.getSchemaColumnInfoSnowflake = exports.getForeignKeysSnowflake = exports.disconnectFromSnowflake = exports.connectToSnowflake = exports.formatSnowflakeConfig = exports.getColumnsByTableSnowflake = exports.getTablesBySchemaSnowflake = exports.getSchemasSnowflake = exports.runQuerySnowflake = void 0;
|
|
16
|
+
const snowflake_sdk_1 = __importDefault(require("snowflake-sdk"));
|
|
17
|
+
const textProcessing_1 = require("../utils/textProcessing");
|
|
18
|
+
const POSTGRES_SNOWFLAKE_MAP = {
|
|
19
|
+
BOOLEAN: 16,
|
|
20
|
+
FIXED: 1700, // DECIMAL or NUMERIC
|
|
21
|
+
REAL: 700, // FLOAT4
|
|
22
|
+
DOUBLE: 701, // FLOAT8
|
|
23
|
+
TEXT: 25, // TEXT in PostgreSQL
|
|
24
|
+
DATE: 1082,
|
|
25
|
+
DATETIME: 1184, // TIMESTAMP in PostgreSQL
|
|
26
|
+
TIME: 1083,
|
|
27
|
+
TIMESTAMP_LTZ: 1184,
|
|
28
|
+
TIMESTAMP_NTZ: 1184,
|
|
29
|
+
TIMESTAMP_TZ: 1184,
|
|
30
|
+
VARIANT: 114, // JSONB in PostgreSQL
|
|
31
|
+
OBJECT: 114, // JSONB, as an equivalent for structured JSON
|
|
32
|
+
ARRAY: 1009, // TEXT[], assuming most common case
|
|
33
|
+
BINARY: 17, // BYTEA
|
|
34
|
+
};
|
|
35
|
+
function runQuerySnowflake(sql, connection) {
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
const results = yield new Promise((resolve, reject) => {
|
|
38
|
+
connection.execute({
|
|
39
|
+
sqlText: sql,
|
|
40
|
+
complete: (err, stmt, rows) => {
|
|
41
|
+
if (err) {
|
|
42
|
+
reject(err);
|
|
43
|
+
return { success: false, message: err.message };
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
resolve({
|
|
47
|
+
rows,
|
|
48
|
+
fields: stmt.getColumns().map((col) => ({
|
|
49
|
+
name: col.getName(),
|
|
50
|
+
dataTypeID: POSTGRES_SNOWFLAKE_MAP[col.getType().toUpperCase()],
|
|
51
|
+
})),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
return results;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
exports.runQuerySnowflake = runQuerySnowflake;
|
|
61
|
+
function getSchemasSnowflake(connection) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
const sql = `SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
|
|
64
|
+
WHERE SCHEMA_NAME != 'INFORMATION_SCHEMA'`;
|
|
65
|
+
const results = yield runQuerySnowflake(sql, connection);
|
|
66
|
+
return results.rows.map((row) => row.SCHEMA_NAME);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
exports.getSchemasSnowflake = getSchemasSnowflake;
|
|
70
|
+
function getTablesBySchemaSnowflake(connection, schema) {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
const sql = `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${schema}'`;
|
|
73
|
+
const results = yield runQuerySnowflake(sql, connection);
|
|
74
|
+
return results.rows.map((row) => row.TABLE_NAME);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
exports.getTablesBySchemaSnowflake = getTablesBySchemaSnowflake;
|
|
78
|
+
function getColumnsByTableSnowflake(connection, schemaName, tableName) {
|
|
79
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
80
|
+
const sql = `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '${schemaName}' AND TABLE_NAME = '${tableName}'`;
|
|
81
|
+
const results = yield runQuerySnowflake(sql, connection);
|
|
82
|
+
return results.rows.map((row) => row.COLUMN_NAME);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
exports.getColumnsByTableSnowflake = getColumnsByTableSnowflake;
|
|
86
|
+
function formatSnowflakeConfig(connectionString) {
|
|
87
|
+
const parsed = new URL(connectionString);
|
|
88
|
+
return {
|
|
89
|
+
account: parsed.hostname,
|
|
90
|
+
username: parsed.username,
|
|
91
|
+
password: parsed.password,
|
|
92
|
+
database: parsed.pathname.split("/")[1],
|
|
93
|
+
warehouse: parsed.pathname.split("/")[2],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
exports.formatSnowflakeConfig = formatSnowflakeConfig;
|
|
97
|
+
function connectToSnowflake(config) {
|
|
98
|
+
const connection = snowflake_sdk_1.default.createConnection(config);
|
|
99
|
+
connection.connect((err) => {
|
|
100
|
+
if (err) {
|
|
101
|
+
console.error(`Failed to connect to Snowflake: ${err.message}`);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return connection;
|
|
105
|
+
}
|
|
106
|
+
exports.connectToSnowflake = connectToSnowflake;
|
|
107
|
+
function disconnectFromSnowflake(connection) {
|
|
108
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
109
|
+
connection.destroy((err, conn) => {
|
|
110
|
+
if (err) {
|
|
111
|
+
console.error(`Failed to disconnect from Snowflake: ${err.message}`);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
exports.disconnectFromSnowflake = disconnectFromSnowflake;
|
|
117
|
+
function getForeignKeysSnowflake(connection, schemaName, tableName, primaryKey) {
|
|
118
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
119
|
+
let depluralizedTableName = (0, textProcessing_1.depluralize)(tableName);
|
|
120
|
+
let sql = `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
|
|
121
|
+
WHERE TABLE_SCHEMA = '${schemaName}'
|
|
122
|
+
AND TABLE_NAME = '${schemaName}'
|
|
123
|
+
and TABLE_NAME != '${tableName}'
|
|
124
|
+
and (COLUMN_NAME = '${primaryKey}'
|
|
125
|
+
or COLUMN_NAME = '${depluralizedTableName}_${primaryKey}'
|
|
126
|
+
or COLUMN_NAME = '${depluralizedTableName}${(0, textProcessing_1.capitalize)(primaryKey)}')`;
|
|
127
|
+
const results = yield runQuerySnowflake(sql, connection);
|
|
128
|
+
let foreignKeysString = results.rows.map((key) => {
|
|
129
|
+
return key.COLUMN_NAME;
|
|
130
|
+
});
|
|
131
|
+
foreignKeysString = foreignKeysString.filter((key) => key !== "id" && key !== "_id_");
|
|
132
|
+
foreignKeysString = [...new Set(foreignKeysString)];
|
|
133
|
+
if (foreignKeysString.length === 0) {
|
|
134
|
+
sql = `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
|
|
135
|
+
WHERE TABLE_SCHEMA = '${schemaName}'
|
|
136
|
+
AND TABLE_NAME = '${schemaName}'
|
|
137
|
+
and TABLE_NAME != '${tableName}'
|
|
138
|
+
and (COLUMN_NAME like '${depluralizedTableName}%'
|
|
139
|
+
or column_name like '%\\_id'
|
|
140
|
+
or column_name like '%Id'
|
|
141
|
+
or COLUMN_NAME like '%\\_${primaryKey}'
|
|
142
|
+
or COLUMN_NAME like '%${(0, textProcessing_1.capitalize)(primaryKey)}')`;
|
|
143
|
+
const results = yield runQuerySnowflake(sql, connection);
|
|
144
|
+
foreignKeysString = results.rows.map((key) => {
|
|
145
|
+
return key.COLUMN_NAME;
|
|
146
|
+
});
|
|
147
|
+
foreignKeysString = [...new Set(foreignKeysString)];
|
|
148
|
+
}
|
|
149
|
+
return foreignKeysString;
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
exports.getForeignKeysSnowflake = getForeignKeysSnowflake;
|
|
153
|
+
function getSchemaColumnInfoSnowflake(connection, schemaName, tableNames) {
|
|
154
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
155
|
+
const allColumns = yield Promise.all(tableNames.map((tableName) => __awaiter(this, void 0, void 0, function* () {
|
|
156
|
+
const query = `SELECT
|
|
157
|
+
COLUMN_NAME as "columnName", DATA_TYPE as "dataType"
|
|
158
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
159
|
+
WHERE TABLE_SCHEMA = '${schemaName}' AND TABLE_NAME = '${tableName}';
|
|
160
|
+
`;
|
|
161
|
+
const results = yield runQuerySnowflake(query, connection);
|
|
162
|
+
return {
|
|
163
|
+
tableName,
|
|
164
|
+
displayName: tableName,
|
|
165
|
+
columns: results.rows.map((row) => {
|
|
166
|
+
const postgresType = POSTGRES_SNOWFLAKE_MAP[row.dataType];
|
|
167
|
+
return {
|
|
168
|
+
columnName: row.columnName,
|
|
169
|
+
displayName: row.columnName,
|
|
170
|
+
dataTypeId: postgresType,
|
|
171
|
+
fieldType: row.dataType,
|
|
172
|
+
};
|
|
173
|
+
}),
|
|
174
|
+
};
|
|
175
|
+
})));
|
|
176
|
+
return allColumns;
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
exports.getSchemaColumnInfoSnowflake = getSchemaColumnInfoSnowflake;
|
package/dist/index.js
CHANGED
|
@@ -12,10 +12,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
const
|
|
15
|
+
const CachedConnection_1 = require("./db/CachedConnection");
|
|
16
16
|
const axios_1 = __importDefault(require("axios"));
|
|
17
17
|
require("dotenv/config");
|
|
18
18
|
const RunQueryProcesses_1 = require("./utils/RunQueryProcesses");
|
|
19
|
+
const pgtypes_1 = require("./assets/pgtypes");
|
|
20
|
+
const DatabaseHelper_1 = require("./db/DatabaseHelper");
|
|
19
21
|
const HOST = process.env.ENV === "development"
|
|
20
22
|
? "http://localhost:8080"
|
|
21
23
|
: "https://quill-344421.uc.r.appspot.com";
|
|
@@ -23,23 +25,39 @@ const HOST = process.env.ENV === "development"
|
|
|
23
25
|
* Quill - Fullstack API Platform for Dashboards and Reporting.
|
|
24
26
|
*/
|
|
25
27
|
class QuillClass {
|
|
26
|
-
constructor(privateKey, databaseConnectionString, cache = {}) {
|
|
27
|
-
this.
|
|
28
|
-
this.baseUrl = HOST;
|
|
28
|
+
constructor(privateKey, databaseConnectionString, cache = {}, databaseType, metadataServerURL) {
|
|
29
|
+
this.baseUrl = metadataServerURL ? metadataServerURL : HOST;
|
|
29
30
|
this.config = { headers: { Authorization: `Bearer ${privateKey}` } };
|
|
30
|
-
this.
|
|
31
|
-
this.ssl = { rejectUnauthorized: false };
|
|
32
|
-
this.targetPool = new CachedPools_1.CachedPool({ connectionString: this.connectionString, ssl: this.ssl }, cache);
|
|
31
|
+
this.targetConnection = new CachedConnection_1.CachedConnection(databaseType, (0, DatabaseHelper_1.getDatabaseCredentials)(databaseType, databaseConnectionString), cache);
|
|
33
32
|
}
|
|
34
33
|
query({ orgId, metadata }) {
|
|
35
|
-
var _a, _b;
|
|
34
|
+
var _a, _b, _c;
|
|
36
35
|
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
-
this.
|
|
36
|
+
this.targetConnection.orgId = orgId;
|
|
38
37
|
try {
|
|
39
38
|
// Initial Query Request
|
|
40
|
-
const
|
|
39
|
+
const limitedQueries = metadata.preQueries
|
|
40
|
+
? (_a = metadata.preQueries) === null || _a === void 0 ? void 0 : _a.map((query) => query + " limit 1")
|
|
41
|
+
: [];
|
|
42
|
+
const preQueryResults = metadata.preQueries
|
|
43
|
+
? yield this.runQueries(limitedQueries)
|
|
44
|
+
: [];
|
|
45
|
+
const columns = metadata.preQueries
|
|
46
|
+
? preQueryResults.queryResults[0].fields.map((field) => {
|
|
47
|
+
var _a;
|
|
48
|
+
return {
|
|
49
|
+
fieldType: pgtypes_1.PG_TYPES.find((type) => field.dataTypeID === type.oid)
|
|
50
|
+
? (_a = pgtypes_1.PG_TYPES.find((type) => field.dataTypeID === type.oid)) === null || _a === void 0 ? void 0 : _a.typname
|
|
51
|
+
: field.dataTypeID,
|
|
52
|
+
name: field.name,
|
|
53
|
+
displayName: field.name,
|
|
54
|
+
isVisible: true,
|
|
55
|
+
field: field.name,
|
|
56
|
+
};
|
|
57
|
+
})
|
|
58
|
+
: metadata.columns;
|
|
41
59
|
const response = yield this.postQuill(metadata.task, Object.assign(Object.assign({}, metadata), { orgId,
|
|
42
|
-
|
|
60
|
+
columns, viewQuery: metadata.preQueries ? metadata.preQueries[0] : undefined }));
|
|
43
61
|
// if there is no metadata object in the response, create one
|
|
44
62
|
if (!response.metadata) {
|
|
45
63
|
response.metadata = {};
|
|
@@ -47,7 +65,7 @@ class QuillClass {
|
|
|
47
65
|
const results = yield this.runQueries(response.queries, response.metadata.runQueryConfig);
|
|
48
66
|
// QUICK JANKY FIX TO UPDATE METADATA AFTER GETTING MAPPED ARRAYS
|
|
49
67
|
if (results.mappedArray &&
|
|
50
|
-
((
|
|
68
|
+
((_c = (_b = response.metadata) === null || _b === void 0 ? void 0 : _b.runQueryConfig) === null || _c === void 0 ? void 0 : _c.arrayToMap)) {
|
|
51
69
|
const arrayToMap = response.metadata.runQueryConfig.arrayToMap;
|
|
52
70
|
results.mappedArray.forEach((array, index) => {
|
|
53
71
|
response.metadata[arrayToMap.arrayName][index][arrayToMap.field] =
|
|
@@ -79,19 +97,21 @@ class QuillClass {
|
|
|
79
97
|
runQueries(queries, runQueryConfig) {
|
|
80
98
|
return __awaiter(this, void 0, void 0, function* () {
|
|
81
99
|
let results;
|
|
100
|
+
if (!queries)
|
|
101
|
+
return Object.assign(Object.assign({}, results), { queryResults: [] });
|
|
82
102
|
if (!queries)
|
|
83
103
|
return Object.assign(Object.assign({}, results), { queryResults: [] });
|
|
84
104
|
if (runQueryConfig === null || runQueryConfig === void 0 ? void 0 : runQueryConfig.arrayToMap) {
|
|
85
|
-
const mappedArray = yield (0, RunQueryProcesses_1.mapQueries)(queries, runQueryConfig.arrayToMap, this.
|
|
105
|
+
const mappedArray = yield (0, RunQueryProcesses_1.mapQueries)(queries, runQueryConfig.arrayToMap, this.targetConnection);
|
|
86
106
|
return Object.assign(Object.assign({}, results), { queryResults: [], mappedArray });
|
|
87
107
|
}
|
|
88
108
|
else {
|
|
89
109
|
const queryResults = yield Promise.all(queries.map((query) => __awaiter(this, void 0, void 0, function* () {
|
|
90
|
-
return yield this.
|
|
110
|
+
return yield this.targetConnection.query(query);
|
|
91
111
|
})));
|
|
92
112
|
results = Object.assign(Object.assign({}, results), { queryResults });
|
|
93
113
|
if (runQueryConfig === null || runQueryConfig === void 0 ? void 0 : runQueryConfig.getSchema) {
|
|
94
|
-
results = Object.assign(Object.assign({}, results), { columns: yield (0, RunQueryProcesses_1.getTableSchema)(queryResults[0], this.
|
|
114
|
+
results = Object.assign(Object.assign({}, results), { columns: yield (0, RunQueryProcesses_1.getTableSchema)(queryResults[0], this.targetConnection) });
|
|
95
115
|
}
|
|
96
116
|
if (runQueryConfig === null || runQueryConfig === void 0 ? void 0 : runQueryConfig.removeFields) {
|
|
97
117
|
results = Object.assign(Object.assign({}, results), { queryResults: (0, RunQueryProcesses_1.removeFields)(queryResults, runQueryConfig.removeFields) });
|
|
@@ -108,14 +128,23 @@ class QuillClass {
|
|
|
108
128
|
}
|
|
109
129
|
close() {
|
|
110
130
|
return __awaiter(this, void 0, void 0, function* () {
|
|
111
|
-
yield this.
|
|
131
|
+
yield this.targetConnection.close();
|
|
112
132
|
});
|
|
113
133
|
}
|
|
114
134
|
}
|
|
115
135
|
exports.default = QuillClass;
|
|
116
|
-
const Quill = ({ privateKey, databaseConnectionString, cache, }) => {
|
|
117
|
-
return new QuillClass(privateKey, databaseConnectionString, cache);
|
|
136
|
+
const Quill = ({ privateKey, databaseConnectionString, cache, databaseType, metadataServerURL, }) => {
|
|
137
|
+
return new QuillClass(privateKey, databaseConnectionString, cache, databaseType, metadataServerURL);
|
|
118
138
|
};
|
|
119
139
|
module.exports = Quill;
|
|
120
140
|
module.exports.Quill = Quill;
|
|
121
141
|
module.exports.default = Quill;
|
|
142
|
+
module.exports.getTablesBySchemaByDatabase = DatabaseHelper_1.getTablesBySchemaByDatabase;
|
|
143
|
+
module.exports.getDatabaseCredentials = DatabaseHelper_1.getDatabaseCredentials;
|
|
144
|
+
module.exports.getColumnsByTableByDatabase = DatabaseHelper_1.getColumnsByTableByDatabase;
|
|
145
|
+
module.exports.getForiegnKeysByDatabase = DatabaseHelper_1.getForiegnKeysByDatabase;
|
|
146
|
+
module.exports.getSchemasByDatabase = DatabaseHelper_1.getSchemasByDatabase;
|
|
147
|
+
module.exports.getColumnInfoBySchemaByDatabase =
|
|
148
|
+
DatabaseHelper_1.getColumnInfoBySchemaByDatabase;
|
|
149
|
+
module.exports.connectToDatabase = DatabaseHelper_1.connectToDatabase;
|
|
150
|
+
module.exports.runQueryByDatabase = DatabaseHelper_1.runQueryByDatabase;
|
package/dist/index.uspec.js
CHANGED
|
@@ -4,12 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const _1 = __importDefault(require("."));
|
|
7
|
+
const DatabaseHelper_1 = require("./db/DatabaseHelper");
|
|
7
8
|
jest.mock(".");
|
|
8
9
|
describe("Quill", () => {
|
|
9
10
|
let quill;
|
|
10
11
|
beforeEach(() => {
|
|
11
|
-
quill = new _1.default("dummy_private_key", "dummy_db_url");
|
|
12
|
-
quill.
|
|
12
|
+
quill = new _1.default("dummy_private_key", "dummy_db_url", {}, DatabaseHelper_1.DatabaseType.postgres, undefined);
|
|
13
|
+
quill.targetConnection.query = jest.fn().mockResolvedValue([]);
|
|
13
14
|
});
|
|
14
15
|
describe("query", () => {
|
|
15
16
|
it("return nothing when suppling no queries", () => {
|
|
@@ -10,9 +10,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.mapQueries = exports.removeFields = exports.getTableSchema = void 0;
|
|
13
|
-
function getTableSchema(queryResults,
|
|
13
|
+
function getTableSchema(queryResults, targetConnection) {
|
|
14
14
|
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
-
const typesQuery = yield
|
|
15
|
+
const typesQuery = yield targetConnection.query("select typname, oid, typarray from pg_type order by oid;");
|
|
16
16
|
const schema = queryResults[0].fields.map((field) => {
|
|
17
17
|
return {
|
|
18
18
|
fieldType: typesQuery.rows.filter((type) => field.dataTypeID === type.oid)[0].typname,
|
|
@@ -35,11 +35,11 @@ function removeFields(queryResults, fieldsToRemove) {
|
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
exports.removeFields = removeFields;
|
|
38
|
-
function mapQueries(queries, arrayToMap,
|
|
38
|
+
function mapQueries(queries, arrayToMap, targetConnection) {
|
|
39
39
|
return __awaiter(this, void 0, void 0, function* () {
|
|
40
40
|
const mappedArray = [];
|
|
41
41
|
for (let i = 0; i < queries.length; i++) {
|
|
42
|
-
const queryResult = yield
|
|
42
|
+
const queryResult = yield targetConnection.query(queries[i]);
|
|
43
43
|
mappedArray.push(queryResult.rows);
|
|
44
44
|
}
|
|
45
45
|
return mappedArray;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.depluralize = exports.capitalize = void 0;
|
|
4
|
+
function capitalize(text) {
|
|
5
|
+
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
6
|
+
}
|
|
7
|
+
exports.capitalize = capitalize;
|
|
8
|
+
function depluralize(text) {
|
|
9
|
+
if (text.endsWith("ies")) {
|
|
10
|
+
return text.slice(0, -3) + "y";
|
|
11
|
+
}
|
|
12
|
+
if (text.endsWith("s")) {
|
|
13
|
+
return text.slice(0, -1);
|
|
14
|
+
}
|
|
15
|
+
return text;
|
|
16
|
+
}
|
|
17
|
+
exports.depluralize = depluralize;
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
// Write a simple node server to test the SDK
|
|
2
2
|
|
|
3
3
|
import express from "express";
|
|
4
|
-
import Quill from "../../src/index";
|
|
5
4
|
import cors from "cors";
|
|
6
5
|
|
|
7
6
|
const app = express();
|
|
8
|
-
const port =
|
|
7
|
+
const port = 3001;
|
|
9
8
|
|
|
10
|
-
const quill =
|
|
11
|
-
process.env.QUILL_PRIVATE_KEY
|
|
12
|
-
process.env.DB_URL
|
|
13
|
-
|
|
14
|
-
);
|
|
9
|
+
const quill = require("../../src/index")({
|
|
10
|
+
privateKey: process.env.QUILL_PRIVATE_KEY,
|
|
11
|
+
databaseConnectionString: process.env.DB_URL,
|
|
12
|
+
});
|
|
15
13
|
|
|
16
14
|
app.use(cors());
|
|
17
15
|
app.use(express.json());
|
|
@@ -24,7 +22,7 @@ app.post("/quill", async (req, res) => {
|
|
|
24
22
|
const organizationId = req.body.orgId;
|
|
25
23
|
const { metadata } = req.body;
|
|
26
24
|
const result = await quill.query({
|
|
27
|
-
orgId:
|
|
25
|
+
orgId: metadata.orgId,
|
|
28
26
|
metadata,
|
|
29
27
|
});
|
|
30
28
|
res.send(result);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quillsql/node",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "Quill's client SDK for node backends.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"@types/jest": "^29.5.11",
|
|
19
19
|
"@types/node": "^20.10.7",
|
|
20
20
|
"@types/pg": "^8.10.9",
|
|
21
|
+
"@types/snowflake-sdk": "^1.6.20",
|
|
21
22
|
"cors": "^2.8.5",
|
|
22
23
|
"express": "^4.18.2",
|
|
23
24
|
"jest": "^29.7.0",
|
|
@@ -26,10 +27,13 @@
|
|
|
26
27
|
"typescript": "^5.3.3"
|
|
27
28
|
},
|
|
28
29
|
"dependencies": {
|
|
30
|
+
"@google-cloud/bigquery": "^7.4.0",
|
|
29
31
|
"axios": "^1.6.5",
|
|
30
32
|
"dotenv": "^16.3.1",
|
|
33
|
+
"mysql2": "^3.9.1",
|
|
31
34
|
"pg": "^8.11.3",
|
|
32
35
|
"redis": "^4.6.12",
|
|
36
|
+
"snowflake-sdk": "^1.9.3",
|
|
33
37
|
"ts-jest": "^29.1.1"
|
|
34
38
|
}
|
|
35
39
|
}
|