@restura/core 0.1.0-alpha.34 → 0.1.0-alpha.36

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
@@ -4,6 +4,7 @@ import * as express from 'express';
4
4
  import { IncomingHttpHeaders } from 'http2';
5
5
  import { z } from 'zod';
6
6
  import { QueryResultRow, QueryConfigValues, QueryResult, PoolConfig, Pool, ClientConfig, Client } from 'pg';
7
+ import peg from 'pegjs';
7
8
 
8
9
  declare const logger: winston.Logger;
9
10
 
@@ -123,15 +124,16 @@ interface DatabaseActionData {
123
124
  queryMetadata: QueryMetadata;
124
125
  }
125
126
  interface ActionRowInsertData<T = DynamicObject> extends DatabaseActionData {
126
- insertId: number;
127
+ insertedId: number;
127
128
  insertObject: T;
128
129
  }
129
130
  interface ActionRowDeleteData<T = DynamicObject> extends DatabaseActionData {
131
+ deletedId: number;
130
132
  deletedRow: T;
131
133
  }
132
134
  interface ActionColumnChangeData<T = DynamicObject> extends DatabaseActionData {
133
135
  tableName: string;
134
- rowId: number;
136
+ changedId: number;
135
137
  newData: T;
136
138
  oldData: T;
137
139
  }
@@ -147,8 +149,10 @@ interface ActionColumnChangeFilter {
147
149
  }
148
150
  type TriggerResult = {
149
151
  table: string;
150
- insertId?: number;
151
- query: string;
152
+ insertedId?: number;
153
+ changedId?: number;
154
+ deletedId?: number;
155
+ queryMetadata: QueryMetadata;
152
156
  record: DynamicObject;
153
157
  previousRecord: DynamicObject;
154
158
  requesterId: number;
@@ -1090,6 +1094,7 @@ declare const tableDataSchema: z.ZodObject<{
1090
1094
  check: string;
1091
1095
  }>, "many">;
1092
1096
  roles: z.ZodArray<z.ZodString, "many">;
1097
+ notify: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"ALL">, z.ZodArray<z.ZodString, "many">]>>;
1093
1098
  }, "strict", z.ZodTypeAny, {
1094
1099
  name: string;
1095
1100
  roles: string[];
@@ -1125,6 +1130,7 @@ declare const tableDataSchema: z.ZodObject<{
1125
1130
  name: string;
1126
1131
  check: string;
1127
1132
  }[];
1133
+ notify?: string[] | "ALL" | undefined;
1128
1134
  }, {
1129
1135
  name: string;
1130
1136
  roles: string[];
@@ -1160,6 +1166,7 @@ declare const tableDataSchema: z.ZodObject<{
1160
1166
  name: string;
1161
1167
  check: string;
1162
1168
  }[];
1169
+ notify?: string[] | "ALL" | undefined;
1163
1170
  }>;
1164
1171
  type TableData = z.infer<typeof tableDataSchema>;
1165
1172
  declare const resturaSchema: z.ZodObject<{
@@ -1254,6 +1261,7 @@ declare const resturaSchema: z.ZodObject<{
1254
1261
  check: string;
1255
1262
  }>, "many">;
1256
1263
  roles: z.ZodArray<z.ZodString, "many">;
1264
+ notify: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"ALL">, z.ZodArray<z.ZodString, "many">]>>;
1257
1265
  }, "strict", z.ZodTypeAny, {
1258
1266
  name: string;
1259
1267
  roles: string[];
@@ -1289,6 +1297,7 @@ declare const resturaSchema: z.ZodObject<{
1289
1297
  name: string;
1290
1298
  check: string;
1291
1299
  }[];
1300
+ notify?: string[] | "ALL" | undefined;
1292
1301
  }, {
1293
1302
  name: string;
1294
1303
  roles: string[];
@@ -1324,6 +1333,7 @@ declare const resturaSchema: z.ZodObject<{
1324
1333
  name: string;
1325
1334
  check: string;
1326
1335
  }[];
1336
+ notify?: string[] | "ALL" | undefined;
1327
1337
  }>, "many">;
1328
1338
  endpoints: z.ZodArray<z.ZodObject<{
1329
1339
  name: z.ZodString;
@@ -2142,6 +2152,7 @@ declare const resturaSchema: z.ZodObject<{
2142
2152
  name: string;
2143
2153
  check: string;
2144
2154
  }[];
2155
+ notify?: string[] | "ALL" | undefined;
2145
2156
  }[];
