@restura/core 0.1.0-alpha.10 → 0.1.0-alpha.12
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/index.d.mts +60 -42
- package/dist/index.d.ts +60 -42
- package/dist/index.js +289 -88
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +287 -86
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/dist/index.mjs
CHANGED
|
@@ -494,7 +494,7 @@ var ApiTree = class _ApiTree {
|
|
|
494
494
|
break;
|
|
495
495
|
}
|
|
496
496
|
}
|
|
497
|
-
return `'${p.name}'${p.required ? "" : "?"}:${requestType}`;
|
|
497
|
+
return `'${p.name}'${p.required ? "" : "?"}:${requestType}${p.isNullable ? " | null" : ""}`;
|
|
498
498
|
}).join(";\n")}${ObjectUtils.isArrayWithData(route.request) ? ";" : ""}
|
|
499
499
|
`;
|
|
500
500
|
modelString += `}`;
|
|
@@ -518,18 +518,18 @@ var ApiTree = class _ApiTree {
|
|
|
518
518
|
return nested;
|
|
519
519
|
}
|
|
520
520
|
getNameAndType(p) {
|
|
521
|
-
let responseType = "any",
|
|
521
|
+
let responseType = "any", isNullable = false, array = false;
|
|
522
522
|
if (p.selector) {
|
|
523
|
-
({ responseType,
|
|
523
|
+
({ responseType, isNullable } = this.getTypeFromTable(p.selector, p.name));
|
|
524
524
|
} else if (p.subquery) {
|
|
525
525
|
responseType = this.getFields(p.subquery.properties);
|
|
526
526
|
array = true;
|
|
527
527
|
}
|
|
528
|
-
return `${p.name}${
|
|
528
|
+
return `${p.name}:${responseType}${array ? "[]" : ""}${isNullable ? " | null" : ""}`;
|
|
529
529
|
}
|
|
530
530
|
getTypeFromTable(selector, name) {
|
|
531
531
|
const path4 = selector.split(".");
|
|
532
|
-
if (path4.length === 0 || path4.length > 2 || path4[0] === "") return { responseType: "any",
|
|
532
|
+
if (path4.length === 0 || path4.length > 2 || path4[0] === "") return { responseType: "any", isNullable: false };
|
|
533
533
|
let tableName = path4.length == 2 ? path4[0] : name;
|
|
534
534
|
const columnName = path4.length == 2 ? path4[1] : path4[0];
|
|
535
535
|
let table = this.database.find((t) => t.name == tableName);
|
|
@@ -539,10 +539,10 @@ var ApiTree = class _ApiTree {
|
|
|
539
539
|
table = this.database.find((t) => t.name == tableName);
|
|
540
540
|
}
|
|
541
541
|
const column = table == null ? void 0 : table.columns.find((c) => c.name == columnName);
|
|
542
|
-
if (!table || !column) return { responseType: "any",
|
|
542
|
+
if (!table || !column) return { responseType: "any", isNullable: false };
|
|
543
543
|
return {
|
|
544
544
|
responseType: SqlUtils.convertDatabaseTypeToTypescript(column.type, column.value),
|
|
545
|
-
|
|
545
|
+
isNullable: column.roles.length > 0 || column.isNullable
|
|
546
546
|
};
|
|
547
547
|
}
|
|
548
548
|
};
|
|
@@ -748,6 +748,7 @@ var joinDataSchema = z3.object({
|
|
|
748
748
|
var requestDataSchema = z3.object({
|
|
749
749
|
name: z3.string(),
|
|
750
750
|
required: z3.boolean(),
|
|
751
|
+
isNullable: z3.boolean().optional().default(false),
|
|
751
752
|
validator: z3.array(validatorDataSchema)
|
|
752
753
|
}).strict();
|
|
753
754
|
var responseDataSchema = z3.object({
|
|
@@ -1023,6 +1024,7 @@ function validateRequestParams(req, routeData, validationSchema) {
|
|
|
1023
1024
|
});
|
|
1024
1025
|
}
|
|
1025
1026
|
function validateRequestSingleParam(requestValue, requestParam) {
|
|
1027
|
+
if (requestParam.isNullable && requestValue === null) return;
|
|
1026
1028
|
requestParam.validator.forEach((validator) => {
|
|
1027
1029
|
switch (validator.type) {
|
|
1028
1030
|
case "TYPE_CHECK":
|
|
@@ -1202,6 +1204,10 @@ function convertTable(table) {
|
|
|
1202
1204
|
// src/restura/sql/PsqlEngine.ts
|
|
1203
1205
|
import { ObjectUtils as ObjectUtils4 } from "@redskytech/core-utils";
|
|
1204
1206
|
|
|
1207
|
+
// src/restura/sql/PsqlPool.ts
|
|
1208
|
+
import pg from "pg";
|
|
1209
|
+
import format3 from "pg-format";
|
|
1210
|
+
|
|
1205
1211
|
// src/restura/sql/PsqlUtils.ts
|
|
1206
1212
|
import format2 from "pg-format";
|
|
1207
1213
|
function escapeColumnName(columnName) {
|
|
@@ -1237,7 +1243,9 @@ function isValueNumber2(value) {
|
|
|
1237
1243
|
function SQL(strings, ...values) {
|
|
1238
1244
|
let query = strings[0];
|
|
1239
1245
|
values.forEach((value, index) => {
|
|
1240
|
-
if (
|
|
1246
|
+
if (typeof value === "boolean") {
|
|
1247
|
+
query += value;
|
|
1248
|
+
} else if (typeof value === "number") {
|
|
1241
1249
|
query += value;
|
|
1242
1250
|
} else {
|
|
1243
1251
|
query += format2.literal(value);
|
|
@@ -1247,6 +1255,76 @@ function SQL(strings, ...values) {
|
|
|
1247
1255
|
return query;
|
|
1248
1256
|
}
|
|
1249
1257
|
|
|
1258
|
+
// src/restura/sql/PsqlPool.ts
|
|
1259
|
+
var { Pool } = pg;
|
|
1260
|
+
var PsqlPool = class {
|
|
1261
|
+
constructor(poolConfig) {
|
|
1262
|
+
this.poolConfig = poolConfig;
|
|
1263
|
+
this.pool = new Pool(poolConfig);
|
|
1264
|
+
this.queryOne("SELECT NOW();", [], { isSystemUser: true, role: "", host: "localhost", ipAddress: "" }).then(() => {
|
|
1265
|
+
logger.info("Connected to PostgreSQL database");
|
|
1266
|
+
}).catch((error) => {
|
|
1267
|
+
logger.error("Error connecting to database", error);
|
|
1268
|
+
process.exit(1);
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1272
|
+
async queryOne(query, options, requesterDetails) {
|
|
1273
|
+
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1274
|
+
this.logSqlStatement(formattedQuery, options, requesterDetails);
|
|
1275
|
+
try {
|
|
1276
|
+
const response = await this.pool.query(formattedQuery, options);
|
|
1277
|
+
if (response.rows.length === 0) throw new RsError("NOT_FOUND", "No results found");
|
|
1278
|
+
else if (response.rows.length > 1) throw new RsError("DUPLICATE", "More than one result found");
|
|
1279
|
+
return response.rows[0];
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
console.error(error, query, options);
|
|
1282
|
+
if (RsError.isRsError(error)) throw error;
|
|
1283
|
+
if ((error == null ? void 0 : error.routine) === "_bt_check_unique") {
|
|
1284
|
+
throw new RsError("DUPLICATE", error.message);
|
|
1285
|
+
}
|
|
1286
|
+
throw new RsError("DATABASE_ERROR", `${error.message}`);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1290
|
+
async runQuery(query, options, requesterDetails) {
|
|
1291
|
+
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1292
|
+
this.logSqlStatement(formattedQuery, options, requesterDetails);
|
|
1293
|
+
const queryUpdated = query.replace(/[\t\n]/g, " ");
|
|
1294
|
+
console.log(queryUpdated, options);
|
|
1295
|
+
try {
|
|
1296
|
+
const response = await this.pool.query(formattedQuery, options);
|
|
1297
|
+
return response.rows;
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
console.error(error, query, options);
|
|
1300
|
+
if ((error == null ? void 0 : error.routine) === "_bt_check_unique") {
|
|
1301
|
+
throw new RsError("DUPLICATE", error.message);
|
|
1302
|
+
}
|
|
1303
|
+
throw new RsError("DATABASE_ERROR", `${error.message}`);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
logSqlStatement(query, options, requesterDetails, prefix = "") {
|
|
1307
|
+
if (logger.level !== "silly") return;
|
|
1308
|
+
let sqlStatement = "";
|
|
1309
|
+
if (options.length === 0) {
|
|
1310
|
+
sqlStatement = query;
|
|
1311
|
+
} else {
|
|
1312
|
+
let stringIndex = 0;
|
|
1313
|
+
sqlStatement = query.replace(/\$\d+/g, () => {
|
|
1314
|
+
const value = options[stringIndex++];
|
|
1315
|
+
if (typeof value === "number") return value.toString();
|
|
1316
|
+
return format3.literal(value);
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
let initiator = "Anonymous";
|
|
1320
|
+
if ("userId" in requesterDetails && requesterDetails.userId)
|
|
1321
|
+
initiator = `User Id (${requesterDetails.userId.toString()})`;
|
|
1322
|
+
if ("isSystemUser" in requesterDetails && requesterDetails.isSystemUser) initiator = "SYSTEM";
|
|
1323
|
+
logger.silly(`${prefix}query by ${initiator}, Query ->
|
|
1324
|
+
${sqlStatement}`);
|
|
1325
|
+
}
|
|
1326
|
+
};
|
|
1327
|
+
|
|
1250
1328
|
// src/restura/sql/SqlEngine.ts
|
|
1251
1329
|
import { ObjectUtils as ObjectUtils3 } from "@redskytech/core-utils";
|
|
1252
1330
|
var SqlEngine = class {
|
|
@@ -1351,6 +1429,57 @@ var SqlEngine = class {
|
|
|
1351
1429
|
// src/restura/sql/filterPsqlParser.ts
|
|
1352
1430
|
import peg from "pegjs";
|
|
1353
1431
|
var filterSqlGrammar = `
|
|
1432
|
+
{
|
|
1433
|
+
// ported from pg-format but intentionally will add double quotes to every column
|
|
1434
|
+
function quoteSqlIdentity(value) {
|
|
1435
|
+
if (value === undefined || value === null) {
|
|
1436
|
+
throw new Error('SQL identifier cannot be null or undefined');
|
|
1437
|
+
} else if (value === false) {
|
|
1438
|
+
return '"f"';
|
|
1439
|
+
} else if (value === true) {
|
|
1440
|
+
return '"t"';
|
|
1441
|
+
} else if (value instanceof Date) {
|
|
1442
|
+
// return '"' + formatDate(value.toISOString()) + '"';
|
|
1443
|
+
} else if (value instanceof Buffer) {
|
|
1444
|
+
throw new Error('SQL identifier cannot be a buffer');
|
|
1445
|
+
} else if (Array.isArray(value) === true) {
|
|
1446
|
+
var temp = [];
|
|
1447
|
+
for (var i = 0; i < value.length; i++) {
|
|
1448
|
+
if (Array.isArray(value[i]) === true) {
|
|
1449
|
+
throw new Error('Nested array to grouped list conversion is not supported for SQL identifier');
|
|
1450
|
+
} else {
|
|
1451
|
+
// temp.push(quoteIdent(value[i]));
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
return temp.toString();
|
|
1455
|
+
} else if (value === Object(value)) {
|
|
1456
|
+
throw new Error('SQL identifier cannot be an object');
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
var ident = value.toString().slice(0); // create copy
|
|
1460
|
+
|
|
1461
|
+
// do not quote a valid, unquoted identifier
|
|
1462
|
+
// if (/^[a-z_][a-z0-9_$]*$/.test(ident) === true && isReserved(ident) === false) {
|
|
1463
|
+
// return ident;
|
|
1464
|
+
// }
|
|
1465
|
+
|
|
1466
|
+
var quoted = '"';
|
|
1467
|
+
|
|
1468
|
+
for (var i = 0; i < ident.length; i++) {
|
|
1469
|
+
var c = ident[i];
|
|
1470
|
+
if (c === '"') {
|
|
1471
|
+
quoted += c + c;
|
|
1472
|
+
} else {
|
|
1473
|
+
quoted += c;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
quoted += '"';
|
|
1478
|
+
|
|
1479
|
+
return quoted;
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1354
1483
|
start = expressionList
|
|
1355
1484
|
|
|
1356
1485
|
expressionList =
|
|
@@ -1369,9 +1498,9 @@ negate = "!"
|
|
|
1369
1498
|
operator = "and"i / "or"i
|
|
1370
1499
|
|
|
1371
1500
|
|
|
1372
|
-
column = left:text "." right:text { return \`\${
|
|
1501
|
+
column = left:text "." right:text { return \`\${quoteSqlIdentity(left)}.\${quoteSqlIdentity(right)}\`; }
|
|
1373
1502
|
/
|
|
1374
|
-
text:text { return
|
|
1503
|
+
text:text { return quoteSqlIdentity(text); }
|
|
1375
1504
|
|
|
1376
1505
|
|
|
1377
1506
|
text = text:[a-z0-9-_:@]i+ { return text.join("");}
|
|
@@ -1397,18 +1526,155 @@ var filterPsqlParser = peg.generate(filterSqlGrammar, {
|
|
|
1397
1526
|
var filterPsqlParser_default = filterPsqlParser;
|
|
1398
1527
|
|
|
1399
1528
|
// src/restura/sql/PsqlEngine.ts
|
|
1529
|
+
import getDiff from "@wmfs/pg-diff-sync";
|
|
1530
|
+
import pgInfo from "@wmfs/pg-info";
|
|
1531
|
+
import { Client } from "pg";
|
|
1532
|
+
var systemUser = {
|
|
1533
|
+
role: "",
|
|
1534
|
+
host: "",
|
|
1535
|
+
ipAddress: "",
|
|
1536
|
+
isSystemUser: true
|
|
1537
|
+
};
|
|
1400
1538
|
var PsqlEngine = class extends SqlEngine {
|
|
1401
1539
|
constructor(psqlConnectionPool) {
|
|
1402
1540
|
super();
|
|
1403
1541
|
this.psqlConnectionPool = psqlConnectionPool;
|
|
1404
1542
|
}
|
|
1405
|
-
async
|
|
1406
|
-
|
|
1407
|
-
|
|
1543
|
+
async createDatabaseFromSchema(schema, connection) {
|
|
1544
|
+
const sqlFullStatement = this.generateDatabaseSchemaFromSchema(schema);
|
|
1545
|
+
await connection.runQuery(sqlFullStatement, [], systemUser);
|
|
1546
|
+
return sqlFullStatement;
|
|
1408
1547
|
}
|
|
1409
1548
|
generateDatabaseSchemaFromSchema(schema) {
|
|
1410
|
-
|
|
1411
|
-
|
|
1549
|
+
const sqlStatements = [];
|
|
1550
|
+
const enums = [];
|
|
1551
|
+
const indexes = [];
|
|
1552
|
+
for (const table of schema.database) {
|
|
1553
|
+
let sql = `CREATE TABLE "${table.name}"
|
|
1554
|
+
( `;
|
|
1555
|
+
const tableColumns = [];
|
|
1556
|
+
for (const column of table.columns) {
|
|
1557
|
+
let columnSql = "";
|
|
1558
|
+
if (column.type === "ENUM") {
|
|
1559
|
+
enums.push(`CREATE TYPE ${schemaToPsqlType(column, table.name)} AS ENUM (${column.value});`);
|
|
1560
|
+
}
|
|
1561
|
+
columnSql += ` "${column.name}" ${schemaToPsqlType(column, table.name)}`;
|
|
1562
|
+
let value = column.value;
|
|
1563
|
+
if (column.type === "JSON") value = "";
|
|
1564
|
+
if (column.type === "JSONB") value = "";
|
|
1565
|
+
if (column.type === "DECIMAL" && value) {
|
|
1566
|
+
value = value.replace("-", ",").replace(/['"]/g, "");
|
|
1567
|
+
}
|
|
1568
|
+
if (value && column.type !== "ENUM") {
|
|
1569
|
+
columnSql += `(${value})`;
|
|
1570
|
+
} else if (column.length) columnSql += `(${column.length})`;
|
|
1571
|
+
if (column.isPrimary) {
|
|
1572
|
+
columnSql += " PRIMARY KEY ";
|
|
1573
|
+
}
|
|
1574
|
+
if (column.isUnique) {
|
|
1575
|
+
columnSql += ` CONSTRAINT "${table.name}_${column.name}_unique_index" UNIQUE `;
|
|
1576
|
+
}
|
|
1577
|
+
if (column.isNullable) columnSql += " NULL";
|
|
1578
|
+
else columnSql += " NOT NULL";
|
|
1579
|
+
if (column.default) columnSql += ` DEFAULT '${column.default}'`;
|
|
1580
|
+
tableColumns.push(columnSql);
|
|
1581
|
+
}
|
|
1582
|
+
sql += tableColumns.join(", \n");
|
|
1583
|
+
for (const index of table.indexes) {
|
|
1584
|
+
if (!index.isPrimaryKey) {
|
|
1585
|
+
let unique = " ";
|
|
1586
|
+
if (index.isUnique) unique = "UNIQUE ";
|
|
1587
|
+
indexes.push(
|
|
1588
|
+
` CREATE ${unique}INDEX "${index.name}" ON "${table.name}" (${index.columns.map((item) => {
|
|
1589
|
+
return `"${item}" ${index.order}`;
|
|
1590
|
+
}).join(", ")})`
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
sql += "\n);";
|
|
1595
|
+
sqlStatements.push(sql);
|
|
1596
|
+
}
|
|
1597
|
+
for (const table of schema.database) {
|
|
1598
|
+
if (!table.foreignKeys.length) continue;
|
|
1599
|
+
const sql = `ALTER TABLE "${table.name}" `;
|
|
1600
|
+
const constraints = [];
|
|
1601
|
+
for (const foreignKey of table.foreignKeys) {
|
|
1602
|
+
let constraint = ` ADD CONSTRAINT "${foreignKey.name}"
|
|
1603
|
+
FOREIGN KEY ("${foreignKey.column}") REFERENCES "${foreignKey.refTable}" ("${foreignKey.refColumn}")`;
|
|
1604
|
+
constraint += ` ON DELETE ${foreignKey.onDelete}`;
|
|
1605
|
+
constraint += ` ON UPDATE ${foreignKey.onUpdate}`;
|
|
1606
|
+
constraints.push(constraint);
|
|
1607
|
+
}
|
|
1608
|
+
sqlStatements.push(sql + constraints.join(",\n") + ";");
|
|
1609
|
+
}
|
|
1610
|
+
for (const table of schema.database) {
|
|
1611
|
+
if (!table.checkConstraints.length) continue;
|
|
1612
|
+
const sql = `ALTER TABLE "${table.name}" `;
|
|
1613
|
+
const constraints = [];
|
|
1614
|
+
for (const check of table.checkConstraints) {
|
|
1615
|
+
const constraint = `ADD CONSTRAINT "${check.name}" CHECK (${check.check})`;
|
|
1616
|
+
constraints.push(constraint);
|
|
1617
|
+
}
|
|
1618
|
+
sqlStatements.push(sql + constraints.join(",\n") + ";");
|
|
1619
|
+
}
|
|
1620
|
+
sqlStatements.push(indexes.join(";\n"));
|
|
1621
|
+
return enums.join("\n") + "\n" + sqlStatements.join("\n\n");
|
|
1622
|
+
}
|
|
1623
|
+
async getScratchPool() {
|
|
1624
|
+
await this.psqlConnectionPool.runQuery(
|
|
1625
|
+
`DROP DATABASE IF EXISTS ${this.psqlConnectionPool.poolConfig.database}_scratch`,
|
|
1626
|
+
[],
|
|
1627
|
+
systemUser
|
|
1628
|
+
);
|
|
1629
|
+
await this.psqlConnectionPool.runQuery(
|
|
1630
|
+
`CREATE DATABASE ${this.psqlConnectionPool.poolConfig.database}_scratch;`,
|
|
1631
|
+
[],
|
|
1632
|
+
systemUser
|
|
1633
|
+
);
|
|
1634
|
+
const scratchPool = new PsqlPool({
|
|
1635
|
+
host: this.psqlConnectionPool.poolConfig.host,
|
|
1636
|
+
port: this.psqlConnectionPool.poolConfig.port,
|
|
1637
|
+
user: this.psqlConnectionPool.poolConfig.user,
|
|
1638
|
+
database: this.psqlConnectionPool.poolConfig.database + "_scratch",
|
|
1639
|
+
password: this.psqlConnectionPool.poolConfig.password,
|
|
1640
|
+
max: this.psqlConnectionPool.poolConfig.max,
|
|
1641
|
+
idleTimeoutMillis: this.psqlConnectionPool.poolConfig.idleTimeoutMillis,
|
|
1642
|
+
connectionTimeoutMillis: this.psqlConnectionPool.poolConfig.connectionTimeoutMillis
|
|
1643
|
+
});
|
|
1644
|
+
return scratchPool;
|
|
1645
|
+
}
|
|
1646
|
+
async diffDatabaseToSchema(schema) {
|
|
1647
|
+
const scratchPool = await this.getScratchPool();
|
|
1648
|
+
await this.createDatabaseFromSchema(schema, scratchPool);
|
|
1649
|
+
const originalClient = new Client({
|
|
1650
|
+
database: this.psqlConnectionPool.poolConfig.database,
|
|
1651
|
+
user: this.psqlConnectionPool.poolConfig.user,
|
|
1652
|
+
password: this.psqlConnectionPool.poolConfig.password,
|
|
1653
|
+
host: this.psqlConnectionPool.poolConfig.host,
|
|
1654
|
+
port: this.psqlConnectionPool.poolConfig.port
|
|
1655
|
+
});
|
|
1656
|
+
const scratchClient = new Client({
|
|
1657
|
+
database: this.psqlConnectionPool.poolConfig.database + "_scratch",
|
|
1658
|
+
user: this.psqlConnectionPool.poolConfig.user,
|
|
1659
|
+
password: this.psqlConnectionPool.poolConfig.password,
|
|
1660
|
+
host: this.psqlConnectionPool.poolConfig.host,
|
|
1661
|
+
port: this.psqlConnectionPool.poolConfig.port
|
|
1662
|
+
});
|
|
1663
|
+
await originalClient.connect();
|
|
1664
|
+
await scratchClient.connect();
|
|
1665
|
+
const info1 = await pgInfo({
|
|
1666
|
+
client: originalClient,
|
|
1667
|
+
schema: "public"
|
|
1668
|
+
});
|
|
1669
|
+
const info2 = await pgInfo({
|
|
1670
|
+
client: scratchClient,
|
|
1671
|
+
schema: "public"
|
|
1672
|
+
});
|
|
1673
|
+
const diff = getDiff(info1, info2);
|
|
1674
|
+
console.log("Schema differences:", diff);
|
|
1675
|
+
await originalClient.end();
|
|
1676
|
+
await scratchClient.end();
|
|
1677
|
+
return diff.join("\n");
|
|
1412
1678
|
}
|
|
1413
1679
|
createNestedSelect(req, schema, item, routeData, userRole, sqlParams) {
|
|
1414
1680
|
if (!item.subquery) return "";
|
|
@@ -1684,77 +1950,12 @@ ${sqlStatement};`,
|
|
|
1684
1950
|
return whereClause;
|
|
1685
1951
|
}
|
|
1686
1952
|
};
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
constructor(poolConfig) {
|
|
1694
|
-
this.poolConfig = poolConfig;
|
|
1695
|
-
this.pool = new Pool(poolConfig);
|
|
1696
|
-
this.queryOne("SELECT NOW();", [], { isSystemUser: true, role: "", host: "localhost", ipAddress: "" }).then(() => {
|
|
1697
|
-
logger.info("Connected to PostgreSQL database");
|
|
1698
|
-
}).catch((error) => {
|
|
1699
|
-
logger.error("Error connecting to database", error);
|
|
1700
|
-
process.exit(1);
|
|
1701
|
-
});
|
|
1702
|
-
}
|
|
1703
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1704
|
-
async queryOne(query, options, requesterDetails) {
|
|
1705
|
-
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1706
|
-
this.logSqlStatement(formattedQuery, options, requesterDetails);
|
|
1707
|
-
try {
|
|
1708
|
-
const response = await this.pool.query(formattedQuery, options);
|
|
1709
|
-
if (response.rows.length === 0) throw new RsError("NOT_FOUND", "No results found");
|
|
1710
|
-
else if (response.rows.length > 1) throw new RsError("DUPLICATE", "More than one result found");
|
|
1711
|
-
return response.rows[0];
|
|
1712
|
-
} catch (error) {
|
|
1713
|
-
console.error(error, query, options);
|
|
1714
|
-
if (RsError.isRsError(error)) throw error;
|
|
1715
|
-
if ((error == null ? void 0 : error.routine) === "_bt_check_unique") {
|
|
1716
|
-
throw new RsError("DUPLICATE", error.message);
|
|
1717
|
-
}
|
|
1718
|
-
throw new RsError("DATABASE_ERROR", `${error.message}`);
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1722
|
-
async runQuery(query, options, requesterDetails) {
|
|
1723
|
-
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1724
|
-
this.logSqlStatement(formattedQuery, options, requesterDetails);
|
|
1725
|
-
const queryUpdated = query.replace(/[\t\n]/g, " ");
|
|
1726
|
-
console.log(queryUpdated, options);
|
|
1727
|
-
try {
|
|
1728
|
-
const response = await this.pool.query(formattedQuery, options);
|
|
1729
|
-
return response.rows;
|
|
1730
|
-
} catch (error) {
|
|
1731
|
-
console.error(error, query, options);
|
|
1732
|
-
if ((error == null ? void 0 : error.routine) === "_bt_check_unique") {
|
|
1733
|
-
throw new RsError("DUPLICATE", error.message);
|
|
1734
|
-
}
|
|
1735
|
-
throw new RsError("DATABASE_ERROR", `${error.message}`);
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
logSqlStatement(query, options, requesterDetails, prefix = "") {
|
|
1739
|
-
if (logger.level !== "silly") return;
|
|
1740
|
-
let sqlStatement = "";
|
|
1741
|
-
if (options.length === 0) {
|
|
1742
|
-
sqlStatement = query;
|
|
1743
|
-
} else {
|
|
1744
|
-
let stringIndex = 0;
|
|
1745
|
-
sqlStatement = query.replace(/\$\d+/g, () => {
|
|
1746
|
-
const value = options[stringIndex++];
|
|
1747
|
-
if (typeof value === "number") return value.toString();
|
|
1748
|
-
return format3.literal(value);
|
|
1749
|
-
});
|
|
1750
|
-
}
|
|
1751
|
-
let initiator = "Anonymous";
|
|
1752
|
-
if ("userId" in requesterDetails && requesterDetails.userId)
|
|
1753
|
-
initiator = `User Id (${requesterDetails.userId.toString()})`;
|
|
1754
|
-
if ("isSystemUser" in requesterDetails && requesterDetails.isSystemUser) initiator = "SYSTEM";
|
|
1755
|
-
logger.silly(`${prefix}query by ${initiator}, Query ->
|
|
1756
|
-
${sqlStatement}`);
|
|
1757
|
-
}
|
|
1953
|
+
var schemaToPsqlType = (column, tableName) => {
|
|
1954
|
+
if (column.hasAutoIncrement) return "BIGSERIAL";
|
|
1955
|
+
if (column.type === "ENUM") return `"${tableName}_${column.name}_enum"`;
|
|
1956
|
+
if (column.type === "DATETIME") return "TIMESTAMPTZ";
|
|
1957
|
+
if (column.type === "MEDIUMINT") return "INT";
|
|
1958
|
+
return column.type;
|
|
1758
1959
|
};
|
|
1759
1960
|
|
|
1760
1961
|
// src/restura/restura.ts
|