@restura/core 0.1.0-alpha.14 → 0.1.0-alpha.16
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 +65 -36
- package/dist/index.d.ts +65 -36
- package/dist/index.js +272 -77
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +272 -75
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -68,9 +68,7 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
68
68
|
var src_exports = {};
|
|
69
69
|
__export(src_exports, {
|
|
70
70
|
HtmlStatusCodes: () => HtmlStatusCodes,
|
|
71
|
-
PsqlConnection: () => PsqlConnection,
|
|
72
71
|
PsqlPool: () => PsqlPool,
|
|
73
|
-
PsqlTransaction: () => PsqlTransaction,
|
|
74
72
|
RsError: () => RsError,
|
|
75
73
|
SQL: () => SQL,
|
|
76
74
|
escapeColumnName: () => escapeColumnName,
|
|
@@ -792,7 +790,7 @@ var joinDataSchema = import_zod3.z.object({
|
|
|
792
790
|
var requestDataSchema = import_zod3.z.object({
|
|
793
791
|
name: import_zod3.z.string(),
|
|
794
792
|
required: import_zod3.z.boolean(),
|
|
795
|
-
isNullable: import_zod3.z.boolean().optional()
|
|
793
|
+
isNullable: import_zod3.z.boolean().optional(),
|
|
796
794
|
validator: import_zod3.z.array(validatorDataSchema)
|
|
797
795
|
}).strict();
|
|
798
796
|
var responseDataSchema = import_zod3.z.object({
|
|
@@ -878,6 +876,12 @@ var postgresColumnDateTypesSchema = import_zod3.z.enum([
|
|
|
878
876
|
"INTERVAL"
|
|
879
877
|
// time span
|
|
880
878
|
]);
|
|
879
|
+
var postgresColumnJsonTypesSchema = import_zod3.z.enum([
|
|
880
|
+
"JSON",
|
|
881
|
+
// stores JSON data as raw text
|
|
882
|
+
"JSONB"
|
|
883
|
+
// stores JSON data in a binary format, optimized for query performance
|
|
884
|
+
]);
|
|
881
885
|
var mariaDbColumnNumericTypesSchema = import_zod3.z.enum([
|
|
882
886
|
"BOOLEAN",
|
|
883
887
|
// 1-byte A synonym for "TINYINT(1)". Supported from version 1.2.0 onwards.
|
|
@@ -940,6 +944,7 @@ var columnDataSchema = import_zod3.z.object({
|
|
|
940
944
|
postgresColumnNumericTypesSchema,
|
|
941
945
|
postgresColumnStringTypesSchema,
|
|
942
946
|
postgresColumnDateTypesSchema,
|
|
947
|
+
postgresColumnJsonTypesSchema,
|
|
943
948
|
mariaDbColumnNumericTypesSchema,
|
|
944
949
|
mariaDbColumnStringTypesSchema,
|
|
945
950
|
mariaDbColumnDateTypesSchema
|
|
@@ -1247,10 +1252,16 @@ function convertTable(table) {
|
|
|
1247
1252
|
|
|
1248
1253
|
// src/restura/sql/PsqlEngine.ts
|
|
1249
1254
|
var import_core_utils5 = require("@redskytech/core-utils");
|
|
1255
|
+
var import_pg_diff_sync = __toESM(require("@wmfs/pg-diff-sync"));
|
|
1256
|
+
var import_pg_info = __toESM(require("@wmfs/pg-info"));
|
|
1257
|
+
var import_pg2 = __toESM(require("pg"));
|
|
1250
1258
|
|
|
1251
1259
|
// src/restura/sql/PsqlPool.ts
|
|
1252
1260
|
var import_pg = __toESM(require("pg"));
|
|
1253
1261
|
|
|
1262
|
+
// src/restura/sql/PsqlConnection.ts
|
|
1263
|
+
var import_pg_format2 = __toESM(require("pg-format"));
|
|
1264
|
+
|
|
1254
1265
|
// src/restura/sql/PsqlUtils.ts
|
|
1255
1266
|
var import_pg_format = __toESM(require("pg-format"));
|
|
1256
1267
|
function escapeColumnName(columnName) {
|
|
@@ -1266,7 +1277,8 @@ function insertObjectQuery(table, obj) {
|
|
|
1266
1277
|
const params = Object.values(obj);
|
|
1267
1278
|
const columns = keys.map((column) => escapeColumnName(column)).join(", ");
|
|
1268
1279
|
const values = params.map((value) => SQL`${value}`).join(", ");
|
|
1269
|
-
const query = `
|
|
1280
|
+
const query = `
|
|
1281
|
+
INSERT INTO "${table}" (${columns})
|
|
1270
1282
|
VALUES (${values})
|
|
1271
1283
|
RETURNING *`;
|
|
1272
1284
|
return query;
|
|
@@ -1276,7 +1288,8 @@ function updateObjectQuery(table, obj, whereStatement) {
|
|
|
1276
1288
|
for (const i in obj) {
|
|
1277
1289
|
setArray.push(`${escapeColumnName(i)} = ` + SQL`${obj[i]}`);
|
|
1278
1290
|
}
|
|
1279
|
-
return `
|
|
1291
|
+
return `
|
|
1292
|
+
UPDATE ${escapeColumnName(table)}
|
|
1280
1293
|
SET ${setArray.join(", ")} ${whereStatement}
|
|
1281
1294
|
RETURNING *`;
|
|
1282
1295
|
}
|
|
@@ -1299,7 +1312,6 @@ function SQL(strings, ...values) {
|
|
|
1299
1312
|
}
|
|
1300
1313
|
|
|
1301
1314
|
// src/restura/sql/PsqlConnection.ts
|
|
1302
|
-
var import_pg_format2 = __toESM(require("pg-format"));
|
|
1303
1315
|
var PsqlConnection = class {
|
|
1304
1316
|
constructor() {
|
|
1305
1317
|
}
|
|
@@ -1307,8 +1319,10 @@ var PsqlConnection = class {
|
|
|
1307
1319
|
async queryOne(query, options, requesterDetails) {
|
|
1308
1320
|
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1309
1321
|
this.logSqlStatement(formattedQuery, options, requesterDetails);
|
|
1322
|
+
const queryMetadata = `--QUERY_METADATA(${JSON.stringify(requesterDetails)})
|
|
1323
|
+
`;
|
|
1310
1324
|
try {
|
|
1311
|
-
const response = await this.query(formattedQuery, options);
|
|
1325
|
+
const response = await this.query(queryMetadata + formattedQuery, options);
|
|
1312
1326
|
if (response.rows.length === 0) throw new RsError("NOT_FOUND", "No results found");
|
|
1313
1327
|
else if (response.rows.length > 1) throw new RsError("DUPLICATE", "More than one result found");
|
|
1314
1328
|
return response.rows[0];
|
|
@@ -1325,8 +1339,10 @@ var PsqlConnection = class {
|
|
|
1325
1339
|
async runQuery(query, options, requesterDetails) {
|
|
1326
1340
|
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1327
1341
|
this.logSqlStatement(formattedQuery, options, requesterDetails);
|
|
1342
|
+
const queryMetadata = `--QUERY_METADATA(${JSON.stringify(requesterDetails)})
|
|
1343
|
+
`;
|
|
1328
1344
|
try {
|
|
1329
|
-
const response = await this.query(formattedQuery, options);
|
|
1345
|
+
const response = await this.query(queryMetadata + formattedQuery, options);
|
|
1330
1346
|
return response.rows;
|
|
1331
1347
|
} catch (error) {
|
|
1332
1348
|
console.error(error, query, options);
|
|
@@ -1577,10 +1593,112 @@ var filterPsqlParser = import_pegjs.default.generate(filterSqlGrammar, {
|
|
|
1577
1593
|
});
|
|
1578
1594
|
var filterPsqlParser_default = filterPsqlParser;
|
|
1579
1595
|
|
|
1596
|
+
// src/restura/eventManager.ts
|
|
1597
|
+
var import_bluebird = __toESM(require("bluebird"));
|
|
1598
|
+
var EventManager = class {
|
|
1599
|
+
constructor() {
|
|
1600
|
+
this.actionHandlers = {
|
|
1601
|
+
DATABASE_ROW_DELETE: [],
|
|
1602
|
+
DATABASE_ROW_INSERT: [],
|
|
1603
|
+
DATABASE_COLUMN_UPDATE: []
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
addRowInsertHandler(onInsert, filter) {
|
|
1607
|
+
this.actionHandlers.DATABASE_ROW_INSERT.push({
|
|
1608
|
+
callback: onInsert,
|
|
1609
|
+
filter
|
|
1610
|
+
});
|
|
1611
|
+
}
|
|
1612
|
+
addColumnChangeHandler(onUpdate, filter) {
|
|
1613
|
+
this.actionHandlers.DATABASE_COLUMN_UPDATE.push({
|
|
1614
|
+
callback: onUpdate,
|
|
1615
|
+
filter
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
addRowDeleteHandler(onDelete, filter) {
|
|
1619
|
+
this.actionHandlers.DATABASE_ROW_DELETE.push({
|
|
1620
|
+
callback: onDelete,
|
|
1621
|
+
filter
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
async fireActionFromDbTrigger(sqlMutationData, result) {
|
|
1625
|
+
if (sqlMutationData.mutationType === "INSERT") {
|
|
1626
|
+
await this.fireInsertActions(sqlMutationData, result);
|
|
1627
|
+
} else if (sqlMutationData.mutationType === "UPDATE") {
|
|
1628
|
+
await this.fireUpdateActions(sqlMutationData, result);
|
|
1629
|
+
} else if (sqlMutationData.mutationType === "DELETE") {
|
|
1630
|
+
await this.fireDeleteActions(sqlMutationData, result);
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
async fireInsertActions(data, triggerResult) {
|
|
1634
|
+
await import_bluebird.default.map(
|
|
1635
|
+
this.actionHandlers.DATABASE_ROW_INSERT,
|
|
1636
|
+
({ callback, filter }) => {
|
|
1637
|
+
if (!this.hasHandlersForEventType("DATABASE_ROW_INSERT", filter, triggerResult)) return;
|
|
1638
|
+
const insertData = {
|
|
1639
|
+
tableName: triggerResult.table,
|
|
1640
|
+
insertId: triggerResult.record.id,
|
|
1641
|
+
insertObject: triggerResult.record,
|
|
1642
|
+
requesterDetails: data.requesterDetails
|
|
1643
|
+
};
|
|
1644
|
+
callback(insertData, data.requesterDetails);
|
|
1645
|
+
},
|
|
1646
|
+
{ concurrency: 10 }
|
|
1647
|
+
);
|
|
1648
|
+
}
|
|
1649
|
+
async fireDeleteActions(data, triggerResult) {
|
|
1650
|
+
await import_bluebird.default.map(
|
|
1651
|
+
this.actionHandlers.DATABASE_ROW_DELETE,
|
|
1652
|
+
({ callback, filter }) => {
|
|
1653
|
+
if (!this.hasHandlersForEventType("DATABASE_ROW_DELETE", filter, triggerResult)) return;
|
|
1654
|
+
const deleteData = {
|
|
1655
|
+
tableName: triggerResult.table,
|
|
1656
|
+
deletedRow: triggerResult.previousRecord,
|
|
1657
|
+
requesterDetails: data.requesterDetails
|
|
1658
|
+
};
|
|
1659
|
+
callback(deleteData, data.requesterDetails);
|
|
1660
|
+
},
|
|
1661
|
+
{ concurrency: 10 }
|
|
1662
|
+
);
|
|
1663
|
+
}
|
|
1664
|
+
async fireUpdateActions(data, triggerResult) {
|
|
1665
|
+
await import_bluebird.default.map(
|
|
1666
|
+
this.actionHandlers.DATABASE_COLUMN_UPDATE,
|
|
1667
|
+
({ callback, filter }) => {
|
|
1668
|
+
if (!this.hasHandlersForEventType("DATABASE_COLUMN_UPDATE", filter, triggerResult)) return;
|
|
1669
|
+
const columnChangeData = {
|
|
1670
|
+
tableName: triggerResult.table,
|
|
1671
|
+
rowId: triggerResult.record.id,
|
|
1672
|
+
newData: triggerResult.record,
|
|
1673
|
+
oldData: triggerResult.previousRecord,
|
|
1674
|
+
requesterDetails: data.requesterDetails
|
|
1675
|
+
};
|
|
1676
|
+
callback(columnChangeData, data.requesterDetails);
|
|
1677
|
+
},
|
|
1678
|
+
{ concurrency: 10 }
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
hasHandlersForEventType(eventType, filter, triggerResult) {
|
|
1682
|
+
if (filter) {
|
|
1683
|
+
switch (eventType) {
|
|
1684
|
+
case "DATABASE_ROW_INSERT":
|
|
1685
|
+
case "DATABASE_ROW_DELETE":
|
|
1686
|
+
if (filter.tableName && filter.tableName !== triggerResult.table) return false;
|
|
1687
|
+
break;
|
|
1688
|
+
case "DATABASE_COLUMN_UPDATE":
|
|
1689
|
+
const filterColumnChange = filter;
|
|
1690
|
+
if (filterColumnChange.tableName !== filter.tableName) return false;
|
|
1691
|
+
break;
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
return true;
|
|
1695
|
+
}
|
|
1696
|
+
};
|
|
1697
|
+
var eventManager = new EventManager();
|
|
1698
|
+
var eventManager_default = eventManager;
|
|
1699
|
+
|
|
1580
1700
|
// src/restura/sql/PsqlEngine.ts
|
|
1581
|
-
var
|
|
1582
|
-
var import_pg_info = __toESM(require("@wmfs/pg-info"));
|
|
1583
|
-
var { Client } = "pg";
|
|
1701
|
+
var { Client } = import_pg2.default;
|
|
1584
1702
|
var systemUser = {
|
|
1585
1703
|
role: "",
|
|
1586
1704
|
host: "",
|
|
@@ -1588,9 +1706,49 @@ var systemUser = {
|
|
|
1588
1706
|
isSystemUser: true
|
|
1589
1707
|
};
|
|
1590
1708
|
var PsqlEngine = class extends SqlEngine {
|
|
1591
|
-
constructor(psqlConnectionPool) {
|
|
1709
|
+
constructor(psqlConnectionPool, shouldListenForDbTriggers = false) {
|
|
1592
1710
|
super();
|
|
1593
1711
|
this.psqlConnectionPool = psqlConnectionPool;
|
|
1712
|
+
if (shouldListenForDbTriggers) {
|
|
1713
|
+
this.setupTriggerListeners = this.listenForDbTriggers();
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
async close() {
|
|
1717
|
+
if (this.triggerClient) {
|
|
1718
|
+
await this.triggerClient.end();
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
async listenForDbTriggers() {
|
|
1722
|
+
this.triggerClient = new Client({
|
|
1723
|
+
user: this.psqlConnectionPool.poolConfig.user,
|
|
1724
|
+
host: this.psqlConnectionPool.poolConfig.host,
|
|
1725
|
+
database: this.psqlConnectionPool.poolConfig.database,
|
|
1726
|
+
password: this.psqlConnectionPool.poolConfig.password,
|
|
1727
|
+
port: this.psqlConnectionPool.poolConfig.port,
|
|
1728
|
+
connectionTimeoutMillis: 2e3
|
|
1729
|
+
});
|
|
1730
|
+
await this.triggerClient.connect();
|
|
1731
|
+
const promises = [];
|
|
1732
|
+
promises.push(this.triggerClient.query("LISTEN insert"));
|
|
1733
|
+
promises.push(this.triggerClient.query("LISTEN update"));
|
|
1734
|
+
promises.push(this.triggerClient.query("LISTEN delete"));
|
|
1735
|
+
await Promise.all(promises);
|
|
1736
|
+
this.triggerClient.on("notification", async (msg) => {
|
|
1737
|
+
if (msg.channel === "insert" || msg.channel === "update" || msg.channel === "delete") {
|
|
1738
|
+
const payload = JSON.parse(msg.payload);
|
|
1739
|
+
await this.handleTrigger(payload, msg.channel.toUpperCase());
|
|
1740
|
+
}
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1743
|
+
async handleTrigger(payload, mutationType) {
|
|
1744
|
+
const findRequesterDetailsRegex = /^--QUERY_METADATA\(\{.*\}\)/;
|
|
1745
|
+
let requesterDetails = {};
|
|
1746
|
+
const match = payload.query.match(findRequesterDetailsRegex);
|
|
1747
|
+
if (match) {
|
|
1748
|
+
const jsonString = match[0].slice(match[0].indexOf("{"), match[0].lastIndexOf("}") + 1);
|
|
1749
|
+
requesterDetails = import_core_utils5.ObjectUtils.safeParse(jsonString);
|
|
1750
|
+
await eventManager_default.fireActionFromDbTrigger({ requesterDetails, mutationType }, payload);
|
|
1751
|
+
}
|
|
1594
1752
|
}
|
|
1595
1753
|
async createDatabaseFromSchema(schema, connection) {
|
|
1596
1754
|
const sqlFullStatement = this.generateDatabaseSchemaFromSchema(schema);
|
|
@@ -1601,7 +1759,11 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1601
1759
|
const sqlStatements = [];
|
|
1602
1760
|
const enums = [];
|
|
1603
1761
|
const indexes = [];
|
|
1762
|
+
const triggers = [];
|
|
1604
1763
|
for (const table of schema.database) {
|
|
1764
|
+
triggers.push(this.createInsertTriggers(table.name));
|
|
1765
|
+
triggers.push(this.createUpdateTrigger(table.name));
|
|
1766
|
+
triggers.push(this.createDeleteTrigger(table.name));
|
|
1605
1767
|
let sql = `CREATE TABLE "${table.name}"
|
|
1606
1768
|
( `;
|
|
1607
1769
|
const tableColumns = [];
|
|
@@ -1628,7 +1790,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1628
1790
|
}
|
|
1629
1791
|
if (column.isNullable) columnSql += " NULL";
|
|
1630
1792
|
else columnSql += " NOT NULL";
|
|
1631
|
-
if (column.default) columnSql += ` DEFAULT
|
|
1793
|
+
if (column.default) columnSql += ` DEFAULT ${column.default}`;
|
|
1632
1794
|
tableColumns.push(columnSql);
|
|
1633
1795
|
}
|
|
1634
1796
|
sql += tableColumns.join(", \n");
|
|
@@ -1639,7 +1801,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1639
1801
|
indexes.push(
|
|
1640
1802
|
` CREATE ${unique}INDEX "${index.name}" ON "${table.name}" (${index.columns.map((item) => {
|
|
1641
1803
|
return `"${item}" ${index.order}`;
|
|
1642
|
-
}).join(", ")})
|
|
1804
|
+
}).join(", ")});`
|
|
1643
1805
|
);
|
|
1644
1806
|
}
|
|
1645
1807
|
}
|
|
@@ -1669,7 +1831,8 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1669
1831
|
}
|
|
1670
1832
|
sqlStatements.push(sql + constraints.join(",\n") + ";");
|
|
1671
1833
|
}
|
|
1672
|
-
sqlStatements.push(indexes.join("
|
|
1834
|
+
sqlStatements.push(indexes.join("\n"));
|
|
1835
|
+
sqlStatements.push(triggers.join("\n"));
|
|
1673
1836
|
return enums.join("\n") + "\n" + sqlStatements.join("\n\n");
|
|
1674
1837
|
}
|
|
1675
1838
|
async getScratchPool() {
|
|
@@ -1715,12 +1878,10 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1715
1878
|
await originalClient.connect();
|
|
1716
1879
|
await scratchClient.connect();
|
|
1717
1880
|
const info1 = await (0, import_pg_info.default)({
|
|
1718
|
-
client: originalClient
|
|
1719
|
-
schema: "public"
|
|
1881
|
+
client: originalClient
|
|
1720
1882
|
});
|
|
1721
1883
|
const info2 = await (0, import_pg_info.default)({
|
|
1722
|
-
client: scratchClient
|
|
1723
|
-
schema: "public"
|
|
1884
|
+
client: scratchClient
|
|
1724
1885
|
});
|
|
1725
1886
|
const diff = (0, import_pg_diff_sync.default)(info1, info2);
|
|
1726
1887
|
await originalClient.end();
|
|
@@ -1739,8 +1900,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1739
1900
|
)) {
|
|
1740
1901
|
return "'[]'";
|
|
1741
1902
|
}
|
|
1742
|
-
return `COALESCE((
|
|
1743
|
-
SELECT JSON_AGG(JSON_BUILD_OBJECT(
|
|
1903
|
+
return `COALESCE((SELECT JSON_AGG(JSON_BUILD_OBJECT(
|
|
1744
1904
|
${item.subquery.properties.map((nestedItem) => {
|
|
1745
1905
|
if (!this.doesRoleHavePermissionToColumn(req.requesterDetails.role, schema, nestedItem, [
|
|
1746
1906
|
...routeData.joins,
|
|
@@ -1749,7 +1909,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1749
1909
|
return;
|
|
1750
1910
|
}
|
|
1751
1911
|
if (nestedItem.subquery) {
|
|
1752
|
-
return `
|
|
1912
|
+
return `'${nestedItem.name}', ${this.createNestedSelect(
|
|
1753
1913
|
// recursion
|
|
1754
1914
|
req,
|
|
1755
1915
|
schema,
|
|
@@ -1760,7 +1920,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1760
1920
|
)}`;
|
|
1761
1921
|
}
|
|
1762
1922
|
return `'${nestedItem.name}', ${escapeColumnName(nestedItem.selector)}`;
|
|
1763
|
-
}).filter(Boolean).join(",")}
|
|
1923
|
+
}).filter(Boolean).join(", ")}
|
|
1764
1924
|
))
|
|
1765
1925
|
FROM
|
|
1766
1926
|
"${item.subquery.table}"
|
|
@@ -1888,10 +2048,12 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1888
2048
|
req.requesterDetails.role,
|
|
1889
2049
|
sqlParams
|
|
1890
2050
|
);
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
2051
|
+
const whereClause = this.generateWhereClause(req, routeData.where, routeData, sqlParams);
|
|
2052
|
+
if (whereClause.replace(/\s/g, "") === "") {
|
|
2053
|
+
throw new RsError("DELETE_FORBIDDEN", "Deletes need a where clause");
|
|
2054
|
+
}
|
|
2055
|
+
const deleteStatement = `
|
|
2056
|
+
DELETE FROM "${routeData.table}" ${joinStatement} ${whereClause}`;
|
|
1895
2057
|
await this.psqlConnectionPool.runQuery(deleteStatement, sqlParams, req.requesterDetails);
|
|
1896
2058
|
return true;
|
|
1897
2059
|
}
|
|
@@ -1954,17 +2116,17 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1954
2116
|
);
|
|
1955
2117
|
let operator = item.operator;
|
|
1956
2118
|
if (operator === "LIKE") {
|
|
1957
|
-
|
|
2119
|
+
item.value = `%${item.value}%`;
|
|
1958
2120
|
} else if (operator === "STARTS WITH") {
|
|
1959
2121
|
operator = "LIKE";
|
|
1960
|
-
|
|
2122
|
+
item.value = `${item.value}%`;
|
|
1961
2123
|
} else if (operator === "ENDS WITH") {
|
|
1962
2124
|
operator = "LIKE";
|
|
1963
|
-
|
|
2125
|
+
item.value = `%${item.value}`;
|
|
1964
2126
|
}
|
|
1965
2127
|
const replacedValue = this.replaceParamKeywords(item.value, routeData, req, sqlParams);
|
|
1966
2128
|
const escapedValue = SQL`${replacedValue}`;
|
|
1967
|
-
whereClause += ` ${item.conjunction || ""} "${item.tableName}"."${item.columnName}" ${operator} ${["IN", "NOT IN"].includes(operator) ? `(${escapedValue})` : escapedValue}
|
|
2129
|
+
whereClause += ` ${item.conjunction || ""} "${item.tableName}"."${item.columnName}" ${operator.replace("LIKE", "ILIKE")} ${["IN", "NOT IN"].includes(operator) ? `(${escapedValue})` : escapedValue}
|
|
1968
2130
|
`;
|
|
1969
2131
|
});
|
|
1970
2132
|
const data = req.data;
|
|
@@ -1998,63 +2160,94 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1998
2160
|
}
|
|
1999
2161
|
return whereClause;
|
|
2000
2162
|
}
|
|
2163
|
+
createUpdateTrigger(tableName) {
|
|
2164
|
+
return `
|
|
2165
|
+
CREATE OR REPLACE FUNCTION notify_${tableName}_update()
|
|
2166
|
+
RETURNS TRIGGER AS $$
|
|
2167
|
+
BEGIN
|
|
2168
|
+
PERFORM pg_notify('update', JSON_BUILD_OBJECT('table', '${tableName}', 'query', current_query(), 'record', NEW, 'previousRecord', OLD)::text);
|
|
2169
|
+
RETURN NEW;
|
|
2170
|
+
END;
|
|
2171
|
+
$$ LANGUAGE plpgsql;
|
|
2172
|
+
|
|
2173
|
+
CREATE OR REPLACE TRIGGER ${tableName}_update
|
|
2174
|
+
AFTER UPDATE ON "${tableName}"
|
|
2175
|
+
FOR EACH ROW
|
|
2176
|
+
EXECUTE FUNCTION notify_${tableName}_update();
|
|
2177
|
+
`;
|
|
2178
|
+
}
|
|
2179
|
+
createDeleteTrigger(tableName) {
|
|
2180
|
+
return `
|
|
2181
|
+
CREATE OR REPLACE FUNCTION notify_${tableName}_delete()
|
|
2182
|
+
RETURNS TRIGGER AS $$
|
|
2183
|
+
BEGIN
|
|
2184
|
+
PERFORM pg_notify('delete', JSON_BUILD_OBJECT('table', '${tableName}', 'query', current_query(), 'record', NEW, 'previousRecord', OLD)::text);
|
|
2185
|
+
RETURN NEW;
|
|
2186
|
+
END;
|
|
2187
|
+
$$ LANGUAGE plpgsql;
|
|
2188
|
+
|
|
2189
|
+
CREATE OR REPLACE TRIGGER "${tableName}_delete"
|
|
2190
|
+
AFTER DELETE ON "${tableName}"
|
|
2191
|
+
FOR EACH ROW
|
|
2192
|
+
EXECUTE FUNCTION notify_${tableName}_delete();
|
|
2193
|
+
`;
|
|
2194
|
+
}
|
|
2195
|
+
createInsertTriggers(tableName) {
|
|
2196
|
+
return `
|
|
2197
|
+
CREATE OR REPLACE FUNCTION notify_${tableName}_insert()
|
|
2198
|
+
RETURNS TRIGGER AS $$
|
|
2199
|
+
BEGIN
|
|
2200
|
+
PERFORM pg_notify('insert', JSON_BUILD_OBJECT('table', '${tableName}', 'query', current_query(), 'record', NEW, 'previousRecord', OLD)::text);
|
|
2201
|
+
RETURN NEW;
|
|
2202
|
+
END;
|
|
2203
|
+
$$ LANGUAGE plpgsql;
|
|
2204
|
+
|
|
2205
|
+
CREATE TRIGGER "${tableName}_insert"
|
|
2206
|
+
AFTER INSERT ON "${tableName}"
|
|
2207
|
+
FOR EACH ROW
|
|
2208
|
+
EXECUTE FUNCTION notify_${tableName}_insert();
|
|
2209
|
+
`;
|
|
2210
|
+
}
|
|
2001
2211
|
};
|
|
2002
|
-
|
|
2212
|
+
__decorateClass([
|
|
2213
|
+
boundMethod
|
|
2214
|
+
], PsqlEngine.prototype, "handleTrigger", 1);
|
|
2215
|
+
__decorateClass([
|
|
2216
|
+
boundMethod
|
|
2217
|
+
], PsqlEngine.prototype, "createUpdateTrigger", 1);
|
|
2218
|
+
__decorateClass([
|
|
2219
|
+
boundMethod
|
|
2220
|
+
], PsqlEngine.prototype, "createDeleteTrigger", 1);
|
|
2221
|
+
__decorateClass([
|
|
2222
|
+
boundMethod
|
|
2223
|
+
], PsqlEngine.prototype, "createInsertTriggers", 1);
|
|
2224
|
+
function schemaToPsqlType(column, tableName) {
|
|
2003
2225
|
if (column.hasAutoIncrement) return "BIGSERIAL";
|
|
2004
2226
|
if (column.type === "ENUM") return `"${tableName}_${column.name}_enum"`;
|
|
2005
2227
|
if (column.type === "DATETIME") return "TIMESTAMPTZ";
|
|
2006
2228
|
if (column.type === "MEDIUMINT") return "INT";
|
|
2007
2229
|
return column.type;
|
|
2008
|
-
}
|
|
2009
|
-
|
|
2010
|
-
// src/restura/sql/PsqlTransaction.ts
|
|
2011
|
-
var import_pg2 = __toESM(require("pg"));
|
|
2012
|
-
var { Client: Client2 } = import_pg2.default;
|
|
2013
|
-
var PsqlTransaction = class extends PsqlConnection {
|
|
2014
|
-
constructor(clientConfig) {
|
|
2015
|
-
super();
|
|
2016
|
-
this.clientConfig = clientConfig;
|
|
2017
|
-
this.client = new Client2(clientConfig);
|
|
2018
|
-
this.beginTransactionPromise = this.beginTransaction();
|
|
2019
|
-
}
|
|
2020
|
-
async beginTransaction() {
|
|
2021
|
-
return this.query("BEGIN");
|
|
2022
|
-
}
|
|
2023
|
-
async rollback() {
|
|
2024
|
-
return this.query("ROLLBACK");
|
|
2025
|
-
}
|
|
2026
|
-
async commit() {
|
|
2027
|
-
return this.query("COMMIT");
|
|
2028
|
-
}
|
|
2029
|
-
async release() {
|
|
2030
|
-
return this.client.end();
|
|
2031
|
-
}
|
|
2032
|
-
async query(query, values) {
|
|
2033
|
-
await this.client.connect();
|
|
2034
|
-
await this.beginTransactionPromise;
|
|
2035
|
-
return this.client.query(query, values);
|
|
2036
|
-
}
|
|
2037
|
-
};
|
|
2230
|
+
}
|
|
2038
2231
|
|
|
2039
2232
|
// src/restura/compareSchema.ts
|
|
2040
2233
|
var import_lodash = __toESM(require("lodash.clonedeep"));
|
|
2041
2234
|
var CompareSchema = class {
|
|
2042
2235
|
async diffSchema(newSchema, latestSchema, psqlEngine) {
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2236
|
+
const endPoints = this.diffEndPoints(newSchema.endpoints[0].routes, latestSchema.endpoints[0].routes);
|
|
2237
|
+
const globalParams = this.diffStringArray(newSchema.globalParams, latestSchema.globalParams);
|
|
2238
|
+
const roles = this.diffStringArray(newSchema.roles, latestSchema.roles);
|
|
2046
2239
|
let commands = "";
|
|
2047
2240
|
if (JSON.stringify(newSchema.database) !== JSON.stringify(latestSchema.database))
|
|
2048
2241
|
commands = await psqlEngine.diffDatabaseToSchema(newSchema);
|
|
2049
|
-
|
|
2242
|
+
const customTypes = newSchema.customTypes !== latestSchema.customTypes;
|
|
2050
2243
|
const schemaPreview = { endPoints, globalParams, roles, commands, customTypes };
|
|
2051
2244
|
return schemaPreview;
|
|
2052
2245
|
}
|
|
2053
2246
|
diffStringArray(newArray, originalArray) {
|
|
2054
|
-
|
|
2055
|
-
|
|
2247
|
+
const stringsDiff = [];
|
|
2248
|
+
const originalClone = new Set(originalArray);
|
|
2056
2249
|
newArray.forEach((item) => {
|
|
2057
|
-
|
|
2250
|
+
const originalIndex = originalClone.has(item);
|
|
2058
2251
|
if (!originalIndex) {
|
|
2059
2252
|
stringsDiff.push({
|
|
2060
2253
|
name: item,
|
|
@@ -2073,11 +2266,11 @@ var CompareSchema = class {
|
|
|
2073
2266
|
return stringsDiff;
|
|
2074
2267
|
}
|
|
2075
2268
|
diffEndPoints(newEndPoints, originalEndpoints) {
|
|
2076
|
-
|
|
2077
|
-
|
|
2269
|
+
const originalClone = (0, import_lodash.default)(originalEndpoints);
|
|
2270
|
+
const diffObj = [];
|
|
2078
2271
|
newEndPoints.forEach((endPoint) => {
|
|
2079
|
-
|
|
2080
|
-
|
|
2272
|
+
const { path: path4, method } = endPoint;
|
|
2273
|
+
const endPointIndex = originalClone.findIndex((original) => {
|
|
2081
2274
|
return original.path === endPoint.path && original.method === endPoint.method;
|
|
2082
2275
|
});
|
|
2083
2276
|
if (endPointIndex === -1) {
|
|
@@ -2086,7 +2279,7 @@ var CompareSchema = class {
|
|
|
2086
2279
|
changeType: "NEW"
|
|
2087
2280
|
});
|
|
2088
2281
|
} else {
|
|
2089
|
-
|
|
2282
|
+
const original = originalClone.findIndex((original2) => {
|
|
2090
2283
|
return this.compareEndPoints(endPoint, original2);
|
|
2091
2284
|
});
|
|
2092
2285
|
if (original === -1) {
|
|
@@ -2099,7 +2292,7 @@ var CompareSchema = class {
|
|
|
2099
2292
|
}
|
|
2100
2293
|
});
|
|
2101
2294
|
originalClone.forEach((original) => {
|
|
2102
|
-
|
|
2295
|
+
const { path: path4, method } = original;
|
|
2103
2296
|
diffObj.push({
|
|
2104
2297
|
name: `${method} ${path4}`,
|
|
2105
2298
|
changeType: "DELETED"
|
|
@@ -2502,12 +2695,14 @@ var setupPgReturnTypes = () => {
|
|
|
2502
2695
|
};
|
|
2503
2696
|
setupPgReturnTypes();
|
|
2504
2697
|
var restura = new ResturaEngine();
|
|
2698
|
+
|
|
2699
|
+
// src/restura/sql/PsqlTransaction.ts
|
|
2700
|
+
var import_pg4 = __toESM(require("pg"));
|
|
2701
|
+
var { Client: Client2 } = import_pg4.default;
|
|
2505
2702
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2506
2703
|
0 && (module.exports = {
|
|
2507
2704
|
HtmlStatusCodes,
|
|
2508
|
-
PsqlConnection,
|
|
2509
2705
|
PsqlPool,
|
|
2510
|
-
PsqlTransaction,
|
|
2511
2706
|
RsError,
|
|
2512
2707
|
SQL,
|
|
2513
2708
|
escapeColumnName,
|