2146
2157
  endpoints: {
2147
2158
  name: string;
@@ -2289,6 +2300,7 @@ declare const resturaSchema: z.ZodObject<{
2289
2300
  name: string;
2290
2301
  check: string;
2291
2302
  }[];
2303
+ notify?: string[] | "ALL" | undefined;
2292
2304
  }[];
2293
2305
  endpoints: {
2294
2306
  name: string;
@@ -2502,6 +2514,8 @@ declare class ResturaEngine {
2502
2514
  }
2503
2515
  declare const restura: ResturaEngine;
2504
2516
 
2517
+ declare const filterPsqlParser: peg.Parser;
2518
+
2505
2519
  declare abstract class SqlEngine {
2506
2520
  runQueryForRoute(req: RsRequest<unknown>, routeData: StandardRouteData, schema: ResturaSchema): Promise<DynamicObject | any[] | boolean>;
2507
2521
  protected getTableSchema(schema: ResturaSchema, tableName: string): TableData;
@@ -2608,4 +2622,4 @@ declare function isValueNumber(value: unknown): value is number;
2608
2622
  */
2609
2623
  declare function SQL(strings: TemplateStringsArray, ...values: unknown[]): string;
2610
2624
 
2611
- export { type ActionColumnChangeData, type ActionColumnChangeFilter, type ActionRowDeleteData, type ActionRowDeleteFilter, type ActionRowInsertData, type ActionRowInsertFilter, type ApiMethod, type AsyncExpressApplication, type AuthenticateHandler, type AuthenticationUserDetails, type ConjunctionTypes, type DatabaseActionData, type DynamicObject, type ErrorCode, type EventType, HtmlStatusCodes, type MatchTypes, type MutationType, type PageQuery, PsqlConnection, PsqlEngine, PsqlPool, PsqlTransaction, type QueryMetadata, type RequesterDetails, RsError, type RsErrorData, type RsErrorInternalData, type RsHeaders, type RsPagedResponseData, type RsRequest, type RsResponse, type RsResponseData, type RsRouteHandler, SQL, type SchemaChangeValue, type SchemaPreview, type SqlMutationData, type StandardOrderTypes, type TriggerResult, type ValidAuthenticationCallback, escapeColumnName, eventManager, insertObjectQuery, isValueNumber, logger, questionMarksToOrderedParams, restura, updateObjectQuery };
2625
+ export { type ActionColumnChangeData, type ActionColumnChangeFilter, type ActionRowDeleteData, type ActionRowDeleteFilter, type ActionRowInsertData, type ActionRowInsertFilter, type ApiMethod, type AsyncExpressApplication, type AuthenticateHandler, type AuthenticationUserDetails, type ConjunctionTypes, type DatabaseActionData, type DynamicObject, type ErrorCode, type EventType, HtmlStatusCodes, type MatchTypes, type MutationType, type PageQuery, PsqlConnection, PsqlEngine, PsqlPool, PsqlTransaction, type QueryMetadata, type RequesterDetails, RsError, type RsErrorData, type RsErrorInternalData, type RsHeaders, type RsPagedResponseData, type RsRequest, type RsResponse, type RsResponseData, type RsRouteHandler, SQL, type SchemaChangeValue, type SchemaPreview, type SqlMutationData, type StandardOrderTypes, type TriggerResult, type ValidAuthenticationCallback, escapeColumnName, eventManager, filterPsqlParser, insertObjectQuery, isValueNumber, logger, questionMarksToOrderedParams, restura, updateObjectQuery };
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import * as express from 'express';
4
4
  import { IncomingHttpHeaders } from 'http2';
5
5
  import { z } from 'zod';
6
6
  import { QueryResultRow, QueryConfigValues, QueryResult, PoolConfig, Pool, ClientConfig, Client } from 'pg';
7
+ import peg from 'pegjs';
7
8
 
8
9
  declare const logger: winston.Logger;
9
10
 
@@ -123,15 +124,16 @@ interface DatabaseActionData {
123
124
  queryMetadata: QueryMetadata;
124
125
  }
125
126
  interface ActionRowInsertData<T = DynamicObject> extends DatabaseActionData {
126
- insertId: number;
127
+ insertedId: number;
127
128
  insertObject: T;
128
129
  }
129
130
  interface ActionRowDeleteData<T = DynamicObject> extends DatabaseActionData {
131
+ deletedId: number;
130
132
  deletedRow: T;
131
133
  }
132
134
  interface ActionColumnChangeData<T = DynamicObject> extends DatabaseActionData {
133
135
  tableName: string;
134
- rowId: number;
136
+ changedId: number;
135
137
  newData: T;
136
138
  oldData: T;
137
139
  }
@@ -147,8 +149,10 @@ interface ActionColumnChangeFilter {
147
149
  }
148
150
  type TriggerResult = {
149
151
  table: string;
150
- insertId?: number;
151
- query: string;
152
+ insertedId?: number;
153
+ changedId?: number;
154
+ deletedId?: number;
155
+ queryMetadata: QueryMetadata;
152
156
  record: DynamicObject;
153
157
  previousRecord: DynamicObject;
154
158
  requesterId: number;
@@ -1090,6 +1094,7 @@ declare const tableDataSchema: z.ZodObject<{
1090
1094
  check: string;
1091
1095
  }>, "many">;
1092
1096
  roles: z.ZodArray<z.ZodString, "many">;
1097
+ notify: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"ALL">, z.ZodArray<z.ZodString, "many">]>>;
1093
1098
  }, "strict", z.ZodTypeAny, {
1094
1099
  name: string;
1095
1100
  roles: string[];
@@ -1125,6 +1130,7 @@ declare const tableDataSchema: z.ZodObject<{
1125
1130
  name: string;
1126
1131
  check: string;
1127
1132
  }[];
1133
+ notify?: string[] | "ALL" | undefined;
1128
1134
  }, {
1129
1135
  name: string;
1130
1136
  roles: string[];
@@ -1160,6 +1166,7 @@ declare const tableDataSchema: z.ZodObject<{
1160
1166
  name: string;
1161
1167
  check: string;
1162
1168
  }[];
1169
+ notify?: string[] | "ALL" | undefined;
1163
1170
  }>;
1164
1171
  type TableData = z.infer<typeof tableDataSchema>;
1165
1172
  declare const resturaSchema: z.ZodObject<{
@@ -1254,6 +1261,7 @@ declare const resturaSchema: z.ZodObject<{
1254
1261
  check: string;
1255
1262
  }>, "many">;
1256
1263
  roles: z.ZodArray<z.ZodString, "many">;
1264
+ notify: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"ALL">, z.ZodArray<z.ZodString, "many">]>>;
1257
1265
  }, "strict", z.ZodTypeAny, {
1258
1266
  name: string;
1259
1267
  roles: string[];
@@ -1289,6 +1297,7 @@ declare const resturaSchema: z.ZodObject<{
1289
1297
  name: string;
1290
1298
  check: string;
1291
1299
  }[];
1300
+ notify?: string[] | "ALL" | undefined;
1292
1301
  }, {
1293
1302
  name: string;
1294
1303
  roles: string[];
@@ -1324,6 +1333,7 @@ declare const resturaSchema: z.ZodObject<{
1324
1333
  name: string;
1325
1334
  check: string;
1326
1335
  }[];
1336
+ notify?: string[] | "ALL" | undefined;
1327
1337
  }>, "many">;
