@restura/core 0.1.0-alpha.13 → 0.1.0-alpha.15
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 +41 -23
- package/dist/index.d.ts +41 -23
- package/dist/index.js +170 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +168 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -68,7 +68,9 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
68
68
|
var src_exports = {};
|
|
69
69
|
__export(src_exports, {
|
|
70
70
|
HtmlStatusCodes: () => HtmlStatusCodes,
|
|
71
|
+
PsqlConnection: () => PsqlConnection,
|
|
71
72
|
PsqlPool: () => PsqlPool,
|
|
73
|
+
PsqlTransaction: () => PsqlTransaction,
|
|
72
74
|
RsError: () => RsError,
|
|
73
75
|
SQL: () => SQL,
|
|
74
76
|
escapeColumnName: () => escapeColumnName,
|
|
@@ -258,7 +260,7 @@ var import_crypto = require("crypto");
|
|
|
258
260
|
var express = __toESM(require("express"));
|
|
259
261
|
var import_fs3 = __toESM(require("fs"));
|
|
260
262
|
var import_path3 = __toESM(require("path"));
|
|
261
|
-
var
|
|
263
|
+
var import_pg4 = __toESM(require("pg"));
|
|
262
264
|
var prettier3 = __toESM(require("prettier"));
|
|
263
265
|
|
|
264
266
|
// src/restura/sql/SqlUtils.ts
|
|
@@ -790,7 +792,7 @@ var joinDataSchema = import_zod3.z.object({
|
|
|
790
792
|
var requestDataSchema = import_zod3.z.object({
|
|
791
793
|
name: import_zod3.z.string(),
|
|
792
794
|
required: import_zod3.z.boolean(),
|
|
793
|
-
isNullable: import_zod3.z.boolean().optional()
|
|
795
|
+
isNullable: import_zod3.z.boolean().optional(),
|
|
794
796
|
validator: import_zod3.z.array(validatorDataSchema)
|
|
795
797
|
}).strict();
|
|
796
798
|
var responseDataSchema = import_zod3.z.object({
|
|
@@ -876,6 +878,12 @@ var postgresColumnDateTypesSchema = import_zod3.z.enum([
|
|
|
876
878
|
"INTERVAL"
|
|
877
879
|
// time span
|
|
878
880
|
]);
|
|
881
|
+
var postgresColumnJsonTypesSchema = import_zod3.z.enum([
|
|
882
|
+
"JSON",
|
|
883
|
+
// stores JSON data as raw text
|
|
884
|
+
"JSONB"
|
|
885
|
+
// stores JSON data in a binary format, optimized for query performance
|
|
886
|
+
]);
|
|
879
887
|
var mariaDbColumnNumericTypesSchema = import_zod3.z.enum([
|
|
880
888
|
"BOOLEAN",
|
|
881
889
|
// 1-byte A synonym for "TINYINT(1)". Supported from version 1.2.0 onwards.
|
|
@@ -938,6 +946,7 @@ var columnDataSchema = import_zod3.z.object({
|
|
|
938
946
|
postgresColumnNumericTypesSchema,
|
|
939
947
|
postgresColumnStringTypesSchema,
|
|
940
948
|
postgresColumnDateTypesSchema,
|
|
949
|
+
postgresColumnJsonTypesSchema,
|
|
941
950
|
mariaDbColumnNumericTypesSchema,
|
|
942
951
|
mariaDbColumnStringTypesSchema,
|
|
943
952
|
mariaDbColumnDateTypesSchema
|
|
@@ -1245,9 +1254,14 @@ function convertTable(table) {
|
|
|
1245
1254
|
|
|
1246
1255
|
// src/restura/sql/PsqlEngine.ts
|
|
1247
1256
|
var import_core_utils5 = require("@redskytech/core-utils");
|
|
1257
|
+
var import_pg_diff_sync = __toESM(require("@wmfs/pg-diff-sync"));
|
|
1258
|
+
var import_pg_info = __toESM(require("@wmfs/pg-info"));
|
|
1259
|
+
var import_pg2 = __toESM(require("pg"));
|
|
1248
1260
|
|
|
1249
1261
|
// src/restura/sql/PsqlPool.ts
|
|
1250
1262
|
var import_pg = __toESM(require("pg"));
|
|
1263
|
+
|
|
1264
|
+
// src/restura/sql/PsqlConnection.ts
|
|
1251
1265
|
var import_pg_format2 = __toESM(require("pg-format"));
|
|
1252
1266
|
|
|
1253
1267
|
// src/restura/sql/PsqlUtils.ts
|
|
@@ -1297,25 +1311,16 @@ function SQL(strings, ...values) {
|
|
|
1297
1311
|
return query;
|
|
1298
1312
|
}
|
|
1299
1313
|
|
|
1300
|
-
// src/restura/sql/
|
|
1301
|
-
var
|
|
1302
|
-
|
|
1303
|
-
constructor(poolConfig) {
|
|
1304
|
-
this.poolConfig = poolConfig;
|
|
1305
|
-
this.pool = new Pool(poolConfig);
|
|
1306
|
-
this.queryOne("SELECT NOW();", [], { isSystemUser: true, role: "", host: "localhost", ipAddress: "" }).then(() => {
|
|
1307
|
-
logger.info("Connected to PostgreSQL database");
|
|
1308
|
-
}).catch((error) => {
|
|
1309
|
-
logger.error("Error connecting to database", error);
|
|
1310
|
-
process.exit(1);
|
|
1311
|
-
});
|
|
1314
|
+
// src/restura/sql/PsqlConnection.ts
|
|
1315
|
+
var PsqlConnection = class {
|
|
1316
|
+
constructor() {
|
|
1312
1317
|
}
|
|
1313
1318
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1314
1319
|
async queryOne(query, options, requesterDetails) {
|
|
1315
1320
|
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1316
1321
|
this.logSqlStatement(formattedQuery, options, requesterDetails);
|
|
1317
1322
|
try {
|
|
1318
|
-
const response = await this.
|
|
1323
|
+
const response = await this.query(formattedQuery, options);
|
|
1319
1324
|
if (response.rows.length === 0) throw new RsError("NOT_FOUND", "No results found");
|
|
1320
1325
|
else if (response.rows.length > 1) throw new RsError("DUPLICATE", "More than one result found");
|
|
1321
1326
|
return response.rows[0];
|
|
@@ -1332,10 +1337,8 @@ var PsqlPool = class {
|
|
|
1332
1337
|
async runQuery(query, options, requesterDetails) {
|
|
1333
1338
|
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1334
1339
|
this.logSqlStatement(formattedQuery, options, requesterDetails);
|
|
1335
|
-
const queryUpdated = query.replace(/[\t\n]/g, " ");
|
|
1336
|
-
console.log(queryUpdated, options);
|
|
1337
1340
|
try {
|
|
1338
|
-
const response = await this.
|
|
1341
|
+
const response = await this.query(formattedQuery, options);
|
|
1339
1342
|
return response.rows;
|
|
1340
1343
|
} catch (error) {
|
|
1341
1344
|
console.error(error, query, options);
|
|
@@ -1367,6 +1370,25 @@ var PsqlPool = class {
|
|
|
1367
1370
|
}
|
|
1368
1371
|
};
|
|
1369
1372
|
|
|
1373
|
+
// src/restura/sql/PsqlPool.ts
|
|
1374
|
+
var { Pool } = import_pg.default;
|
|
1375
|
+
var PsqlPool = class extends PsqlConnection {
|
|
1376
|
+
constructor(poolConfig) {
|
|
1377
|
+
super();
|
|
1378
|
+
this.poolConfig = poolConfig;
|
|
1379
|
+
this.pool = new Pool(poolConfig);
|
|
1380
|
+
this.queryOne("SELECT NOW();", [], { isSystemUser: true, role: "", host: "localhost", ipAddress: "" }).then(() => {
|
|
1381
|
+
logger.info("Connected to PostgreSQL database");
|
|
1382
|
+
}).catch((error) => {
|
|
1383
|
+
logger.error("Error connecting to database", error);
|
|
1384
|
+
process.exit(1);
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1387
|
+
async query(query, values) {
|
|
1388
|
+
return this.pool.query(query, values);
|
|
1389
|
+
}
|
|
1390
|
+
};
|
|
1391
|
+
|
|
1370
1392
|
// src/restura/sql/SqlEngine.ts
|
|
1371
1393
|
var import_core_utils4 = require("@redskytech/core-utils");
|
|
1372
1394
|
var SqlEngine = class {
|
|
@@ -1531,9 +1553,9 @@ expressionList =
|
|
|
1531
1553
|
|
|
1532
1554
|
expression =
|
|
1533
1555
|
negate:negate?"(" "column:" column:column ","? value:value? ","? type:type? ")"
|
|
1534
|
-
{return \`\${negate? "
|
|
1556
|
+
{return \`\${negate? " NOT " : ""}(\${type? type(column, value) : \`\${column} = \${format.literal(value)}\`})\`;}
|
|
1535
1557
|
/
|
|
1536
|
-
negate:negate?"("expression:expressionList")" { return \`\${negate? "
|
|
1558
|
+
negate:negate?"("expression:expressionList")" { return \`\${negate? " NOT " : ""}(\${expression})\`; }
|
|
1537
1559
|
|
|
1538
1560
|
negate = "!"
|
|
1539
1561
|
|
|
@@ -1568,9 +1590,7 @@ var filterPsqlParser = import_pegjs.default.generate(filterSqlGrammar, {
|
|
|
1568
1590
|
var filterPsqlParser_default = filterPsqlParser;
|
|
1569
1591
|
|
|
1570
1592
|
// src/restura/sql/PsqlEngine.ts
|
|
1571
|
-
var
|
|
1572
|
-
var import_pg_info = __toESM(require("@wmfs/pg-info"));
|
|
1573
|
-
var { Client } = "pg";
|
|
1593
|
+
var { Client } = import_pg2.default;
|
|
1574
1594
|
var systemUser = {
|
|
1575
1595
|
role: "",
|
|
1576
1596
|
host: "",
|
|
@@ -1618,7 +1638,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1618
1638
|
}
|
|
1619
1639
|
if (column.isNullable) columnSql += " NULL";
|
|
1620
1640
|
else columnSql += " NOT NULL";
|
|
1621
|
-
if (column.default) columnSql += ` DEFAULT
|
|
1641
|
+
if (column.default) columnSql += ` DEFAULT ${column.default}`;
|
|
1622
1642
|
tableColumns.push(columnSql);
|
|
1623
1643
|
}
|
|
1624
1644
|
sql += tableColumns.join(", \n");
|
|
@@ -1705,15 +1725,12 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1705
1725
|
await originalClient.connect();
|
|
1706
1726
|
await scratchClient.connect();
|
|
1707
1727
|
const info1 = await (0, import_pg_info.default)({
|
|
1708
|
-
client: originalClient
|
|
1709
|
-
schema: "public"
|
|
1728
|
+
client: originalClient
|
|
1710
1729
|
});
|
|
1711
1730
|
const info2 = await (0, import_pg_info.default)({
|
|
1712
|
-
client: scratchClient
|
|
1713
|
-
schema: "public"
|
|
1731
|
+
client: scratchClient
|
|
1714
1732
|
});
|
|
1715
1733
|
const diff = (0, import_pg_diff_sync.default)(info1, info2);
|
|
1716
|
-
console.log("Schema differences:", diff);
|
|
1717
1734
|
await originalClient.end();
|
|
1718
1735
|
await scratchClient.end();
|
|
1719
1736
|
return diff.join("\n");
|
|
@@ -1990,16 +2007,135 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1990
2007
|
return whereClause;
|
|
1991
2008
|
}
|
|
1992
2009
|
};
|
|
1993
|
-
|
|
2010
|
+
function schemaToPsqlType(column, tableName) {
|
|
1994
2011
|
if (column.hasAutoIncrement) return "BIGSERIAL";
|
|
1995
2012
|
if (column.type === "ENUM") return `"${tableName}_${column.name}_enum"`;
|
|
1996
2013
|
if (column.type === "DATETIME") return "TIMESTAMPTZ";
|
|
1997
2014
|
if (column.type === "MEDIUMINT") return "INT";
|
|
1998
2015
|
return column.type;
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
// src/restura/sql/PsqlTransaction.ts
|
|
2019
|
+
var import_pg3 = __toESM(require("pg"));
|
|
2020
|
+
var { Client: Client2 } = import_pg3.default;
|
|
2021
|
+
var PsqlTransaction = class extends PsqlConnection {
|
|
2022
|
+
constructor(clientConfig) {
|
|
2023
|
+
super();
|
|
2024
|
+
this.clientConfig = clientConfig;
|
|
2025
|
+
this.client = new Client2(clientConfig);
|
|
2026
|
+
this.beginTransactionPromise = this.beginTransaction();
|
|
2027
|
+
}
|
|
2028
|
+
async beginTransaction() {
|
|
2029
|
+
return this.query("BEGIN");
|
|
2030
|
+
}
|
|
2031
|
+
async rollback() {
|
|
2032
|
+
return this.query("ROLLBACK");
|
|
2033
|
+
}
|
|
2034
|
+
async commit() {
|
|
2035
|
+
return this.query("COMMIT");
|
|
2036
|
+
}
|
|
2037
|
+
async release() {
|
|
2038
|
+
return this.client.end();
|
|
2039
|
+
}
|
|
2040
|
+
async query(query, values) {
|
|
2041
|
+
await this.client.connect();
|
|
2042
|
+
await this.beginTransactionPromise;
|
|
2043
|
+
return this.client.query(query, values);
|
|
2044
|
+
}
|
|
2045
|
+
};
|
|
2046
|
+
|
|
2047
|
+
// src/restura/compareSchema.ts
|
|
2048
|
+
var import_lodash = __toESM(require("lodash.clonedeep"));
|
|
2049
|
+
var CompareSchema = class {
|
|
2050
|
+
async diffSchema(newSchema, latestSchema, psqlEngine) {
|
|
2051
|
+
const endPoints = this.diffEndPoints(newSchema.endpoints[0].routes, latestSchema.endpoints[0].routes);
|
|
2052
|
+
const globalParams = this.diffStringArray(newSchema.globalParams, latestSchema.globalParams);
|
|
2053
|
+
const roles = this.diffStringArray(newSchema.roles, latestSchema.roles);
|
|
2054
|
+
let commands = "";
|
|
2055
|
+
if (JSON.stringify(newSchema.database) !== JSON.stringify(latestSchema.database))
|
|
2056
|
+
commands = await psqlEngine.diffDatabaseToSchema(newSchema);
|
|
2057
|
+
const customTypes = newSchema.customTypes !== latestSchema.customTypes;
|
|
2058
|
+
const schemaPreview = { endPoints, globalParams, roles, commands, customTypes };
|
|
2059
|
+
return schemaPreview;
|
|
2060
|
+
}
|
|
2061
|
+
diffStringArray(newArray, originalArray) {
|
|
2062
|
+
const stringsDiff = [];
|
|
2063
|
+
const originalClone = new Set(originalArray);
|
|
2064
|
+
newArray.forEach((item) => {
|
|
2065
|
+
const originalIndex = originalClone.has(item);
|
|
2066
|
+
if (!originalIndex) {
|
|
2067
|
+
stringsDiff.push({
|
|
2068
|
+
name: item,
|
|
2069
|
+
changeType: "NEW"
|
|
2070
|
+
});
|
|
2071
|
+
} else {
|
|
2072
|
+
originalClone.delete(item);
|
|
2073
|
+
}
|
|
2074
|
+
});
|
|
2075
|
+
originalClone.forEach((item) => {
|
|
2076
|
+
stringsDiff.push({
|
|
2077
|
+
name: item,
|
|
2078
|
+
changeType: "DELETED"
|
|
2079
|
+
});
|
|
2080
|
+
});
|
|
2081
|
+
return stringsDiff;
|
|
2082
|
+
}
|
|
2083
|
+
diffEndPoints(newEndPoints, originalEndpoints) {
|
|
2084
|
+
const originalClone = (0, import_lodash.default)(originalEndpoints);
|
|
2085
|
+
const diffObj = [];
|
|
2086
|
+
newEndPoints.forEach((endPoint) => {
|
|
2087
|
+
const { path: path4, method } = endPoint;
|
|
2088
|
+
const endPointIndex = originalClone.findIndex((original) => {
|
|
2089
|
+
return original.path === endPoint.path && original.method === endPoint.method;
|
|
2090
|
+
});
|
|
2091
|
+
if (endPointIndex === -1) {
|
|
2092
|
+
diffObj.push({
|
|
2093
|
+
name: `${method} ${path4}`,
|
|
2094
|
+
changeType: "NEW"
|
|
2095
|
+
});
|
|
2096
|
+
} else {
|
|
2097
|
+
const original = originalClone.findIndex((original2) => {
|
|
2098
|
+
return this.compareEndPoints(endPoint, original2);
|
|
2099
|
+
});
|
|
2100
|
+
if (original === -1) {
|
|
2101
|
+
diffObj.push({
|
|
2102
|
+
name: `${method} ${path4}`,
|
|
2103
|
+
changeType: "MODIFIED"
|
|
2104
|
+
});
|
|
2105
|
+
}
|
|
2106
|
+
originalClone.splice(endPointIndex, 1);
|
|
2107
|
+
}
|
|
2108
|
+
});
|
|
2109
|
+
originalClone.forEach((original) => {
|
|
2110
|
+
const { path: path4, method } = original;
|
|
2111
|
+
diffObj.push({
|
|
2112
|
+
name: `${method} ${path4}`,
|
|
2113
|
+
changeType: "DELETED"
|
|
2114
|
+
});
|
|
2115
|
+
});
|
|
2116
|
+
return diffObj;
|
|
2117
|
+
}
|
|
2118
|
+
compareEndPoints(endPoint1, endPoint2) {
|
|
2119
|
+
return JSON.stringify(endPoint1) === JSON.stringify(endPoint2);
|
|
2120
|
+
}
|
|
1999
2121
|
};
|
|
2122
|
+
__decorateClass([
|
|
2123
|
+
boundMethod
|
|
2124
|
+
], CompareSchema.prototype, "diffSchema", 1);
|
|
2125
|
+
__decorateClass([
|
|
2126
|
+
boundMethod
|
|
2127
|
+
], CompareSchema.prototype, "diffStringArray", 1);
|
|
2128
|
+
__decorateClass([
|
|
2129
|
+
boundMethod
|
|
2130
|
+
], CompareSchema.prototype, "diffEndPoints", 1);
|
|
2131
|
+
__decorateClass([
|
|
2132
|
+
boundMethod
|
|
2133
|
+
], CompareSchema.prototype, "compareEndPoints", 1);
|
|
2134
|
+
var compareSchema = new CompareSchema();
|
|
2135
|
+
var compareSchema_default = compareSchema;
|
|
2000
2136
|
|
|
2001
2137
|
// src/restura/restura.ts
|
|
2002
|
-
var { types } =
|
|
2138
|
+
var { types } = import_pg4.default;
|
|
2003
2139
|
var ResturaEngine = class {
|
|
2004
2140
|
constructor() {
|
|
2005
2141
|
this.publicEndpoints = {
|
|
@@ -2203,7 +2339,7 @@ var ResturaEngine = class {
|
|
|
2203
2339
|
}
|
|
2204
2340
|
async previewCreateSchema(req, res) {
|
|
2205
2341
|
try {
|
|
2206
|
-
const schemaDiff =
|
|
2342
|
+
const schemaDiff = await compareSchema_default.diffSchema(req.data, this.schema, this.psqlEngine);
|
|
2207
2343
|
res.send({ data: schemaDiff });
|
|
2208
2344
|
} catch (err) {
|
|
2209
2345
|
res.status(400).send(err);
|
|
@@ -2377,7 +2513,9 @@ var restura = new ResturaEngine();
|
|
|
2377
2513
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2378
2514
|
0 && (module.exports = {
|
|
2379
2515
|
HtmlStatusCodes,
|
|
2516
|
+
PsqlConnection,
|
|
2380
2517
|
PsqlPool,
|
|
2518
|
+
PsqlTransaction,
|
|
2381
2519
|
RsError,
|
|
2382
2520
|
SQL,
|
|
2383
2521
|
escapeColumnName,
|