@restura/core 0.1.0-alpha.25 → 0.1.0-alpha.27

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 CHANGED
@@ -126,14 +126,14 @@ interface ActionRowInsertData<T = DynamicObject> extends DatabaseActionData {
126
126
  insertId: number;
127
127
  insertObject: T;
128
128
  }
129
- interface ActionRowDeleteData extends DatabaseActionData {
130
- deletedRow: DynamicObject;
129
+ interface ActionRowDeleteData<T = DynamicObject> extends DatabaseActionData {
130
+ deletedRow: T;
131
131
  }
132
- interface ActionColumnChangeData extends DatabaseActionData {
132
+ interface ActionColumnChangeData<T = DynamicObject> extends DatabaseActionData {
133
133
  tableName: string;
134
134
  rowId: number;
135
- newData: DynamicObject;
136
- oldData: DynamicObject;
135
+ newData: T;
136
+ oldData: T;
137
137
  }
138
138
  interface ActionRowInsertFilter {
139
139
  tableName: string;
@@ -158,9 +158,9 @@ type QueryMetadata = RequesterDetails & {
158
158
  };
159
159
  declare class EventManager {
160
160
  private actionHandlers;
161
- addRowInsertHandler(onInsert: (data: ActionRowInsertData<unknown>) => Promise<void>, filter?: ActionRowInsertFilter): void;
162
- addColumnChangeHandler(onUpdate: (data: ActionColumnChangeData) => Promise<void>, filter: ActionColumnChangeFilter): void;
163
- addRowDeleteHandler(onDelete: (data: ActionRowDeleteData) => Promise<void>, filter?: ActionRowDeleteFilter): void;
161
+ addRowInsertHandler<T>(onInsert: (data: ActionRowInsertData<T>, queryMetadata: QueryMetadata) => Promise<void>, filter?: ActionRowInsertFilter): void;
162
+ addColumnChangeHandler<T>(onUpdate: (data: ActionColumnChangeData<T>, queryMetadata: QueryMetadata) => Promise<void>, filter: ActionColumnChangeFilter): void;
163
+ addRowDeleteHandler<T>(onDelete: (data: ActionRowDeleteData<T>, queryMetadata: QueryMetadata) => Promise<void>, filter?: ActionRowDeleteFilter): void;
164
164
  fireActionFromDbTrigger(sqlMutationData: SqlMutationData, result: TriggerResult): Promise<void>;
165
165
  private fireInsertActions;
166
166
  private fireDeleteActions;
@@ -2529,6 +2529,7 @@ declare class PsqlEngine extends SqlEngine {
2529
2529
  private triggerClient;
2530
2530
  constructor(psqlConnectionPool: PsqlPool, shouldListenForDbTriggers?: boolean);
2531
2531
  close(): Promise<void>;
2532
+ private setupPgReturnTypes;
2532
2533
  private listenForDbTriggers;
2533
2534
  private handleTrigger;
2534
2535
  createDatabaseFromSchema(schema: ResturaSchema, connection: PsqlPool): Promise<string>;
@@ -2547,6 +2548,7 @@ declare class PsqlEngine extends SqlEngine {
2547
2548
  private createUpdateTrigger;
2548
2549
  private createDeleteTrigger;
2549
2550
  private createInsertTriggers;
2551
+ private schemaToPsqlType;
2550
2552
  }
2551
2553
 
2552
2554
  declare class PsqlTransaction extends PsqlConnection {
@@ -2564,6 +2566,12 @@ declare class PsqlTransaction extends PsqlConnection {
2564
2566
  }
2565
2567
 
2566
2568
  declare function escapeColumnName(columnName: string | undefined): string;
2569
+ /**
2570
+ * Converts a query with question marks to a query with numbered parameters,
2571
+ * however it ignores question marks inside single or double quotes.
2572
+ * @param query PostgreSQL query with question marks
2573
+ * @returns A string with numbered parameters such as $1, $2 in replacement of question marks
2574
+ */
2567
2575
  declare function questionMarksToOrderedParams(query: string): string;
2568
2576
  declare function insertObjectQuery(table: string, obj: DynamicObject): string;
2569
2577
  declare function updateObjectQuery(table: string, obj: DynamicObject, whereStatement: string): string;
package/dist/index.d.ts CHANGED
@@ -126,14 +126,14 @@ interface ActionRowInsertData<T = DynamicObject> extends DatabaseActionData {
126
126
  insertId: number;
127
127
  insertObject: T;
128
128
  }
129
- interface ActionRowDeleteData extends DatabaseActionData {
130
- deletedRow: DynamicObject;
129
+ interface ActionRowDeleteData<T = DynamicObject> extends DatabaseActionData {
130
+ deletedRow: T;
131
131
  }
132
- interface ActionColumnChangeData extends DatabaseActionData {
132
+ interface ActionColumnChangeData<T = DynamicObject> extends DatabaseActionData {
133
133
  tableName: string;
134
134
  rowId: number;
135
- newData: DynamicObject;
136
- oldData: DynamicObject;
135
+ newData: T;
136
+ oldData: T;
137
137
  }
138
138
  interface ActionRowInsertFilter {
139
139
  tableName: string;
@@ -158,9 +158,9 @@ type QueryMetadata = RequesterDetails & {
158
158
  };
159
159
  declare class EventManager {
160
160
  private actionHandlers;
161
- addRowInsertHandler(onInsert: (data: ActionRowInsertData<unknown>) => Promise<void>, filter?: ActionRowInsertFilter): void;
162
- addColumnChangeHandler(onUpdate: (data: ActionColumnChangeData) => Promise<void>, filter: ActionColumnChangeFilter): void;
163
- addRowDeleteHandler(onDelete: (data: ActionRowDeleteData) => Promise<void>, filter?: ActionRowDeleteFilter): void;
161
+ addRowInsertHandler<T>(onInsert: (data: ActionRowInsertData<T>, queryMetadata: QueryMetadata) => Promise<void>, filter?: ActionRowInsertFilter): void;
162
+ addColumnChangeHandler<T>(onUpdate: (data: ActionColumnChangeData<T>, queryMetadata: QueryMetadata) => Promise<void>, filter: ActionColumnChangeFilter): void;
163
+ addRowDeleteHandler<T>(onDelete: (data: ActionRowDeleteData<T>, queryMetadata: QueryMetadata) => Promise<void>, filter?: ActionRowDeleteFilter): void;
164
164
  fireActionFromDbTrigger(sqlMutationData: SqlMutationData, result: TriggerResult): Promise<void>;
165
165
  private fireInsertActions;
166
166
  private fireDeleteActions;
@@ -2529,6 +2529,7 @@ declare class PsqlEngine extends SqlEngine {
2529
2529
  private triggerClient;
2530
2530
  constructor(psqlConnectionPool: PsqlPool, shouldListenForDbTriggers?: boolean);
2531
2531
  close(): Promise<void>;
2532
+ private setupPgReturnTypes;
2532
2533
  private listenForDbTriggers;
2533
2534
  private handleTrigger;
2534
2535
  createDatabaseFromSchema(schema: ResturaSchema, connection: PsqlPool): Promise<string>;
@@ -2547,6 +2548,7 @@ declare class PsqlEngine extends SqlEngine {
2547
2548
  private createUpdateTrigger;
2548
2549
  private createDeleteTrigger;
2549
2550
  private createInsertTriggers;
2551
+ private schemaToPsqlType;
2550
2552
  }
2551
2553
 
2552
2554
  declare class PsqlTransaction extends PsqlConnection {
@@ -2564,6 +2566,12 @@ declare class PsqlTransaction extends PsqlConnection {
2564
2566
  }
2565
2567
 
2566
2568
  declare function escapeColumnName(columnName: string | undefined): string;
2569
+ /**
2570
+ * Converts a query with question marks to a query with numbered parameters,
2571
+ * however it ignores question marks inside single or double quotes.
2572
+ * @param query PostgreSQL query with question marks
2573
+ * @returns A string with numbered parameters such as $1, $2 in replacement of question marks
2574
+ */
2567
2575
  declare function questionMarksToOrderedParams(query: string): string;
2568
2576
  declare function insertObjectQuery(table: string, obj: DynamicObject): string;
2569
2577
  declare function updateObjectQuery(table: string, obj: DynamicObject, whereStatement: string): string;
package/dist/index.js CHANGED
@@ -315,7 +315,6 @@ var import_cookie_parser = __toESM(require("cookie-parser"));
315
315
  var express = __toESM(require("express"));
316
316
  var import_fs4 = __toESM(require("fs"));
317
317
  var import_path5 = __toESM(require("path"));
318
- var import_pg3 = __toESM(require("pg"));
319
318
  var prettier3 = __toESM(require("prettier"));
320
319
 
321
320
  // src/restura/RsError.ts
@@ -474,10 +473,10 @@ var compareSchema = new CompareSchema();
474
473
  var compareSchema_default = compareSchema;
475
474
 
476
475
  // src/restura/customApiFactory.ts
477
- var import_internal2 = require("@restura/internal");
478
476
  var import_bluebird2 = __toESM(require("bluebird"));
479
477
  var import_fs = __toESM(require("fs"));
480
478
  var import_path = __toESM(require("path"));
479
+ var import_internal2 = require("@restura/internal");
481
480
  var CustomApiFactory = class {
482
481
  constructor() {
483
482
  this.customApis = {};
@@ -486,7 +485,7 @@ var CustomApiFactory = class {
486
485
  const apiVersions = ["v1"];
487
486
  for (const apiVersion of apiVersions) {
488
487
  const apiVersionFolderPath = import_path.default.join(baseFolderPath, apiVersion);
489
- const directoryExists = await import_internal2.fileUtils.existDir(apiVersionFolderPath);
488
+ const directoryExists = await import_internal2.FileUtils.existDir(apiVersionFolderPath);
490
489
  if (!directoryExists) continue;
491
490
  await this.addDirectory(apiVersionFolderPath, apiVersion);
492
491
  }
@@ -972,7 +971,7 @@ function resturaGlobalTypesGenerator() {
972
971
  return `/** Auto generated file. DO NOT MODIFY **/
973
972
  /** This file contains types that may be used in the CustomTypes of Restura **/
974
973
  /** For example export interface MyPagedQuery extends Restura.PageQuery { } **/
975
-
974
+
976
975
  declare namespace Restura {
977
976
  export type StandardOrderTypes = 'ASC' | 'DESC' | 'RAND' | 'NONE';
978
977
  export interface PageQuery {
@@ -1329,7 +1328,7 @@ var import_core_utils3 = require("@redskytech/core-utils");
1329
1328
  var import_jsonschema = __toESM(require("jsonschema"));
1330
1329
  var import_zod4 = require("zod");
1331
1330
 
1332
- // src/restura/utils/addQuotesToStrings.ts
1331
+ // src/restura/utils/utils.ts
1333
1332
  function addQuotesToStrings(variable) {
1334
1333
  if (typeof variable === "string") {
1335
1334
  return `'${variable}'`;
@@ -1340,6 +1339,17 @@ function addQuotesToStrings(variable) {
1340
1339
  return variable;
1341
1340
  }
1342
1341
  }
1342
+ function sortObjectKeysAlphabetically(obj) {
1343
+ if (Array.isArray(obj)) {
1344
+ return obj.map(sortObjectKeysAlphabetically);
1345
+ } else if (obj !== null && typeof obj === "object") {
1346
+ return Object.keys(obj).sort().reduce((sorted, key) => {
1347
+ sorted[key] = sortObjectKeysAlphabetically(obj[key]);
1348
+ return sorted;
1349
+ }, {});
1350
+ }
1351
+ return obj;
1352
+ }
1343
1353
 
1344
1354
  // src/restura/validators/requestValidator.ts
1345
1355
  function requestValidator(req, routeData, validationSchema) {
@@ -1554,7 +1564,22 @@ function escapeColumnName(columnName) {
1554
1564
  }
1555
1565
  function questionMarksToOrderedParams(query) {
1556
1566
  let count = 1;
1557
- return query.replace(/'\?'|\?/g, () => `$${count++}`);
1567
+ let inSingleQuote = false;
1568
+ let inDoubleQuote = false;
1569
+ return query.replace(/('|"|\?)/g, (char) => {
1570
+ if (char === "'") {
1571
+ inSingleQuote = !inSingleQuote && !inDoubleQuote;
1572
+ return char;
1573
+ }
1574
+ if (char === '"') {
1575
+ inDoubleQuote = !inDoubleQuote && !inSingleQuote;
1576
+ return char;
1577
+ }
1578
+ if (char === "?" && !inSingleQuote && !inDoubleQuote) {
1579
+ return `$${count++}`;
1580
+ }
1581
+ return char;
1582
+ });
1558
1583
  }
1559
1584
  function insertObjectQuery(table, obj) {
1560
1585
  const keys = Object.keys(obj);
@@ -1884,7 +1909,7 @@ var filterPsqlParser = import_pegjs.default.generate(filterSqlGrammar, {
1884
1909
  var filterPsqlParser_default = filterPsqlParser;
1885
1910
 
1886
1911
  // src/restura/sql/PsqlEngine.ts
1887
- var { Client } = import_pg2.default;
1912
+ var { Client, types } = import_pg2.default;
1888
1913
  var systemUser = {
1889
1914
  role: "",
1890
1915
  host: "",
@@ -1895,6 +1920,7 @@ var PsqlEngine = class extends SqlEngine {
1895
1920
  constructor(psqlConnectionPool, shouldListenForDbTriggers = false) {
1896
1921
  super();
1897
1922
  this.psqlConnectionPool = psqlConnectionPool;
1923
+ this.setupPgReturnTypes();
1898
1924
  if (shouldListenForDbTriggers) {
1899
1925
  this.setupTriggerListeners = this.listenForDbTriggers();
1900
1926
  }
@@ -1904,6 +1930,16 @@ var PsqlEngine = class extends SqlEngine {
1904
1930
  await this.triggerClient.end();
1905
1931
  }
1906
1932
  }
1933
+ setupPgReturnTypes() {
1934
+ const TIMESTAMPTZ_OID = 1184;
1935
+ types.setTypeParser(TIMESTAMPTZ_OID, (val) => {
1936
+ return val === null ? null : new Date(val).toISOString();
1937
+ });
1938
+ const BIGINT_OID = 20;
1939
+ types.setTypeParser(BIGINT_OID, (val) => {
1940
+ return val === null ? null : Number(val);
1941
+ });
1942
+ }
1907
1943
  async listenForDbTriggers() {
1908
1944
  this.triggerClient = new Client({
1909
1945
  user: this.psqlConnectionPool.poolConfig.user,
@@ -1957,7 +1993,7 @@ var PsqlEngine = class extends SqlEngine {
1957
1993
  const tableColumns = [];
1958
1994
  for (const column of table.columns) {
1959
1995
  let columnSql = "";
1960
- columnSql += ` "${column.name}" ${schemaToPsqlType(column)}`;
1996
+ columnSql += ` "${column.name}" ${this.schemaToPsqlType(column)}`;
1961
1997
  let value = column.value;
1962
1998
  if (column.type === "JSON") value = "";
1963
1999
  if (column.type === "JSONB") value = "";
@@ -2426,10 +2462,14 @@ CREATE TRIGGER "${tableName}_insert"
2426
2462
  EXECUTE FUNCTION notify_${tableName}_insert();
2427
2463
  `;
2428
2464
  }
2465
+ schemaToPsqlType(column) {
2466
+ if (column.hasAutoIncrement) return "BIGSERIAL";
2467
+ if (column.type === "ENUM") return `TEXT`;
2468
+ if (column.type === "DATETIME") return "TIMESTAMPTZ";
2469
+ if (column.type === "MEDIUMINT") return "INT";
2470
+ return column.type;
2471
+ }
2429
2472
  };
2430
- __decorateClass([
2431
- boundMethod
2432
- ], PsqlEngine.prototype, "handleTrigger", 1);
2433
2473
  __decorateClass([
2434
2474
  boundMethod
2435
2475
  ], PsqlEngine.prototype, "createUpdateTrigger", 1);
@@ -2439,26 +2479,19 @@ __decorateClass([
2439
2479
  __decorateClass([
2440
2480
  boundMethod
2441
2481
  ], PsqlEngine.prototype, "createInsertTriggers", 1);
2442
- function schemaToPsqlType(column) {
2443
- if (column.hasAutoIncrement) return "BIGSERIAL";
2444
- if (column.type === "ENUM") return `TEXT`;
2445
- if (column.type === "DATETIME") return "TIMESTAMPTZ";
2446
- if (column.type === "MEDIUMINT") return "INT";
2447
- return column.type;
2448
- }
2449
2482
 
2450
2483
  // src/restura/utils/TempCache.ts
2451
2484
  var import_fs3 = __toESM(require("fs"));
2452
2485
  var import_path4 = __toESM(require("path"));
2453
2486
  var import_core_utils6 = require("@redskytech/core-utils");
2487
+ var import_internal3 = require("@restura/internal");
2454
2488
  var import_bluebird3 = __toESM(require("bluebird"));
2455
2489
  var os2 = __toESM(require("os"));
2456
- var import_internal3 = require("@restura/internal");
2457
2490
  var TempCache = class {
2458
2491
  constructor(location) {
2459
2492
  this.maxDurationDays = 7;
2460
2493
  this.location = location || os2.tmpdir();
2461
- import_internal3.fileUtils.ensureDir(this.location).catch((e) => {
2494
+ import_internal3.FileUtils.ensureDir(this.location).catch((e) => {
2462
2495
  throw e;
2463
2496
  });
2464
2497
  }
@@ -2480,7 +2513,6 @@ var TempCache = class {
2480
2513
  };
2481
2514
 
2482
2515
  // src/restura/restura.ts
2483
- var { types } = import_pg3.default;
2484
2516
  var ResturaEngine = class {
2485
2517
  constructor() {
2486
2518
  this.publicEndpoints = {
@@ -2503,7 +2535,6 @@ var ResturaEngine = class {
2503
2535
  new TempCache(this.resturaConfig.fileTempCachePath);
2504
2536
  this.psqlConnectionPool = psqlConnectionPool;
2505
2537
  this.psqlEngine = new PsqlEngine(this.psqlConnectionPool, true);
2506
- setupPgReturnTypes();
2507
2538
  await customApiFactory_default.loadApiFiles(this.resturaConfig.customApiFolderPath);
2508
2539
  this.authenticationHandler = authenticationHandler;
2509
2540
  app.use((0, import_compression.default)());
@@ -2654,7 +2685,7 @@ var ResturaEngine = class {
2654
2685
  }
2655
2686
  async updateSchema(req, res) {
2656
2687
  try {
2657
- this.schema = req.data;
2688
+ this.schema = sortObjectKeysAlphabetically(req.data);
2658
2689
  await this.storeFileSystemSchema();
2659
2690
  await this.reloadEndpoints();
2660
2691
  await this.updateTypes();
@@ -2816,22 +2847,11 @@ __decorateClass([
2816
2847
  __decorateClass([
2817
2848
  boundMethod
2818
2849
  ], ResturaEngine.prototype, "runCustomRouteLogic", 1);
2819
- function setupPgReturnTypes() {
2820
- const TIMESTAMPTZ_OID = 1184;
2821
- types.setTypeParser(TIMESTAMPTZ_OID, (val) => {
2822
- return val === null ? null : new Date(val).toISOString();
2823
- });
2824
- const BIGINT_OID = 20;
2825
- types.setTypeParser(BIGINT_OID, (val) => {
2826
- return val === null ? null : Number(val);
2827
- });
2828
- }
2829
- setupPgReturnTypes();
2830
2850
  var restura = new ResturaEngine();
2831
2851
 
2832
2852
  // src/restura/sql/PsqlTransaction.ts
2833
- var import_pg4 = __toESM(require("pg"));
2834
- var { Client: Client2 } = import_pg4.default;
2853
+ var import_pg3 = __toESM(require("pg"));
2854
+ var { Client: Client2 } = import_pg3.default;
2835
2855
  var PsqlTransaction = class extends PsqlConnection {
2836
2856
  constructor(clientConfig) {
2837
2857
  super();