@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.mjs CHANGED
@@ -216,7 +216,7 @@ import { createHash } from "crypto";
216
216
  import * as express from "express";
217
217
  import fs3 from "fs";
218
218
  import path3 from "path";
219
- import pg2 from "pg";
219
+ import pg4 from "pg";
220
220
  import * as prettier3 from "prettier";
221
221
 
222
222
  // src/restura/sql/SqlUtils.ts
@@ -748,7 +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
+ isNullable: z3.boolean().optional(),
752
752
  validator: z3.array(validatorDataSchema)
753
753
  }).strict();
754
754
  var responseDataSchema = z3.object({
@@ -834,6 +834,12 @@ var postgresColumnDateTypesSchema = z3.enum([
834
834
  "INTERVAL"
835
835
  // time span
836
836
  ]);
837
+ var postgresColumnJsonTypesSchema = z3.enum([
838
+ "JSON",
839
+ // stores JSON data as raw text
840
+ "JSONB"
841
+ // stores JSON data in a binary format, optimized for query performance
842
+ ]);
837
843
  var mariaDbColumnNumericTypesSchema = z3.enum([
838
844
  "BOOLEAN",
839
845
  // 1-byte A synonym for "TINYINT(1)". Supported from version 1.2.0 onwards.
@@ -896,6 +902,7 @@ var columnDataSchema = z3.object({
896
902
  postgresColumnNumericTypesSchema,
897
903
  postgresColumnStringTypesSchema,
898
904
  postgresColumnDateTypesSchema,
905
+ postgresColumnJsonTypesSchema,
899
906
  mariaDbColumnNumericTypesSchema,
900
907
  mariaDbColumnStringTypesSchema,
901
908
  mariaDbColumnDateTypesSchema
@@ -1203,9 +1210,14 @@ function convertTable(table) {
1203
1210
 
1204
1211
  // src/restura/sql/PsqlEngine.ts
1205
1212
  import { ObjectUtils as ObjectUtils4 } from "@redskytech/core-utils";
1213
+ import getDiff from "@wmfs/pg-diff-sync";
1214
+ import pgInfo from "@wmfs/pg-info";
1215
+ import pg2 from "pg";
1206
1216
 
1207
1217
  // src/restura/sql/PsqlPool.ts
1208
1218
  import pg from "pg";
1219
+
1220
+ // src/restura/sql/PsqlConnection.ts
1209
1221
  import format3 from "pg-format";
1210
1222
 
1211
1223
  // src/restura/sql/PsqlUtils.ts
@@ -1255,25 +1267,16 @@ function SQL(strings, ...values) {
1255
1267
  return query;
1256
1268
  }
1257
1269
 
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
+ // src/restura/sql/PsqlConnection.ts
1271
+ var PsqlConnection = class {
1272
+ constructor() {
1270
1273
  }
1271
1274
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1272
1275
  async queryOne(query, options, requesterDetails) {
1273
1276
  const formattedQuery = questionMarksToOrderedParams(query);
1274
1277
  this.logSqlStatement(formattedQuery, options, requesterDetails);
1275
1278
  try {
1276
- const response = await this.pool.query(formattedQuery, options);
1279
+ const response = await this.query(formattedQuery, options);
1277
1280
  if (response.rows.length === 0) throw new RsError("NOT_FOUND", "No results found");
1278
1281
  else if (response.rows.length > 1) throw new RsError("DUPLICATE", "More than one result found");
1279
1282
  return response.rows[0];
@@ -1290,10 +1293,8 @@ var PsqlPool = class {
1290
1293
  async runQuery(query, options, requesterDetails) {
1291
1294
  const formattedQuery = questionMarksToOrderedParams(query);
1292
1295
  this.logSqlStatement(formattedQuery, options, requesterDetails);
1293
- const queryUpdated = query.replace(/[\t\n]/g, " ");
1294
- console.log(queryUpdated, options);
1295
1296
  try {
1296
- const response = await this.pool.query(formattedQuery, options);
1297
+ const response = await this.query(formattedQuery, options);
1297
1298
  return response.rows;
1298
1299
  } catch (error) {
1299
1300
  console.error(error, query, options);
@@ -1325,6 +1326,25 @@ var PsqlPool = class {
1325
1326
  }
1326
1327
  };
1327
1328
 
1329
+ // src/restura/sql/PsqlPool.ts
1330
+ var { Pool } = pg;
1331
+ var PsqlPool = class extends PsqlConnection {
1332
+ constructor(poolConfig) {
1333
+ super();
1334
+ this.poolConfig = poolConfig;
1335
+ this.pool = new Pool(poolConfig);
1336
+ this.queryOne("SELECT NOW();", [], { isSystemUser: true, role: "", host: "localhost", ipAddress: "" }).then(() => {
1337
+ logger.info("Connected to PostgreSQL database");
1338
+ }).catch((error) => {
1339
+ logger.error("Error connecting to database", error);
1340
+ process.exit(1);
1341
+ });
1342
+ }
1343
+ async query(query, values) {
1344
+ return this.pool.query(query, values);
1345
+ }
1346
+ };
1347
+
1328
1348
  // src/restura/sql/SqlEngine.ts
1329
1349
  import { ObjectUtils as ObjectUtils3 } from "@redskytech/core-utils";
1330
1350
  var SqlEngine = class {
@@ -1489,9 +1509,9 @@ expressionList =
1489
1509
 
1490
1510
  expression =
1491
1511
  negate:negate?"(" "column:" column:column ","? value:value? ","? type:type? ")"
1492
- {return \`\${negate? "!" : ""}(\${type? type(column, value) : \`\${column} = \${format.literal(value)}\`})\`;}
1512
+ {return \`\${negate? " NOT " : ""}(\${type? type(column, value) : \`\${column} = \${format.literal(value)}\`})\`;}
1493
1513
  /
1494
- negate:negate?"("expression:expressionList")" { return \`\${negate? "!" : ""}(\${expression})\`; }
1514
+ negate:negate?"("expression:expressionList")" { return \`\${negate? " NOT " : ""}(\${expression})\`; }
1495
1515
 
1496
1516
  negate = "!"
1497
1517
 
@@ -1526,9 +1546,7 @@ var filterPsqlParser = peg.generate(filterSqlGrammar, {
1526
1546
  var filterPsqlParser_default = filterPsqlParser;
1527
1547
 
1528
1548
  // src/restura/sql/PsqlEngine.ts
1529
- import getDiff from "@wmfs/pg-diff-sync";
1530
- import pgInfo from "@wmfs/pg-info";
1531
- var { Client } = "pg";
1549
+ var { Client } = pg2;
1532
1550
  var systemUser = {
1533
1551
  role: "",
1534
1552
  host: "",
@@ -1576,7 +1594,7 @@ var PsqlEngine = class extends SqlEngine {
1576
1594
  }
1577
1595
  if (column.isNullable) columnSql += " NULL";
1578
1596
  else columnSql += " NOT NULL";
1579
- if (column.default) columnSql += ` DEFAULT '${column.default}'`;
1597
+ if (column.default) columnSql += ` DEFAULT ${column.default}`;
1580
1598
  tableColumns.push(columnSql);
1581
1599
  }
1582
1600
  sql += tableColumns.join(", \n");
@@ -1663,15 +1681,12 @@ var PsqlEngine = class extends SqlEngine {
1663
1681
  await originalClient.connect();
1664
1682
  await scratchClient.connect();
1665
1683
  const info1 = await pgInfo({
1666
- client: originalClient,
1667
- schema: "public"
1684
+ client: originalClient
1668
1685
  });
1669
1686
  const info2 = await pgInfo({
1670
- client: scratchClient,
1671
- schema: "public"
1687
+ client: scratchClient
1672
1688
  });
1673
1689
  const diff = getDiff(info1, info2);
1674
- console.log("Schema differences:", diff);
1675
1690
  await originalClient.end();
1676
1691
  await scratchClient.end();
1677
1692
  return diff.join("\n");
@@ -1948,16 +1963,135 @@ var PsqlEngine = class extends SqlEngine {
1948
1963
  return whereClause;
1949
1964
  }
1950
1965
  };
1951
- var schemaToPsqlType = (column, tableName) => {
1966
+ function schemaToPsqlType(column, tableName) {
1952
1967
  if (column.hasAutoIncrement) return "BIGSERIAL";
1953
1968
  if (column.type === "ENUM") return `"${tableName}_${column.name}_enum"`;
1954
1969
  if (column.type === "DATETIME") return "TIMESTAMPTZ";
1955
1970
  if (column.type === "MEDIUMINT") return "INT";
1956
1971
  return column.type;
1972
+ }
1973
+
1974
+ // src/restura/sql/PsqlTransaction.ts
1975
+ import pg3 from "pg";
1976
+ var { Client: Client2 } = pg3;
1977
+ var PsqlTransaction = class extends PsqlConnection {
1978
+ constructor(clientConfig) {
1979
+ super();
1980
+ this.clientConfig = clientConfig;
1981
+ this.client = new Client2(clientConfig);
1982
+ this.beginTransactionPromise = this.beginTransaction();
1983
+ }
1984
+ async beginTransaction() {
1985
+ return this.query("BEGIN");
1986
+ }
1987
+ async rollback() {
1988
+ return this.query("ROLLBACK");
1989
+ }
1990
+ async commit() {
1991
+ return this.query("COMMIT");
1992
+ }
1993
+ async release() {
1994
+ return this.client.end();
1995
+ }
1996
+ async query(query, values) {
1997
+ await this.client.connect();
1998
+ await this.beginTransactionPromise;
1999
+ return this.client.query(query, values);
2000
+ }
2001
+ };
2002
+
2003
+ // src/restura/compareSchema.ts
2004
+ import cloneDeep from "lodash.clonedeep";
2005
+ var CompareSchema = class {
2006
+ async diffSchema(newSchema, latestSchema, psqlEngine) {
2007
+ const endPoints = this.diffEndPoints(newSchema.endpoints[0].routes, latestSchema.endpoints[0].routes);
2008
+ const globalParams = this.diffStringArray(newSchema.globalParams, latestSchema.globalParams);
2009
+ const roles = this.diffStringArray(newSchema.roles, latestSchema.roles);
2010
+ let commands = "";
2011
+ if (JSON.stringify(newSchema.database) !== JSON.stringify(latestSchema.database))
2012
+ commands = await psqlEngine.diffDatabaseToSchema(newSchema);
2013
+ const customTypes = newSchema.customTypes !== latestSchema.customTypes;
2014
+ const schemaPreview = { endPoints, globalParams, roles, commands, customTypes };
2015
+ return schemaPreview;
2016
+ }
2017
+ diffStringArray(newArray, originalArray) {
2018
+ const stringsDiff = [];
2019
+ const originalClone = new Set(originalArray);
2020
+ newArray.forEach((item) => {
2021
+ const originalIndex = originalClone.has(item);
2022
+ if (!originalIndex) {
2023
+ stringsDiff.push({
2024
+ name: item,
2025
+ changeType: "NEW"
2026
+ });
2027
+ } else {
2028
+ originalClone.delete(item);
2029
+ }
2030
+ });
2031
+ originalClone.forEach((item) => {
2032
+ stringsDiff.push({
2033
+ name: item,
2034
+ changeType: "DELETED"
2035
+ });
2036
+ });
2037
+ return stringsDiff;
2038
+ }
2039
+ diffEndPoints(newEndPoints, originalEndpoints) {
2040
+ const originalClone = cloneDeep(originalEndpoints);
2041
+ const diffObj = [];
2042
+ newEndPoints.forEach((endPoint) => {
2043
+ const { path: path4, method } = endPoint;
2044
+ const endPointIndex = originalClone.findIndex((original) => {
2045
+ return original.path === endPoint.path && original.method === endPoint.method;
2046
+ });
2047
+ if (endPointIndex === -1) {
2048
+ diffObj.push({
2049
+ name: `${method} ${path4}`,
2050
+ changeType: "NEW"
2051
+ });
2052
+ } else {
2053
+ const original = originalClone.findIndex((original2) => {
2054
+ return this.compareEndPoints(endPoint, original2);
2055
+ });
2056
+ if (original === -1) {
2057
+ diffObj.push({
2058
+ name: `${method} ${path4}`,
2059
+ changeType: "MODIFIED"
2060
+ });
2061
+ }
2062
+ originalClone.splice(endPointIndex, 1);
2063
+ }
2064
+ });
2065
+ originalClone.forEach((original) => {
2066
+ const { path: path4, method } = original;
2067
+ diffObj.push({
2068
+ name: `${method} ${path4}`,
2069
+ changeType: "DELETED"
2070
+ });
2071
+ });
2072
+ return diffObj;
2073
+ }
2074
+ compareEndPoints(endPoint1, endPoint2) {
2075
+ return JSON.stringify(endPoint1) === JSON.stringify(endPoint2);
2076
+ }
1957
2077
  };
2078
+ __decorateClass([
2079
+ boundMethod
2080
+ ], CompareSchema.prototype, "diffSchema", 1);
2081
+ __decorateClass([
2082
+ boundMethod
2083
+ ], CompareSchema.prototype, "diffStringArray", 1);
2084
+ __decorateClass([
2085
+ boundMethod
2086
+ ], CompareSchema.prototype, "diffEndPoints", 1);
2087
+ __decorateClass([
2088
+ boundMethod
2089
+ ], CompareSchema.prototype, "compareEndPoints", 1);
2090
+ var compareSchema = new CompareSchema();
2091
+ var compareSchema_default = compareSchema;
1958
2092
 
1959
2093
  // src/restura/restura.ts
1960
- var { types } = pg2;
2094
+ var { types } = pg4;
1961
2095
  var ResturaEngine = class {
1962
2096
  constructor() {
1963
2097
  this.publicEndpoints = {
@@ -2161,7 +2295,7 @@ var ResturaEngine = class {
2161
2295
  }
2162
2296
  async previewCreateSchema(req, res) {
2163
2297
  try {
2164
- const schemaDiff = { commands: "", endPoints: [], globalParams: [], roles: [], customTypes: false };
2298
+ const schemaDiff = await compareSchema_default.diffSchema(req.data, this.schema, this.psqlEngine);
2165
2299
  res.send({ data: schemaDiff });
2166
2300
  } catch (err) {
2167
2301
  res.status(400).send(err);
@@ -2334,7 +2468,9 @@ setupPgReturnTypes();
2334
2468
  var restura = new ResturaEngine();
2335
2469
  export {
2336
2470
  HtmlStatusCodes,
2471
+ PsqlConnection,
2337
2472
  PsqlPool,
2473
+ PsqlTransaction,
2338
2474
  RsError,
2339
2475
  SQL,
2340
2476
  escapeColumnName,