@restura/core 0.1.0-alpha.15 → 0.1.0-alpha.17
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 +69 -16
- package/dist/index.d.ts +69 -16
- package/dist/index.js +268 -50
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +267 -50
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/dist/index.d.mts
CHANGED
|
@@ -1392,10 +1392,10 @@ interface AsyncExpressApplication {
|
|
|
1392
1392
|
}
|
|
1393
1393
|
|
|
1394
1394
|
declare abstract class PsqlConnection {
|
|
1395
|
-
constructor();
|
|
1395
|
+
protected constructor();
|
|
1396
1396
|
protected abstract query<R extends QueryResultRow = QueryResultRow, T extends Array<unknown> = unknown[]>(query: string, values?: QueryConfigValues<T>): Promise<QueryResult<R>>;
|
|
1397
|
-
queryOne(query: string, options: any[], requesterDetails: RequesterDetails): Promise<
|
|
1398
|
-
runQuery(query: string, options: any[], requesterDetails: RequesterDetails): Promise<
|
|
1397
|
+
queryOne<T>(query: string, options: any[], requesterDetails: RequesterDetails): Promise<T>;
|
|
1398
|
+
runQuery<T>(query: string, options: any[], requesterDetails: RequesterDetails): Promise<T[]>;
|
|
1399
1399
|
private logSqlStatement;
|
|
1400
1400
|
}
|
|
1401
1401
|
|
|
@@ -1406,18 +1406,6 @@ declare class PsqlPool extends PsqlConnection {
|
|
|
1406
1406
|
protected query<R extends QueryResultRow = QueryResultRow, T extends Array<unknown> = unknown[]>(query: string, values?: QueryConfigValues<T>): Promise<QueryResult<R>>;
|
|
1407
1407
|
}
|
|
1408
1408
|
|
|
1409
|
-
declare class PsqlTransaction extends PsqlConnection {
|
|
1410
|
-
clientConfig: ClientConfig;
|
|
1411
|
-
client: Client;
|
|
1412
|
-
private beginTransactionPromise;
|
|
1413
|
-
constructor(clientConfig: ClientConfig);
|
|
1414
|
-
private beginTransaction;
|
|
1415
|
-
rollback(): Promise<QueryResult<QueryResultRow>>;
|
|
1416
|
-
commit(): Promise<QueryResult<QueryResultRow>>;
|
|
1417
|
-
release(): Promise<void>;
|
|
1418
|
-
protected query<R extends QueryResultRow = QueryResultRow, T extends Array<unknown> = unknown[]>(query: string, values?: QueryConfigValues<T>): Promise<QueryResult<R>>;
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
1409
|
declare class ResturaEngine {
|
|
1422
1410
|
resturaConfig: ResturaConfigSchema;
|
|
1423
1411
|
private resturaRouter;
|
|
@@ -1516,4 +1504,69 @@ declare function updateObjectQuery(table: string, obj: DynamicObject, whereState
|
|
|
1516
1504
|
declare function isValueNumber(value: unknown): value is number;
|
|
1517
1505
|
declare function SQL(strings: any, ...values: any): any;
|
|
1518
1506
|
|
|
1519
|
-
|
|
1507
|
+
declare class PsqlTransaction extends PsqlConnection {
|
|
1508
|
+
clientConfig: ClientConfig;
|
|
1509
|
+
client: Client;
|
|
1510
|
+
private beginTransactionPromise;
|
|
1511
|
+
constructor(clientConfig: ClientConfig);
|
|
1512
|
+
private beginTransaction;
|
|
1513
|
+
rollback(): Promise<QueryResult<QueryResultRow>>;
|
|
1514
|
+
commit(): Promise<QueryResult<QueryResultRow>>;
|
|
1515
|
+
release(): Promise<void>;
|
|
1516
|
+
protected query<R extends QueryResultRow = QueryResultRow, T extends Array<unknown> = unknown[]>(query: string, values?: QueryConfigValues<T>): Promise<QueryResult<R>>;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
type EventType = 'DATABASE_ROW_DELETE' | 'DATABASE_ROW_INSERT' | 'DATABASE_COLUMN_UPDATE' | 'WEBHOOK';
|
|
1520
|
+
type MutationType = 'INSERT' | 'UPDATE' | 'DELETE';
|
|
1521
|
+
interface SqlMutationData {
|
|
1522
|
+
mutationType: MutationType;
|
|
1523
|
+
requesterDetails: RequesterDetails;
|
|
1524
|
+
}
|
|
1525
|
+
interface DatabaseActionData {
|
|
1526
|
+
tableName: string;
|
|
1527
|
+
requesterDetails: RequesterDetails;
|
|
1528
|
+
}
|
|
1529
|
+
interface ActionRowInsertData<T = DynamicObject> extends DatabaseActionData {
|
|
1530
|
+
insertId: number;
|
|
1531
|
+
insertObject: T;
|
|
1532
|
+
}
|
|
1533
|
+
interface ActionRowDeleteData extends DatabaseActionData {
|
|
1534
|
+
deletedRow: DynamicObject;
|
|
1535
|
+
}
|
|
1536
|
+
interface ActionColumnChangeData extends DatabaseActionData {
|
|
1537
|
+
tableName: string;
|
|
1538
|
+
rowId: number;
|
|
1539
|
+
newData: DynamicObject;
|
|
1540
|
+
oldData: DynamicObject;
|
|
1541
|
+
}
|
|
1542
|
+
interface ActionRowInsertFilter {
|
|
1543
|
+
tableName: string;
|
|
1544
|
+
}
|
|
1545
|
+
interface ActionRowDeleteFilter {
|
|
1546
|
+
tableName: string;
|
|
1547
|
+
}
|
|
1548
|
+
interface ActionColumnChangeFilter {
|
|
1549
|
+
tableName: string;
|
|
1550
|
+
}
|
|
1551
|
+
type TriggerResult = {
|
|
1552
|
+
table: string;
|
|
1553
|
+
insertId?: number;
|
|
1554
|
+
query: string;
|
|
1555
|
+
record: DynamicObject;
|
|
1556
|
+
previousRecord: DynamicObject;
|
|
1557
|
+
requesterId: number;
|
|
1558
|
+
};
|
|
1559
|
+
declare class EventManager {
|
|
1560
|
+
private actionHandlers;
|
|
1561
|
+
addRowInsertHandler(onInsert: (data: ActionRowInsertData<unknown>) => Promise<void>, filter?: ActionRowInsertFilter): void;
|
|
1562
|
+
addColumnChangeHandler(onUpdate: (data: ActionColumnChangeData) => Promise<void>, filter: ActionColumnChangeFilter): void;
|
|
1563
|
+
addRowDeleteHandler(onDelete: (data: ActionRowDeleteData) => Promise<void>, filter?: ActionRowDeleteFilter): void;
|
|
1564
|
+
fireActionFromDbTrigger(sqlMutationData: SqlMutationData, result: TriggerResult): Promise<void>;
|
|
1565
|
+
private fireInsertActions;
|
|
1566
|
+
private fireDeleteActions;
|
|
1567
|
+
private fireUpdateActions;
|
|
1568
|
+
private hasHandlersForEventType;
|
|
1569
|
+
}
|
|
1570
|
+
declare const eventManager: EventManager;
|
|
1571
|
+
|
|
1572
|
+
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 LoginDetails, type MatchTypes, type MutationType, type PageQuery, PsqlConnection, PsqlPool, PsqlTransaction, type RequesterDetails, type ResponseType, type ResponseTypeMap, 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, type ValidatorString, escapeColumnName, eventManager, insertObjectQuery, isValueNumber, logger, questionMarksToOrderedParams, restura, updateObjectQuery };
|
package/dist/index.d.ts
CHANGED
|
@@ -1392,10 +1392,10 @@ interface AsyncExpressApplication {
|
|
|
1392
1392
|
}
|
|
1393
1393
|
|
|
1394
1394
|
declare abstract class PsqlConnection {
|
|
1395
|
-
constructor();
|
|
1395
|
+
protected constructor();
|
|
1396
1396
|
protected abstract query<R extends QueryResultRow = QueryResultRow, T extends Array<unknown> = unknown[]>(query: string, values?: QueryConfigValues<T>): Promise<QueryResult<R>>;
|
|
1397
|
-
queryOne(query: string, options: any[], requesterDetails: RequesterDetails): Promise<
|
|
1398
|
-
runQuery(query: string, options: any[], requesterDetails: RequesterDetails): Promise<
|
|
1397
|
+
queryOne<T>(query: string, options: any[], requesterDetails: RequesterDetails): Promise<T>;
|
|
1398
|
+
runQuery<T>(query: string, options: any[], requesterDetails: RequesterDetails): Promise<T[]>;
|
|
1399
1399
|
private logSqlStatement;
|
|
1400
1400
|
}
|
|
1401
1401
|
|
|
@@ -1406,18 +1406,6 @@ declare class PsqlPool extends PsqlConnection {
|
|
|
1406
1406
|
protected query<R extends QueryResultRow = QueryResultRow, T extends Array<unknown> = unknown[]>(query: string, values?: QueryConfigValues<T>): Promise<QueryResult<R>>;
|
|
1407
1407
|
}
|
|
1408
1408
|
|
|
1409
|
-
declare class PsqlTransaction extends PsqlConnection {
|
|
1410
|
-
clientConfig: ClientConfig;
|
|
1411
|
-
client: Client;
|
|
1412
|
-
private beginTransactionPromise;
|
|
1413
|
-
constructor(clientConfig: ClientConfig);
|
|
1414
|
-
private beginTransaction;
|
|
1415
|
-
rollback(): Promise<QueryResult<QueryResultRow>>;
|
|
1416
|
-
commit(): Promise<QueryResult<QueryResultRow>>;
|
|
1417
|
-
release(): Promise<void>;
|
|
1418
|
-
protected query<R extends QueryResultRow = QueryResultRow, T extends Array<unknown> = unknown[]>(query: string, values?: QueryConfigValues<T>): Promise<QueryResult<R>>;
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
1409
|
declare class ResturaEngine {
|
|
1422
1410
|
resturaConfig: ResturaConfigSchema;
|
|
1423
1411
|
private resturaRouter;
|
|
@@ -1516,4 +1504,69 @@ declare function updateObjectQuery(table: string, obj: DynamicObject, whereState
|
|
|
1516
1504
|
declare function isValueNumber(value: unknown): value is number;
|
|
1517
1505
|
declare function SQL(strings: any, ...values: any): any;
|
|
1518
1506
|
|
|
1519
|
-
|
|
1507
|
+
declare class PsqlTransaction extends PsqlConnection {
|
|
1508
|
+
clientConfig: ClientConfig;
|
|
1509
|
+
client: Client;
|
|
1510
|
+
private beginTransactionPromise;
|
|
1511
|
+
constructor(clientConfig: ClientConfig);
|
|
1512
|
+
private beginTransaction;
|
|
1513
|
+
rollback(): Promise<QueryResult<QueryResultRow>>;
|
|
1514
|
+
commit(): Promise<QueryResult<QueryResultRow>>;
|
|
1515
|
+
release(): Promise<void>;
|
|
1516
|
+
protected query<R extends QueryResultRow = QueryResultRow, T extends Array<unknown> = unknown[]>(query: string, values?: QueryConfigValues<T>): Promise<QueryResult<R>>;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
type EventType = 'DATABASE_ROW_DELETE' | 'DATABASE_ROW_INSERT' | 'DATABASE_COLUMN_UPDATE' | 'WEBHOOK';
|
|
1520
|
+
type MutationType = 'INSERT' | 'UPDATE' | 'DELETE';
|
|
1521
|
+
interface SqlMutationData {
|
|
1522
|
+
mutationType: MutationType;
|
|
1523
|
+
requesterDetails: RequesterDetails;
|
|
1524
|
+
}
|
|
1525
|
+
interface DatabaseActionData {
|
|
1526
|
+
tableName: string;
|
|
1527
|
+
requesterDetails: RequesterDetails;
|
|
1528
|
+
}
|
|
1529
|
+
interface ActionRowInsertData<T = DynamicObject> extends DatabaseActionData {
|
|
1530
|
+
insertId: number;
|
|
1531
|
+
insertObject: T;
|
|
1532
|
+
}
|
|
1533
|
+
interface ActionRowDeleteData extends DatabaseActionData {
|
|
1534
|
+
deletedRow: DynamicObject;
|
|
1535
|
+
}
|
|
1536
|
+
interface ActionColumnChangeData extends DatabaseActionData {
|
|
1537
|
+
tableName: string;
|
|
1538
|
+
rowId: number;
|
|
1539
|
+
newData: DynamicObject;
|
|
1540
|
+
oldData: DynamicObject;
|
|
1541
|
+
}
|
|
1542
|
+
interface ActionRowInsertFilter {
|
|
1543
|
+
tableName: string;
|
|
1544
|
+
}
|
|
1545
|
+
interface ActionRowDeleteFilter {
|
|
1546
|
+
tableName: string;
|
|
1547
|
+
}
|
|
1548
|
+
interface ActionColumnChangeFilter {
|
|
1549
|
+
tableName: string;
|
|
1550
|
+
}
|
|
1551
|
+
type TriggerResult = {
|
|
1552
|
+
table: string;
|
|
1553
|
+
insertId?: number;
|
|
1554
|
+
query: string;
|
|
1555
|
+
record: DynamicObject;
|
|
1556
|
+
previousRecord: DynamicObject;
|
|
1557
|
+
requesterId: number;
|
|
1558
|
+
};
|
|
1559
|
+
declare class EventManager {
|
|
1560
|
+
private actionHandlers;
|
|
1561
|
+
addRowInsertHandler(onInsert: (data: ActionRowInsertData<unknown>) => Promise<void>, filter?: ActionRowInsertFilter): void;
|
|
1562
|
+
addColumnChangeHandler(onUpdate: (data: ActionColumnChangeData) => Promise<void>, filter: ActionColumnChangeFilter): void;
|
|
1563
|
+
addRowDeleteHandler(onDelete: (data: ActionRowDeleteData) => Promise<void>, filter?: ActionRowDeleteFilter): void;
|
|
1564
|
+
fireActionFromDbTrigger(sqlMutationData: SqlMutationData, result: TriggerResult): Promise<void>;
|
|
1565
|
+
private fireInsertActions;
|
|
1566
|
+
private fireDeleteActions;
|
|
1567
|
+
private fireUpdateActions;
|
|
1568
|
+
private hasHandlersForEventType;
|
|
1569
|
+
}
|
|
1570
|
+
declare const eventManager: EventManager;
|
|
1571
|
+
|
|
1572
|
+
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 LoginDetails, type MatchTypes, type MutationType, type PageQuery, PsqlConnection, PsqlPool, PsqlTransaction, type RequesterDetails, type ResponseType, type ResponseTypeMap, 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, type ValidatorString, escapeColumnName, eventManager, insertObjectQuery, isValueNumber, logger, questionMarksToOrderedParams, restura, updateObjectQuery };
|
package/dist/index.js
CHANGED
|
@@ -74,6 +74,7 @@ __export(src_exports, {
|
|
|
74
74
|
RsError: () => RsError,
|
|
75
75
|
SQL: () => SQL,
|
|
76
76
|
escapeColumnName: () => escapeColumnName,
|
|
77
|
+
eventManager: () => eventManager_default,
|
|
77
78
|
insertObjectQuery: () => insertObjectQuery,
|
|
78
79
|
isValueNumber: () => isValueNumber2,
|
|
79
80
|
logger: () => logger,
|
|
@@ -260,7 +261,7 @@ var import_crypto = require("crypto");
|
|
|
260
261
|
var express = __toESM(require("express"));
|
|
261
262
|
var import_fs3 = __toESM(require("fs"));
|
|
262
263
|
var import_path3 = __toESM(require("path"));
|
|
263
|
-
var
|
|
264
|
+
var import_pg3 = __toESM(require("pg"));
|
|
264
265
|
var prettier3 = __toESM(require("prettier"));
|
|
265
266
|
|
|
266
267
|
// src/restura/sql/SqlUtils.ts
|
|
@@ -1279,7 +1280,8 @@ function insertObjectQuery(table, obj) {
|
|
|
1279
1280
|
const params = Object.values(obj);
|
|
1280
1281
|
const columns = keys.map((column) => escapeColumnName(column)).join(", ");
|
|
1281
1282
|
const values = params.map((value) => SQL`${value}`).join(", ");
|
|
1282
|
-
const query = `
|
|
1283
|
+
const query = `
|
|
1284
|
+
INSERT INTO "${table}" (${columns})
|
|
1283
1285
|
VALUES (${values})
|
|
1284
1286
|
RETURNING *`;
|
|
1285
1287
|
return query;
|
|
@@ -1289,7 +1291,8 @@ function updateObjectQuery(table, obj, whereStatement) {
|
|
|
1289
1291
|
for (const i in obj) {
|
|
1290
1292
|
setArray.push(`${escapeColumnName(i)} = ` + SQL`${obj[i]}`);
|
|
1291
1293
|
}
|
|
1292
|
-
return `
|
|
1294
|
+
return `
|
|
1295
|
+
UPDATE ${escapeColumnName(table)}
|
|
1293
1296
|
SET ${setArray.join(", ")} ${whereStatement}
|
|
1294
1297
|
RETURNING *`;
|
|
1295
1298
|
}
|
|
@@ -1319,8 +1322,10 @@ var PsqlConnection = class {
|
|
|
1319
1322
|
async queryOne(query, options, requesterDetails) {
|
|
1320
1323
|
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1321
1324
|
this.logSqlStatement(formattedQuery, options, requesterDetails);
|
|
1325
|
+
const queryMetadata = `--QUERY_METADATA(${JSON.stringify(requesterDetails)})
|
|
1326
|
+
`;
|
|
1322
1327
|
try {
|
|
1323
|
-
const response = await this.query(formattedQuery, options);
|
|
1328
|
+
const response = await this.query(queryMetadata + formattedQuery, options);
|
|
1324
1329
|
if (response.rows.length === 0) throw new RsError("NOT_FOUND", "No results found");
|
|
1325
1330
|
else if (response.rows.length > 1) throw new RsError("DUPLICATE", "More than one result found");
|
|
1326
1331
|
return response.rows[0];
|
|
@@ -1337,8 +1342,10 @@ var PsqlConnection = class {
|
|
|
1337
1342
|
async runQuery(query, options, requesterDetails) {
|
|
1338
1343
|
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1339
1344
|
this.logSqlStatement(formattedQuery, options, requesterDetails);
|
|
1345
|
+
const queryMetadata = `--QUERY_METADATA(${JSON.stringify(requesterDetails)})
|
|
1346
|
+
`;
|
|
1340
1347
|
try {
|
|
1341
|
-
const response = await this.query(formattedQuery, options);
|
|
1348
|
+
const response = await this.query(queryMetadata + formattedQuery, options);
|
|
1342
1349
|
return response.rows;
|
|
1343
1350
|
} catch (error) {
|
|
1344
1351
|
console.error(error, query, options);
|
|
@@ -1589,6 +1596,110 @@ var filterPsqlParser = import_pegjs.default.generate(filterSqlGrammar, {
|
|
|
1589
1596
|
});
|
|
1590
1597
|
var filterPsqlParser_default = filterPsqlParser;
|
|
1591
1598
|
|
|
1599
|
+
// src/restura/eventManager.ts
|
|
1600
|
+
var import_bluebird = __toESM(require("bluebird"));
|
|
1601
|
+
var EventManager = class {
|
|
1602
|
+
constructor() {
|
|
1603
|
+
this.actionHandlers = {
|
|
1604
|
+
DATABASE_ROW_DELETE: [],
|
|
1605
|
+
DATABASE_ROW_INSERT: [],
|
|
1606
|
+
DATABASE_COLUMN_UPDATE: []
|
|
1607
|
+
};
|
|
1608
|
+
}
|
|
1609
|
+
addRowInsertHandler(onInsert, filter) {
|
|
1610
|
+
this.actionHandlers.DATABASE_ROW_INSERT.push({
|
|
1611
|
+
callback: onInsert,
|
|
1612
|
+
filter
|
|
1613
|
+
});
|
|
1614
|
+
}
|
|
1615
|
+
addColumnChangeHandler(onUpdate, filter) {
|
|
1616
|
+
this.actionHandlers.DATABASE_COLUMN_UPDATE.push({
|
|
1617
|
+
callback: onUpdate,
|
|
1618
|
+
filter
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
addRowDeleteHandler(onDelete, filter) {
|
|
1622
|
+
this.actionHandlers.DATABASE_ROW_DELETE.push({
|
|
1623
|
+
callback: onDelete,
|
|
1624
|
+
filter
|
|
1625
|
+
});
|
|
1626
|
+
}
|
|
1627
|
+
async fireActionFromDbTrigger(sqlMutationData, result) {
|
|
1628
|
+
if (sqlMutationData.mutationType === "INSERT") {
|
|
1629
|
+
await this.fireInsertActions(sqlMutationData, result);
|
|
1630
|
+
} else if (sqlMutationData.mutationType === "UPDATE") {
|
|
1631
|
+
await this.fireUpdateActions(sqlMutationData, result);
|
|
1632
|
+
} else if (sqlMutationData.mutationType === "DELETE") {
|
|
1633
|
+
await this.fireDeleteActions(sqlMutationData, result);
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
async fireInsertActions(data, triggerResult) {
|
|
1637
|
+
await import_bluebird.default.map(
|
|
1638
|
+
this.actionHandlers.DATABASE_ROW_INSERT,
|
|
1639
|
+
({ callback, filter }) => {
|
|
1640
|
+
if (!this.hasHandlersForEventType("DATABASE_ROW_INSERT", filter, triggerResult)) return;
|
|
1641
|
+
const insertData = {
|
|
1642
|
+
tableName: triggerResult.table,
|
|
1643
|
+
insertId: triggerResult.record.id,
|
|
1644
|
+
insertObject: triggerResult.record,
|
|
1645
|
+
requesterDetails: data.requesterDetails
|
|
1646
|
+
};
|
|
1647
|
+
callback(insertData, data.requesterDetails);
|
|
1648
|
+
},
|
|
1649
|
+
{ concurrency: 10 }
|
|
1650
|
+
);
|
|
1651
|
+
}
|
|
1652
|
+
async fireDeleteActions(data, triggerResult) {
|
|
1653
|
+
await import_bluebird.default.map(
|
|
1654
|
+
this.actionHandlers.DATABASE_ROW_DELETE,
|
|
1655
|
+
({ callback, filter }) => {
|
|
1656
|
+
if (!this.hasHandlersForEventType("DATABASE_ROW_DELETE", filter, triggerResult)) return;
|
|
1657
|
+
const deleteData = {
|
|
1658
|
+
tableName: triggerResult.table,
|
|
1659
|
+
deletedRow: triggerResult.previousRecord,
|
|
1660
|
+
requesterDetails: data.requesterDetails
|
|
1661
|
+
};
|
|
1662
|
+
callback(deleteData, data.requesterDetails);
|
|
1663
|
+
},
|
|
1664
|
+
{ concurrency: 10 }
|
|
1665
|
+
);
|
|
1666
|
+
}
|
|
1667
|
+
async fireUpdateActions(data, triggerResult) {
|
|
1668
|
+
await import_bluebird.default.map(
|
|
1669
|
+
this.actionHandlers.DATABASE_COLUMN_UPDATE,
|
|
1670
|
+
({ callback, filter }) => {
|
|
1671
|
+
if (!this.hasHandlersForEventType("DATABASE_COLUMN_UPDATE", filter, triggerResult)) return;
|
|
1672
|
+
const columnChangeData = {
|
|
1673
|
+
tableName: triggerResult.table,
|
|
1674
|
+
rowId: triggerResult.record.id,
|
|
1675
|
+
newData: triggerResult.record,
|
|
1676
|
+
oldData: triggerResult.previousRecord,
|
|
1677
|
+
requesterDetails: data.requesterDetails
|
|
1678
|
+
};
|
|
1679
|
+
callback(columnChangeData, data.requesterDetails);
|
|
1680
|
+
},
|
|
1681
|
+
{ concurrency: 10 }
|
|
1682
|
+
);
|
|
1683
|
+
}
|
|
1684
|
+
hasHandlersForEventType(eventType, filter, triggerResult) {
|
|
1685
|
+
if (filter) {
|
|
1686
|
+
switch (eventType) {
|
|
1687
|
+
case "DATABASE_ROW_INSERT":
|
|
1688
|
+
case "DATABASE_ROW_DELETE":
|
|
1689
|
+
if (filter.tableName && filter.tableName !== triggerResult.table) return false;
|
|
1690
|
+
break;
|
|
1691
|
+
case "DATABASE_COLUMN_UPDATE":
|
|
1692
|
+
const filterColumnChange = filter;
|
|
1693
|
+
if (filterColumnChange.tableName !== filter.tableName) return false;
|
|
1694
|
+
break;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
return true;
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
var eventManager = new EventManager();
|
|
1701
|
+
var eventManager_default = eventManager;
|
|
1702
|
+
|
|
1592
1703
|
// src/restura/sql/PsqlEngine.ts
|
|
1593
1704
|
var { Client } = import_pg2.default;
|
|
1594
1705
|
var systemUser = {
|
|
@@ -1598,9 +1709,49 @@ var systemUser = {
|
|
|
1598
1709
|
isSystemUser: true
|
|
1599
1710
|
};
|
|
1600
1711
|
var PsqlEngine = class extends SqlEngine {
|
|
1601
|
-
constructor(psqlConnectionPool) {
|
|
1712
|
+
constructor(psqlConnectionPool, shouldListenForDbTriggers = false) {
|
|
1602
1713
|
super();
|
|
1603
1714
|
this.psqlConnectionPool = psqlConnectionPool;
|
|
1715
|
+
if (shouldListenForDbTriggers) {
|
|
1716
|
+
this.setupTriggerListeners = this.listenForDbTriggers();
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
async close() {
|
|
1720
|
+
if (this.triggerClient) {
|
|
1721
|
+
await this.triggerClient.end();
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
async listenForDbTriggers() {
|
|
1725
|
+
this.triggerClient = new Client({
|
|
1726
|
+
user: this.psqlConnectionPool.poolConfig.user,
|
|
1727
|
+
host: this.psqlConnectionPool.poolConfig.host,
|
|
1728
|
+
database: this.psqlConnectionPool.poolConfig.database,
|
|
1729
|
+
password: this.psqlConnectionPool.poolConfig.password,
|
|
1730
|
+
port: this.psqlConnectionPool.poolConfig.port,
|
|
1731
|
+
connectionTimeoutMillis: 2e3
|
|
1732
|
+
});
|
|
1733
|
+
await this.triggerClient.connect();
|
|
1734
|
+
const promises = [];
|
|
1735
|
+
promises.push(this.triggerClient.query("LISTEN insert"));
|
|
1736
|
+
promises.push(this.triggerClient.query("LISTEN update"));
|
|
1737
|
+
promises.push(this.triggerClient.query("LISTEN delete"));
|
|
1738
|
+
await Promise.all(promises);
|
|
1739
|
+
this.triggerClient.on("notification", async (msg) => {
|
|
1740
|
+
if (msg.channel === "insert" || msg.channel === "update" || msg.channel === "delete") {
|
|
1741
|
+
const payload = JSON.parse(msg.payload);
|
|
1742
|
+
await this.handleTrigger(payload, msg.channel.toUpperCase());
|
|
1743
|
+
}
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
async handleTrigger(payload, mutationType) {
|
|
1747
|
+
const findRequesterDetailsRegex = /^--QUERY_METADATA\(\{.*\}\)/;
|
|
1748
|
+
let requesterDetails = {};
|
|
1749
|
+
const match = payload.query.match(findRequesterDetailsRegex);
|
|
1750
|
+
if (match) {
|
|
1751
|
+
const jsonString = match[0].slice(match[0].indexOf("{"), match[0].lastIndexOf("}") + 1);
|
|
1752
|
+
requesterDetails = import_core_utils5.ObjectUtils.safeParse(jsonString);
|
|
1753
|
+
await eventManager_default.fireActionFromDbTrigger({ requesterDetails, mutationType }, payload);
|
|
1754
|
+
}
|
|
1604
1755
|
}
|
|
1605
1756
|
async createDatabaseFromSchema(schema, connection) {
|
|
1606
1757
|
const sqlFullStatement = this.generateDatabaseSchemaFromSchema(schema);
|
|
@@ -1611,7 +1762,11 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1611
1762
|
const sqlStatements = [];
|
|
1612
1763
|
const enums = [];
|
|
1613
1764
|
const indexes = [];
|
|
1765
|
+
const triggers = [];
|
|
1614
1766
|
for (const table of schema.database) {
|
|
1767
|
+
triggers.push(this.createInsertTriggers(table.name));
|
|
1768
|
+
triggers.push(this.createUpdateTrigger(table.name));
|
|
1769
|
+
triggers.push(this.createDeleteTrigger(table.name));
|
|
1615
1770
|
let sql = `CREATE TABLE "${table.name}"
|
|
1616
1771
|
( `;
|
|
1617
1772
|
const tableColumns = [];
|
|
@@ -1649,7 +1804,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1649
1804
|
indexes.push(
|
|
1650
1805
|
` CREATE ${unique}INDEX "${index.name}" ON "${table.name}" (${index.columns.map((item) => {
|
|
1651
1806
|
return `"${item}" ${index.order}`;
|
|
1652
|
-
}).join(", ")})
|
|
1807
|
+
}).join(", ")});`
|
|
1653
1808
|
);
|
|
1654
1809
|
}
|
|
1655
1810
|
}
|
|
@@ -1679,7 +1834,8 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1679
1834
|
}
|
|
1680
1835
|
sqlStatements.push(sql + constraints.join(",\n") + ";");
|
|
1681
1836
|
}
|
|
1682
|
-
sqlStatements.push(indexes.join("
|
|
1837
|
+
sqlStatements.push(indexes.join("\n"));
|
|
1838
|
+
sqlStatements.push(triggers.join("\n"));
|
|
1683
1839
|
return enums.join("\n") + "\n" + sqlStatements.join("\n\n");
|
|
1684
1840
|
}
|
|
1685
1841
|
async getScratchPool() {
|
|
@@ -1747,8 +1903,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1747
1903
|
)) {
|
|
1748
1904
|
return "'[]'";
|
|
1749
1905
|
}
|
|
1750
|
-
return `COALESCE((
|
|
1751
|
-
SELECT JSON_AGG(JSON_BUILD_OBJECT(
|
|
1906
|
+
return `COALESCE((SELECT JSON_AGG(JSON_BUILD_OBJECT(
|
|
1752
1907
|
${item.subquery.properties.map((nestedItem) => {
|
|
1753
1908
|
if (!this.doesRoleHavePermissionToColumn(req.requesterDetails.role, schema, nestedItem, [
|
|
1754
1909
|
...routeData.joins,
|
|
@@ -1757,7 +1912,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1757
1912
|
return;
|
|
1758
1913
|
}
|
|
1759
1914
|
if (nestedItem.subquery) {
|
|
1760
|
-
return `
|
|
1915
|
+
return `'${nestedItem.name}', ${this.createNestedSelect(
|
|
1761
1916
|
// recursion
|
|
1762
1917
|
req,
|
|
1763
1918
|
schema,
|
|
@@ -1768,7 +1923,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1768
1923
|
)}`;
|
|
1769
1924
|
}
|
|
1770
1925
|
return `'${nestedItem.name}', ${escapeColumnName(nestedItem.selector)}`;
|
|
1771
|
-
}).filter(Boolean).join(",")}
|
|
1926
|
+
}).filter(Boolean).join(", ")}
|
|
1772
1927
|
))
|
|
1773
1928
|
FROM
|
|
1774
1929
|
"${item.subquery.table}"
|
|
@@ -1896,10 +2051,12 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1896
2051
|
req.requesterDetails.role,
|
|
1897
2052
|
sqlParams
|
|
1898
2053
|
);
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
2054
|
+
const whereClause = this.generateWhereClause(req, routeData.where, routeData, sqlParams);
|
|
2055
|
+
if (whereClause.replace(/\s/g, "") === "") {
|
|
2056
|
+
throw new RsError("DELETE_FORBIDDEN", "Deletes need a where clause");
|
|
2057
|
+
}
|
|
2058
|
+
const deleteStatement = `
|
|
2059
|
+
DELETE FROM "${routeData.table}" ${joinStatement} ${whereClause}`;
|
|
1903
2060
|
await this.psqlConnectionPool.runQuery(deleteStatement, sqlParams, req.requesterDetails);
|
|
1904
2061
|
return true;
|
|
1905
2062
|
}
|
|
@@ -1962,17 +2119,17 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1962
2119
|
);
|
|
1963
2120
|
let operator = item.operator;
|
|
1964
2121
|
if (operator === "LIKE") {
|
|
1965
|
-
|
|
2122
|
+
item.value = `%${item.value}%`;
|
|
1966
2123
|
} else if (operator === "STARTS WITH") {
|
|
1967
2124
|
operator = "LIKE";
|
|
1968
|
-
|
|
2125
|
+
item.value = `${item.value}%`;
|
|
1969
2126
|
} else if (operator === "ENDS WITH") {
|
|
1970
2127
|
operator = "LIKE";
|
|
1971
|
-
|
|
2128
|
+
item.value = `%${item.value}`;
|
|
1972
2129
|
}
|
|
1973
2130
|
const replacedValue = this.replaceParamKeywords(item.value, routeData, req, sqlParams);
|
|
1974
2131
|
const escapedValue = SQL`${replacedValue}`;
|
|
1975
|
-
whereClause += ` ${item.conjunction || ""} "${item.tableName}"."${item.columnName}" ${operator} ${["IN", "NOT IN"].includes(operator) ? `(${escapedValue})` : escapedValue}
|
|
2132
|
+
whereClause += ` ${item.conjunction || ""} "${item.tableName}"."${item.columnName}" ${operator.replace("LIKE", "ILIKE")} ${["IN", "NOT IN"].includes(operator) ? `(${escapedValue})` : escapedValue}
|
|
1976
2133
|
`;
|
|
1977
2134
|
});
|
|
1978
2135
|
const data = req.data;
|
|
@@ -2006,7 +2163,67 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
2006
2163
|
}
|
|
2007
2164
|
return whereClause;
|
|
2008
2165
|
}
|
|
2166
|
+
createUpdateTrigger(tableName) {
|
|
2167
|
+
return `
|
|
2168
|
+
CREATE OR REPLACE FUNCTION notify_${tableName}_update()
|
|
2169
|
+
RETURNS TRIGGER AS $$
|
|
2170
|
+
BEGIN
|
|
2171
|
+
PERFORM pg_notify('update', JSON_BUILD_OBJECT('table', '${tableName}', 'query', current_query(), 'record', NEW, 'previousRecord', OLD)::text);
|
|
2172
|
+
RETURN NEW;
|
|
2173
|
+
END;
|
|
2174
|
+
$$ LANGUAGE plpgsql;
|
|
2175
|
+
|
|
2176
|
+
CREATE OR REPLACE TRIGGER ${tableName}_update
|
|
2177
|
+
AFTER UPDATE ON "${tableName}"
|
|
2178
|
+
FOR EACH ROW
|
|
2179
|
+
EXECUTE FUNCTION notify_${tableName}_update();
|
|
2180
|
+
`;
|
|
2181
|
+
}
|
|
2182
|
+
createDeleteTrigger(tableName) {
|
|
2183
|
+
return `
|
|
2184
|
+
CREATE OR REPLACE FUNCTION notify_${tableName}_delete()
|
|
2185
|
+
RETURNS TRIGGER AS $$
|
|
2186
|
+
BEGIN
|
|
2187
|
+
PERFORM pg_notify('delete', JSON_BUILD_OBJECT('table', '${tableName}', 'query', current_query(), 'record', NEW, 'previousRecord', OLD)::text);
|
|
2188
|
+
RETURN NEW;
|
|
2189
|
+
END;
|
|
2190
|
+
$$ LANGUAGE plpgsql;
|
|
2191
|
+
|
|
2192
|
+
CREATE OR REPLACE TRIGGER "${tableName}_delete"
|
|
2193
|
+
AFTER DELETE ON "${tableName}"
|
|
2194
|
+
FOR EACH ROW
|
|
2195
|
+
EXECUTE FUNCTION notify_${tableName}_delete();
|
|
2196
|
+
`;
|
|
2197
|
+
}
|
|
2198
|
+
createInsertTriggers(tableName) {
|
|
2199
|
+
return `
|
|
2200
|
+
CREATE OR REPLACE FUNCTION notify_${tableName}_insert()
|
|
2201
|
+
RETURNS TRIGGER AS $$
|
|
2202
|
+
BEGIN
|
|
2203
|
+
PERFORM pg_notify('insert', JSON_BUILD_OBJECT('table', '${tableName}', 'query', current_query(), 'record', NEW, 'previousRecord', OLD)::text);
|
|
2204
|
+
RETURN NEW;
|
|
2205
|
+
END;
|
|
2206
|
+
$$ LANGUAGE plpgsql;
|
|
2207
|
+
|
|
2208
|
+
CREATE TRIGGER "${tableName}_insert"
|
|
2209
|
+
AFTER INSERT ON "${tableName}"
|
|
2210
|
+
FOR EACH ROW
|
|
2211
|
+
EXECUTE FUNCTION notify_${tableName}_insert();
|
|
2212
|
+
`;
|
|
2213
|
+
}
|
|
2009
2214
|
};
|
|
2215
|
+
__decorateClass([
|
|
2216
|
+
boundMethod
|
|
2217
|
+
], PsqlEngine.prototype, "handleTrigger", 1);
|
|
2218
|
+
__decorateClass([
|
|
2219
|
+
boundMethod
|
|
2220
|
+
], PsqlEngine.prototype, "createUpdateTrigger", 1);
|
|
2221
|
+
__decorateClass([
|
|
2222
|
+
boundMethod
|
|
2223
|
+
], PsqlEngine.prototype, "createDeleteTrigger", 1);
|
|
2224
|
+
__decorateClass([
|
|
2225
|
+
boundMethod
|
|
2226
|
+
], PsqlEngine.prototype, "createInsertTriggers", 1);
|
|
2010
2227
|
function schemaToPsqlType(column, tableName) {
|
|
2011
2228
|
if (column.hasAutoIncrement) return "BIGSERIAL";
|
|
2012
2229
|
if (column.type === "ENUM") return `"${tableName}_${column.name}_enum"`;
|
|
@@ -2015,35 +2232,6 @@ function schemaToPsqlType(column, tableName) {
|
|
|
2015
2232
|
return column.type;
|
|
2016
2233
|
}
|
|
2017
2234
|
|
|
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
2235
|
// src/restura/compareSchema.ts
|
|
2048
2236
|
var import_lodash = __toESM(require("lodash.clonedeep"));
|
|
2049
2237
|
var CompareSchema = class {
|
|
@@ -2135,7 +2323,7 @@ var compareSchema = new CompareSchema();
|
|
|
2135
2323
|
var compareSchema_default = compareSchema;
|
|
2136
2324
|
|
|
2137
2325
|
// src/restura/restura.ts
|
|
2138
|
-
var { types } =
|
|
2326
|
+
var { types } = import_pg3.default;
|
|
2139
2327
|
var ResturaEngine = class {
|
|
2140
2328
|
constructor() {
|
|
2141
2329
|
this.publicEndpoints = {
|
|
@@ -2510,6 +2698,35 @@ var setupPgReturnTypes = () => {
|
|
|
2510
2698
|
};
|
|
2511
2699
|
setupPgReturnTypes();
|
|
2512
2700
|
var restura = new ResturaEngine();
|
|
2701
|
+
|
|
2702
|
+
// src/restura/sql/PsqlTransaction.ts
|
|
2703
|
+
var import_pg4 = __toESM(require("pg"));
|
|
2704
|
+
var { Client: Client2 } = import_pg4.default;
|
|
2705
|
+
var PsqlTransaction = class extends PsqlConnection {
|
|
2706
|
+
constructor(clientConfig) {
|
|
2707
|
+
super();
|
|
2708
|
+
this.clientConfig = clientConfig;
|
|
2709
|
+
this.client = new Client2(clientConfig);
|
|
2710
|
+
this.beginTransactionPromise = this.beginTransaction();
|
|
2711
|
+
}
|
|
2712
|
+
async beginTransaction() {
|
|
2713
|
+
return this.query("BEGIN");
|
|
2714
|
+
}
|
|
2715
|
+
async rollback() {
|
|
2716
|
+
return this.query("ROLLBACK");
|
|
2717
|
+
}
|
|
2718
|
+
async commit() {
|
|
2719
|
+
return this.query("COMMIT");
|
|
2720
|
+
}
|
|
2721
|
+
async release() {
|
|
2722
|
+
return this.client.end();
|
|
2723
|
+
}
|
|
2724
|
+
async query(query, values) {
|
|
2725
|
+
await this.client.connect();
|
|
2726
|
+
await this.beginTransactionPromise;
|
|
2727
|
+
return this.client.query(query, values);
|
|
2728
|
+
}
|
|
2729
|
+
};
|
|
2513
2730
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2514
2731
|
0 && (module.exports = {
|
|
2515
2732
|
HtmlStatusCodes,
|
|
@@ -2519,6 +2736,7 @@ var restura = new ResturaEngine();
|
|
|
2519
2736
|
RsError,
|
|
2520
2737
|
SQL,
|
|
2521
2738
|
escapeColumnName,
|
|
2739
|
+
eventManager,
|
|
2522
2740
|
insertObjectQuery,
|
|
2523
2741
|
isValueNumber,
|
|
2524
2742
|
logger,
|