1328
1338
  endpoints: z.ZodArray<z.ZodObject<{
1329
1339
  name: z.ZodString;
@@ -2142,6 +2152,7 @@ declare const resturaSchema: z.ZodObject<{
2142
2152
  name: string;
2143
2153
  check: string;
2144
2154
  }[];
2155
+ notify?: string[] | "ALL" | undefined;
2145
2156
  }[];
2146
2157
  endpoints: {
2147
2158
  name: string;
@@ -2289,6 +2300,7 @@ declare const resturaSchema: z.ZodObject<{
2289
2300
  name: string;
2290
2301
  check: string;
2291
2302
  }[];
2303
+ notify?: string[] | "ALL" | undefined;
2292
2304
  }[];
2293
2305
  endpoints: {
2294
2306
  name: string;
@@ -2502,6 +2514,8 @@ declare class ResturaEngine {
2502
2514
  }
2503
2515
  declare const restura: ResturaEngine;
2504
2516
 
2517
+ declare const filterPsqlParser: peg.Parser;
2518
+
2505
2519
  declare abstract class SqlEngine {
2506
2520
  runQueryForRoute(req: RsRequest<unknown>, routeData: StandardRouteData, schema: ResturaSchema): Promise<DynamicObject | any[] | boolean>;
2507
2521
  protected getTableSchema(schema: ResturaSchema, tableName: string): TableData;
@@ -2608,4 +2622,4 @@ declare function isValueNumber(value: unknown): value is number;
2608
2622
  */
2609
2623
  declare function SQL(strings: TemplateStringsArray, ...values: unknown[]): string;
2610
2624
 
2611
- export { type ActionColumnChangeData, type ActionColumnChangeFilter, type ActionRowDeleteData, type ActionRowDeleteFilter, type ActionRowInsertData, type ActionRowInsertFilter, type ApiMethod, type AsyncExpressApplication, type AuthenticateHandler, type AuthenticationUserDetails, type ConjunctionTypes, type DatabaseActionData, type DynamicObject, type ErrorCode, type EventType, HtmlStatusCodes, type MatchTypes, type MutationType, type PageQuery, PsqlConnection, PsqlEngine, PsqlPool, PsqlTransaction, type QueryMetadata, type RequesterDetails, RsError, type RsErrorData, type RsErrorInternalData, type RsHeaders, type RsPagedResponseData, type RsRequest, type RsResponse, type RsResponseData, type RsRouteHandler, SQL, type SchemaChangeValue, type SchemaPreview, type SqlMutationData, type StandardOrderTypes, type TriggerResult, type ValidAuthenticationCallback, escapeColumnName, eventManager, insertObjectQuery, isValueNumber, logger, questionMarksToOrderedParams, restura, updateObjectQuery };
2625
+ export { type ActionColumnChangeData, type ActionColumnChangeFilter, type ActionRowDeleteData, type ActionRowDeleteFilter, type ActionRowInsertData, type ActionRowInsertFilter, type ApiMethod, type AsyncExpressApplication, type AuthenticateHandler, type AuthenticationUserDetails, type ConjunctionTypes, type DatabaseActionData, type DynamicObject, type ErrorCode, type EventType, HtmlStatusCodes, type MatchTypes, type MutationType, type PageQuery, PsqlConnection, PsqlEngine, PsqlPool, PsqlTransaction, type QueryMetadata, type RequesterDetails, RsError, type RsErrorData, type RsErrorInternalData, type RsHeaders, type RsPagedResponseData, type RsRequest, type RsResponse, type RsResponseData, type RsRouteHandler, SQL, type SchemaChangeValue, type SchemaPreview, type SqlMutationData, type StandardOrderTypes, type TriggerResult, type ValidAuthenticationCallback, escapeColumnName, eventManager, filterPsqlParser, insertObjectQuery, isValueNumber, logger, questionMarksToOrderedParams, restura, updateObjectQuery };
package/dist/index.js CHANGED
@@ -76,6 +76,7 @@ __export(src_exports, {
76
76
  SQL: () => SQL,
77
77
  escapeColumnName: () => escapeColumnName,
78
78
  eventManager: () => eventManager_default,
79
+ filterPsqlParser: () => filterPsqlParser_default,
79
80
  insertObjectQuery: () => insertObjectQuery,
80
81
  isValueNumber: () => isValueNumber2,
81
82
  logger: () => logger,
@@ -175,7 +176,7 @@ var EventManager = class {
175
176
  if (!this.hasHandlersForEventType("DATABASE_ROW_INSERT", filter, triggerResult)) return;
176
177
  const insertData = {
177
178
  tableName: triggerResult.table,
178
- insertId: triggerResult.record.id,
179
+ insertedId: triggerResult.insertedId || 0,
179
180
  insertObject: triggerResult.record,
180
181
  queryMetadata: data.queryMetadata
181
182
  };
@@ -191,6 +192,7 @@ var EventManager = class {
191
192
  if (!this.hasHandlersForEventType("DATABASE_ROW_DELETE", filter, triggerResult)) return;
192
193
  const deleteData = {
193
194
  tableName: triggerResult.table,
195
+ deletedId: triggerResult.deletedId || 0,
194
196
  deletedRow: triggerResult.previousRecord,
195
197
  queryMetadata: data.queryMetadata
196
198
  };
@@ -206,7 +208,7 @@ var EventManager = class {
206
208
  if (!this.hasHandlersForEventType("DATABASE_COLUMN_UPDATE", filter, triggerResult)) return;
207
209
  const columnChangeData = {
208
210
  tableName: triggerResult.table,
209
- rowId: triggerResult.record.id,
211
+ changedId: triggerResult.changedId || 0,
210
212
  newData: triggerResult.record,
211
213
  oldData: triggerResult.previousRecord,
212
214
  queryMetadata: data.queryMetadata
@@ -550,7 +552,7 @@ var SqlUtils = class _SqlUtils {
550
552
  static convertDatabaseTypeToTypescript(type, value) {
551
553
  type = type.toLocaleLowerCase();
552
554
  if (type.startsWith("tinyint") || type.startsWith("boolean")) return "boolean";
553
- if (type.indexOf("int") > -1 || type.startsWith("decimal") || type.startsWith("double") || type.startsWith("float"))
555
+ if (type.indexOf("int") > -1 || type.startsWith("decimal") || type.startsWith("double") || type.startsWith("float") || type.indexOf("serial") > -1 || type.startsWith("decimal") || type.startsWith("real") || type.startsWith("double precision") || type.startsWith("numeric"))
554
556
  return "number";
555
557
  if (type === "json") {
556
558
  if (!value) return "object";
@@ -832,21 +834,28 @@ var ApiTree = class _ApiTree {
832
834
  return `export type Res = CustomTypes.${route.responseType}[]`;
833
835
  else return `export type Res = CustomTypes.${route.responseType}`;
834
836
  }
835
- return `export interface Res ${this.getFields(route.response)}`;
837
+ return `export interface Res ${this.getFields(route.response, route.table, route.joins)}`;
836
838
  }
837
- getFields(fields) {
838
- const nameFields = fields.map((f) => this.getNameAndType(f));
839
+ getFields(fields, routeBaseTable, joins) {
840
+ const nameFields = fields.map((f) => this.getNameAndType(f, routeBaseTable, joins));
839
841
  const nested = `{
840
842
  ${nameFields.join(";\n ")}${import_core_utils.ObjectUtils.isArrayWithData(nameFields) ? ";" : ""}
841
843
  }`;
842
844
  return nested;
843
845
  }
844
- getNameAndType(p) {
846
+ getNameAndType(p, routeBaseTable, joins) {
845
847
  let responseType = "any", isNullable = false, array = false;
846
848
  if (p.selector) {
847
849
  ({ responseType, isNullable } = this.getTypeFromTable(p.selector, p.name));
850
+ const selectorKey = p.selector.split(".")[0];
851
+ if (selectorKey !== routeBaseTable) {
852
+ const join = joins.find((j) => j.alias === selectorKey);
853
+ if (join && join.type !== "INNER") {
854
+ isNullable = true;
855
+ }
856
+ }
848
857
  } else if (p.subquery) {
849
- responseType = this.getFields(p.subquery.properties);
858
+ responseType = this.getFields(p.subquery.properties, p.subquery.table, p.subquery.joins);
850
859
  array = true;
851
860
  }
852
861
  return `${p.name}:${responseType}${array ? "[]" : ""}${isNullable ? " | null" : ""}`;
@@ -1312,7 +1321,8 @@ var tableDataSchema = import_zod3.z.object({
1312
1321
  indexes: import_zod3.z.array(indexDataSchema),
1313
1322
  foreignKeys: import_zod3.z.array(foreignKeyDataSchema),
1314
1323
  checkConstraints: import_zod3.z.array(checkConstraintDataSchema),
1315
- roles: import_zod3.z.array(import_zod3.z.string())
1324
+ roles: import_zod3.z.array(import_zod3.z.string()),
1325
+ notify: import_zod3.z.union([import_zod3.z.literal("ALL"), import_zod3.z.array(import_zod3.z.string())]).optional()
1316
1326
  }).strict();
1317
1327
  var endpointDataSchema = import_zod3.z.object({
1318
1328
  name: import_zod3.z.string(),
@@ -1985,16 +1995,8 @@ var PsqlEngine = class extends SqlEngine {
1985
1995
  });
1986
1996
  }
1987
1997
  async handleTrigger(payload, mutationType) {
1988
- const findRequesterDetailsRegex = /^--QUERY_METADATA\(\{.*\}\)/;
1989
- const match = payload.query.match(findRequesterDetailsRegex);
1990
- if (match) {
1991
- const jsonString = match[0].slice(match[0].indexOf("{"), match[0].lastIndexOf("}") + 1);
1992
- const queryMetadata = import_core_utils5.ObjectUtils.safeParse(jsonString);
1993
- const triggerFromThisInstance = queryMetadata.connectionInstanceId === this.psqlConnectionPool.instanceId;
1994
- if (!triggerFromThisInstance) {
1995
- return;
1996
- }
1997
- await eventManager_default.fireActionFromDbTrigger({ queryMetadata, mutationType }, payload);
1998
+ if (payload.queryMetadata && payload.queryMetadata.connectionInstanceId === this.psqlConnectionPool.instanceId) {
1999
+ await eventManager_default.fireActionFromDbTrigger({ queryMetadata: payload.queryMetadata, mutationType }, payload);
1998
2000
  }
1999
2001
  }
2000
2002
  async createDatabaseFromSchema(schema, connection) {
@@ -2007,9 +2009,11 @@ var PsqlEngine = class extends SqlEngine {
2007
2009
  const indexes = [];
2008
2010
  const triggers = [];
2009
2011
  for (const table of schema.database) {
2010
- triggers.push(this.createInsertTriggers(table.name));
2011
- triggers.push(this.createUpdateTrigger(table.name));
2012
- triggers.push(this.createDeleteTrigger(table.name));
2012
+ if (table.notify) {
2013
+ triggers.push(this.createInsertTriggers(table.name, table.notify));
2014
+ triggers.push(this.createUpdateTrigger(table.name, table.notify));
2015
+ triggers.push(this.createDeleteTrigger(table.name, table.notify));
2016
+ }
2013
2017
  let sql = `CREATE TABLE "${table.name}"
2014
2018
  ( `;
2015
2019
  const tableColumns = [];
@@ -2436,53 +2440,216 @@ DELETE FROM "${routeData.table}" ${joinStatement} ${whereClause}`;
2436
2440
  }
2437
2441
  return whereClause;
2438
2442
  }
2439
- createUpdateTrigger(tableName) {
2440
- return `
2443
+ createUpdateTrigger(tableName, notify) {
2444
+ if (!notify) return "";
2445
+ if (notify === "ALL") {
2446
+ return `
2441
2447
  CREATE OR REPLACE FUNCTION notify_${tableName}_update()
2442
- RETURNS TRIGGER AS $$
2448
+ RETURNS TRIGGER AS $$
2449
+ DECLARE
2450
+ query_metadata JSON;
2443
2451
  BEGIN
2444
- PERFORM pg_notify('update', JSON_BUILD_OBJECT('table', '${tableName}', 'query', current_query(), 'record', NEW, 'previousRecord', OLD)::text);
2445
- RETURN NEW;
2452
+ SELECT INTO query_metadata
2453
+ (regexp_match(
2454
+ current_query(),
2455
+ '^--QUERY_METADATA\\(({.*})', 'n'
2456
+ ))[1]::json;
2457
+
2458
+ PERFORM pg_notify(
2459
+ 'update',
2460
+ json_build_object(
2461
+ 'table', '${tableName}',
2462
+ 'queryMetadata', query_metadata,
2463
+ 'changedId', NEW.id,
2464
+ 'record', NEW,
2465
+ 'previousRecord', OLD
2466
+ )::text
2467
+ );
2468
+ RETURN NEW;
2446
2469
  END;
2447
2470
  $$ LANGUAGE plpgsql;
2448
2471
 
2449
2472
  CREATE OR REPLACE TRIGGER ${tableName}_update
2450
- AFTER UPDATE ON "${tableName}"
2451
- FOR EACH ROW
2473
+ AFTER UPDATE ON "${tableName}"
2474
+ FOR EACH ROW
2475
+ EXECUTE FUNCTION notify_${tableName}_update();
2476
+ `;
2477
+ }
2478
+ const notifyColumnNewBuildString = notify.map((column) => `'${column}', NEW."${column}"`).join(",\n");
2479
+ const notifyColumnOldBuildString = notify.map((column) => `'${column}', OLD."${column}"`).join(",\n");
2480
+ return `
2481
+ CREATE OR REPLACE FUNCTION notify_${tableName}_update()
2482
+ RETURNS TRIGGER AS $$
2483
+ DECLARE
2484
+ query_metadata JSON;
2485
+ BEGIN
2486
+ SELECT INTO query_metadata
2487
+ (regexp_match(
2488
+ current_query(),
2489
+ '^--QUERY_METADATA\\(({.*})', 'n'
2490
+ ))[1]::json;
2491
+
2492
+ PERFORM pg_notify(
2493
+ 'update',
2494
+ json_build_object(
2495
+ 'table', '${tableName}',
2496
+ 'queryMetadata', query_metadata,
2497
+ 'changedId', NEW.id,
2498
+ 'record', json_build_object(
2499
+ ${notifyColumnNewBuildString}
2500
+ ),
2501
+ 'previousRecord', json_build_object(
2502
+ ${notifyColumnOldBuildString}
2503
+ )
2504
+ )::text
2505
+ );
2506
+ RETURN NEW;
2507
+ END;
2508
+ $$ LANGUAGE plpgsql;
2509
+
2510
+ CREATE OR REPLACE TRIGGER ${tableName}_update
2511
+ AFTER UPDATE ON "${tableName}"
2512
+ FOR EACH ROW
2452
2513
  EXECUTE FUNCTION notify_${tableName}_update();
2453
2514
  `;
2454
2515
  }
2455
- createDeleteTrigger(tableName) {
2516
+ createDeleteTrigger(tableName, notify) {
2517
+ if (!notify) return "";
2518
+ if (notify === "ALL") {
2519
+ return `
2520
+ CREATE OR REPLACE FUNCTION notify_${tableName}_delete()
2521
+ RETURNS TRIGGER AS $$
2522
+ DECLARE
2523
+ query_metadata JSON;
2524
+ BEGIN
2525
+ SELECT INTO query_metadata
2526
+ (regexp_match(
2527
+ current_query(),
2528
+ '^--QUERY_METADATA\\(({.*})', 'n'
2529
+ ))[1]::json;
2530
+
2531
+ PERFORM pg_notify(
2532
+ 'delete',
2533
+ json_build_object(
2534
+ 'table', '${tableName}',
2535
+ 'queryMetadata', query_metadata,
2536
+ 'deletedId', OLD.id,
2537
+ 'previousRecord', OLD
2538
+ )::text
2539
+ );
2540
+ RETURN NEW;
2541
+ END;
2542
+ $$ LANGUAGE plpgsql;
2543
+
2544
+ CREATE OR REPLACE TRIGGER "${tableName}_delete"
2545
+ AFTER DELETE ON "${tableName}"
2546
+ FOR EACH ROW
2547
+ EXECUTE FUNCTION notify_${tableName}_delete();
2548
+ `;
2549
+ }
2550
+ const notifyColumnOldBuildString = notify.map((column) => `'${column}', OLD."${column}"`).join(",\n");
2456
2551
  return `
2457
2552
  CREATE OR REPLACE FUNCTION notify_${tableName}_delete()
2458
- RETURNS TRIGGER AS $$
2553
+ RETURNS TRIGGER AS $$
2554
+ DECLARE
2555
+ query_metadata JSON;
2459
2556
  BEGIN
2460
- PERFORM pg_notify('delete', JSON_BUILD_OBJECT('table', '${tableName}', 'query', current_query(), 'record', NEW, 'previousRecord', OLD)::text);
2461
- RETURN NEW;
2557
+ SELECT INTO query_metadata
2558
+ (regexp_match(
2559
+ current_query(),
2560
+ '^--QUERY_METADATA\\(({.*})', 'n'
2561
+ ))[1]::json;
2562
+
2563
+ PERFORM pg_notify(
2564
+ 'delete',
2565
+ json_build_object(
2566
+ 'table', '${tableName}',
2567
+ 'queryMetadata', query_metadata,
2568
+ 'deletedId', OLD.id,
2569
+ 'previousRecord', json_build_object(
2570
+ ${notifyColumnOldBuildString}
2571
+ )
2572
+ )::text
2573
+ );
2574
+ RETURN NEW;
2462
2575
  END;
2463
2576
  $$ LANGUAGE plpgsql;
2464
2577
 
2465
2578
  CREATE OR REPLACE TRIGGER "${tableName}_delete"
2466
- AFTER DELETE ON "${tableName}"
2467
- FOR EACH ROW
2579
+ AFTER DELETE ON "${tableName}"
2580
+ FOR EACH ROW
2468
2581
  EXECUTE FUNCTION notify_${tableName}_delete();
2469
2582
  `;
2470
2583
  }
2471
- createInsertTriggers(tableName) {
2584
+ createInsertTriggers(tableName, notify) {
2585
+ if (!notify) return "";
2586
+ if (notify === "ALL") {
2587
+ return `
2588
+ CREATE OR REPLACE FUNCTION notify_${tableName}_insert()
2589
+ RETURNS TRIGGER AS $$
2590
+ DECLARE
2591
+ query_metadata JSON;
2592
+ BEGIN
2593
+ SELECT INTO query_metadata
2594
+ (regexp_match(
2595
+ current_query(),
2596
+ '^--QUERY_METADATA\\(({.*})', 'n'
2597
+ ))[1]::json;
2598
+
2599
+ PERFORM pg_notify(
2600
+ 'insert',
2601
+ json_build_object(
2602
+ 'table', '${tableName}',
2603
+ 'queryMetadata', query_metadata,
2604
+ 'insertedId', NEW.id,
2605
+ 'record', NEW
2606
+ )::text
2607
+ );
2608
+
2609
+ RETURN NEW;
2610
+ END;
2611
+ $$ LANGUAGE plpgsql;
2612
+
2613
+ CREATE OR REPLACE TRIGGER "${tableName}_insert"
2614
+ AFTER INSERT ON "${tableName}"
2615
+ FOR EACH ROW
2616
+ EXECUTE FUNCTION notify_${tableName}_insert();
2617
+ `;
2618
+ }
2619
+ const notifyColumnNewBuildString = notify.map((column) => `'${column}', NEW."${column}"`).join(",\n");
2472
2620
  return `
2473
2621
  CREATE OR REPLACE FUNCTION notify_${tableName}_insert()
2474
- RETURNS TRIGGER AS $$
2622
+ RETURNS TRIGGER AS $$
2623
+ DECLARE
2624
+ query_metadata JSON;
2475
2625
  BEGIN
2476
- PERFORM pg_notify('insert', JSON_BUILD_OBJECT('table', '${tableName}', 'query', current_query(), 'record', NEW, 'previousRecord', OLD)::text);
2477
- RETURN NEW;
2626
+ SELECT INTO query_metadata
2627
+ (regexp_match(
2628
+ current_query(),
2629
+ '^--QUERY_METADATA\\(({.*})', 'n'
2630
+ ))[1]::json;
2631
+
2632
+ PERFORM pg_notify(
2633
+ 'insert',
2634
+ json_build_object(
2635
+ 'table', '${tableName}',
2636
+ 'queryMetadata', query_metadata,
2637
+ 'insertedId', NEW.id,
2638
+ 'record', json_build_object(
2639
+ ${notifyColumnNewBuildString}
2640
+ )
2641
+ )::text
2642
+ );
2643
+
2644
+ RETURN NEW;
2478
2645
  END;
2479
2646
  $$ LANGUAGE plpgsql;
2480
2647
 
2481
- CREATE TRIGGER "${tableName}_insert"
2482
- AFTER INSERT ON "${tableName}"
2483
- FOR EACH ROW
2648
+ CREATE OR REPLACE TRIGGER "${tableName}_insert"
2649
+ AFTER INSERT ON "${tableName}"
2650
+ FOR EACH ROW
2484
2651
  EXECUTE FUNCTION notify_${tableName}_insert();
2485
- `;
2652
+ `;
2486
2653
  }
2487
2654
  schemaToPsqlType(column) {
2488
2655
  if (column.hasAutoIncrement) return "BIGSERIAL";
@@ -2492,15 +2659,6 @@ EXECUTE FUNCTION notify_${tableName}_insert();
2492
2659
  return column.type;
2493
2660
  }
2494
2661
  };
2495
- __decorateClass([
2496
- boundMethod
2497
- ], PsqlEngine.prototype, "createUpdateTrigger", 1);
2498
- __decorateClass([
2499
- boundMethod
2500
- ], PsqlEngine.prototype, "createDeleteTrigger", 1);
2501
- __decorateClass([
2502
- boundMethod
2503
- ], PsqlEngine.prototype, "createInsertTriggers", 1);
2504
2662
 
2505
2663
  // src/restura/utils/TempCache.ts
2506
2664
  var import_fs3 = __toESM(require("fs"));
@@ -2917,6 +3075,7 @@ var PsqlTransaction = class extends PsqlConnection {
2917
3075
  SQL,
2918
3076
  escapeColumnName,
2919
3077
  eventManager,
3078
+ filterPsqlParser,
2920
3079
  insertObjectQuery,
2921
3080
  isValueNumber,
2922
3081
  logger,