@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.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 import_pg2 = __toESM(require("pg"));
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().default(false),
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/PsqlPool.ts
1301
- var { Pool } = import_pg.default;
1302
- var PsqlPool = class {
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.pool.query(formattedQuery, options);
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.pool.query(formattedQuery, options);
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? "!" : ""}(\${type? type(column, value) : \`\${column} = \${format.literal(value)}\`})\`;}
1556
+ {return \`\${negate? " NOT " : ""}(\${type? type(column, value) : \`\${column} = \${format.literal(value)}\`})\`;}
1535
1557
  /
1536
- negate:negate?"("expression:expressionList")" { return \`\${negate? "!" : ""}(\${expression})\`; }
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 import_pg_diff_sync = __toESM(require("@wmfs/pg-diff-sync"));
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 '${column.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
- var schemaToPsqlType = (column, tableName) => {
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 } = import_pg2.default;
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 = { commands: "", endPoints: [], globalParams: [], roles: [], customTypes: false };
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,