@restura/core 0.1.0-alpha.20 → 0.1.0-alpha.21
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 +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +90 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +88 -39
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1283,14 +1283,17 @@ function SQL(strings, ...values) {
|
|
|
1283
1283
|
}
|
|
1284
1284
|
|
|
1285
1285
|
// src/restura/sql/PsqlConnection.ts
|
|
1286
|
+
import crypto from "crypto";
|
|
1286
1287
|
var PsqlConnection = class {
|
|
1287
1288
|
constructor() {
|
|
1289
|
+
this.instanceId = crypto.randomUUID();
|
|
1288
1290
|
}
|
|
1289
1291
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1290
1292
|
async queryOne(query, options, requesterDetails) {
|
|
1291
1293
|
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1292
|
-
this.
|
|
1293
|
-
|
|
1294
|
+
const meta = __spreadValues({ connectionInstanceId: this.instanceId }, requesterDetails);
|
|
1295
|
+
this.logSqlStatement(formattedQuery, options, meta);
|
|
1296
|
+
const queryMetadata = `--QUERY_METADATA(${JSON.stringify(meta)})
|
|
1294
1297
|
`;
|
|
1295
1298
|
try {
|
|
1296
1299
|
const response = await this.query(queryMetadata + formattedQuery, options);
|
|
@@ -1309,8 +1312,9 @@ var PsqlConnection = class {
|
|
|
1309
1312
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1310
1313
|
async runQuery(query, options, requesterDetails) {
|
|
1311
1314
|
const formattedQuery = questionMarksToOrderedParams(query);
|
|
1312
|
-
this.
|
|
1313
|
-
|
|
1315
|
+
const meta = __spreadValues({ connectionInstanceId: this.instanceId }, requesterDetails);
|
|
1316
|
+
this.logSqlStatement(formattedQuery, options, meta);
|
|
1317
|
+
const queryMetadata = `--QUERY_METADATA(${JSON.stringify(meta)})
|
|
1314
1318
|
`;
|
|
1315
1319
|
try {
|
|
1316
1320
|
const response = await this.query(queryMetadata + formattedQuery, options);
|
|
@@ -1323,7 +1327,7 @@ var PsqlConnection = class {
|
|
|
1323
1327
|
throw new RsError("DATABASE_ERROR", `${error.message}`);
|
|
1324
1328
|
}
|
|
1325
1329
|
}
|
|
1326
|
-
logSqlStatement(query, options,
|
|
1330
|
+
logSqlStatement(query, options, queryMetadata, prefix = "") {
|
|
1327
1331
|
if (logger.level !== "silly") return;
|
|
1328
1332
|
let sqlStatement = "";
|
|
1329
1333
|
if (options.length === 0) {
|
|
@@ -1337,9 +1341,9 @@ var PsqlConnection = class {
|
|
|
1337
1341
|
});
|
|
1338
1342
|
}
|
|
1339
1343
|
let initiator = "Anonymous";
|
|
1340
|
-
if ("userId" in
|
|
1341
|
-
initiator = `User Id (${
|
|
1342
|
-
if ("isSystemUser" in
|
|
1344
|
+
if ("userId" in queryMetadata && queryMetadata.userId)
|
|
1345
|
+
initiator = `User Id (${queryMetadata.userId.toString()})`;
|
|
1346
|
+
if ("isSystemUser" in queryMetadata && queryMetadata.isSystemUser) initiator = "SYSTEM";
|
|
1343
1347
|
logger.silly(`${prefix}query by ${initiator}, Query ->
|
|
1344
1348
|
${sqlStatement}`);
|
|
1345
1349
|
}
|
|
@@ -1521,13 +1525,15 @@ var filterSqlGrammar = `
|
|
|
1521
1525
|
|
|
1522
1526
|
start = expressionList
|
|
1523
1527
|
|
|
1528
|
+
_ = [ \\t\\r\\n]* // Matches spaces, tabs, and line breaks
|
|
1529
|
+
|
|
1524
1530
|
expressionList =
|
|
1525
|
-
|
|
1531
|
+
leftExpression:expression _ operator:operator _ rightExpression:expressionList
|
|
1526
1532
|
{ return \`\${leftExpression} \${operator} \${rightExpression}\`;}
|
|
1527
1533
|
/ expression
|
|
1528
1534
|
|
|
1529
1535
|
expression =
|
|
1530
|
-
negate:negate?"(" "column:"
|
|
1536
|
+
negate:negate? _ "(" _ "column" _ ":" column:column _ ","? _ value:value? ","? _ type:type? _ ")"_
|
|
1531
1537
|
{return \`\${negate? " NOT " : ""}(\${type? type(column, value) : \`\${column} = \${format.literal(value)}\`})\`;}
|
|
1532
1538
|
/
|
|
1533
1539
|
negate:negate?"("expression:expressionList")" { return \`\${negate? " NOT " : ""}(\${expression})\`; }
|
|
@@ -1542,9 +1548,9 @@ column = left:text "." right:text { return \`\${quoteSqlIdentity(left)}.\${quot
|
|
|
1542
1548
|
text:text { return quoteSqlIdentity(text); }
|
|
1543
1549
|
|
|
1544
1550
|
|
|
1545
|
-
text = text:[a-z0-9
|
|
1551
|
+
text = text:[a-z0-9 \\t\\r\\n\\-_:@]i+ { return text.join(""); }
|
|
1546
1552
|
|
|
1547
|
-
type = "type:" type:typeString { return type; }
|
|
1553
|
+
type = "type" _ ":" _ type:typeString { return type; }
|
|
1548
1554
|
typeString = text:"startsWith" { return function(column, value) { return \`\${column} ILIKE '\${format.literal(value).slice(1,-1)}%'\`; } } /
|
|
1549
1555
|
text:"endsWith" { return function(column, value) { return \`\${column} ILIKE '%\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1550
1556
|
text:"contains" { return function(column, value) { return \`\${column} ILIKE '%\${format.literal(value).slice(1,-1)}%'\`; } } /
|
|
@@ -1554,8 +1560,9 @@ typeString = text:"startsWith" { return function(column, value) { return \`\${co
|
|
|
1554
1560
|
text:"lessThanEqual" { return function(column, value) { return \`\${column} <= '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1555
1561
|
text:"lessThan" { return function(column, value) { return \`\${column} < '\${format.literal(value).slice(1,-1)}'\`; } } /
|
|
1556
1562
|
text:"isNull" { return function(column, value) { return \`isNull(\${column})\`; } }
|
|
1557
|
-
|
|
1558
|
-
value = "value:" value:text { return value; }
|
|
1563
|
+
|
|
1564
|
+
value = "value" _ ":" value:text { return value; }
|
|
1565
|
+
|
|
1559
1566
|
|
|
1560
1567
|
`;
|
|
1561
1568
|
var filterPsqlParser = peg.generate(filterSqlGrammar, {
|
|
@@ -1610,9 +1617,9 @@ var EventManager = class {
|
|
|
1610
1617
|
tableName: triggerResult.table,
|
|
1611
1618
|
insertId: triggerResult.record.id,
|
|
1612
1619
|
insertObject: triggerResult.record,
|
|
1613
|
-
|
|
1620
|
+
queryMetadata: data.queryMetadata
|
|
1614
1621
|
};
|
|
1615
|
-
callback(insertData, data.
|
|
1622
|
+
callback(insertData, data.queryMetadata);
|
|
1616
1623
|
},
|
|
1617
1624
|
{ concurrency: 10 }
|
|
1618
1625
|
);
|
|
@@ -1625,9 +1632,9 @@ var EventManager = class {
|
|
|
1625
1632
|
const deleteData = {
|
|
1626
1633
|
tableName: triggerResult.table,
|
|
1627
1634
|
deletedRow: triggerResult.previousRecord,
|
|
1628
|
-
|
|
1635
|
+
queryMetadata: data.queryMetadata
|
|
1629
1636
|
};
|
|
1630
|
-
callback(deleteData, data.
|
|
1637
|
+
callback(deleteData, data.queryMetadata);
|
|
1631
1638
|
},
|
|
1632
1639
|
{ concurrency: 10 }
|
|
1633
1640
|
);
|
|
@@ -1642,9 +1649,9 @@ var EventManager = class {
|
|
|
1642
1649
|
rowId: triggerResult.record.id,
|
|
1643
1650
|
newData: triggerResult.record,
|
|
1644
1651
|
oldData: triggerResult.previousRecord,
|
|
1645
|
-
|
|
1652
|
+
queryMetadata: data.queryMetadata
|
|
1646
1653
|
};
|
|
1647
|
-
callback(columnChangeData, data.
|
|
1654
|
+
callback(columnChangeData, data.queryMetadata);
|
|
1648
1655
|
},
|
|
1649
1656
|
{ concurrency: 10 }
|
|
1650
1657
|
);
|
|
@@ -1659,6 +1666,13 @@ var EventManager = class {
|
|
|
1659
1666
|
case "DATABASE_COLUMN_UPDATE":
|
|
1660
1667
|
const filterColumnChange = filter;
|
|
1661
1668
|
if (filterColumnChange.tableName !== filter.tableName) return false;
|
|
1669
|
+
if (!filterColumnChange.columns.some((item) => {
|
|
1670
|
+
const updatedColumns = Object.keys(
|
|
1671
|
+
changedValues(triggerResult.record, triggerResult.previousRecord)
|
|
1672
|
+
);
|
|
1673
|
+
return updatedColumns.includes(item);
|
|
1674
|
+
}))
|
|
1675
|
+
return false;
|
|
1662
1676
|
break;
|
|
1663
1677
|
}
|
|
1664
1678
|
}
|
|
@@ -1667,6 +1681,22 @@ var EventManager = class {
|
|
|
1667
1681
|
};
|
|
1668
1682
|
var eventManager = new EventManager();
|
|
1669
1683
|
var eventManager_default = eventManager;
|
|
1684
|
+
function changedValues(record, previousRecord) {
|
|
1685
|
+
const changed = {};
|
|
1686
|
+
for (const i in previousRecord) {
|
|
1687
|
+
if (previousRecord[i] !== record[i]) {
|
|
1688
|
+
if (typeof previousRecord[i] === "object" && typeof record[i] === "object") {
|
|
1689
|
+
const nestedChanged = changedValues(record[i], previousRecord[i]);
|
|
1690
|
+
if (Object.keys(nestedChanged).length > 0) {
|
|
1691
|
+
changed[i] = record[i];
|
|
1692
|
+
}
|
|
1693
|
+
} else {
|
|
1694
|
+
changed[i] = record[i];
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
return changed;
|
|
1699
|
+
}
|
|
1670
1700
|
|
|
1671
1701
|
// src/restura/sql/PsqlEngine.ts
|
|
1672
1702
|
var { Client } = pg2;
|
|
@@ -1713,12 +1743,15 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1713
1743
|
}
|
|
1714
1744
|
async handleTrigger(payload, mutationType) {
|
|
1715
1745
|
const findRequesterDetailsRegex = /^--QUERY_METADATA\(\{.*\}\)/;
|
|
1716
|
-
let requesterDetails = {};
|
|
1717
1746
|
const match = payload.query.match(findRequesterDetailsRegex);
|
|
1718
1747
|
if (match) {
|
|
1719
1748
|
const jsonString = match[0].slice(match[0].indexOf("{"), match[0].lastIndexOf("}") + 1);
|
|
1720
|
-
|
|
1721
|
-
|
|
1749
|
+
const queryMetadata = ObjectUtils4.safeParse(jsonString);
|
|
1750
|
+
const triggerFromThisInstance = queryMetadata.connectionInstanceId === this.psqlConnectionPool.instanceId;
|
|
1751
|
+
if (!triggerFromThisInstance) {
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
await eventManager_default.fireActionFromDbTrigger({ queryMetadata, mutationType }, payload);
|
|
1722
1755
|
}
|
|
1723
1756
|
}
|
|
1724
1757
|
async createDatabaseFromSchema(schema, connection) {
|
|
@@ -1728,7 +1761,6 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1728
1761
|
}
|
|
1729
1762
|
generateDatabaseSchemaFromSchema(schema) {
|
|
1730
1763
|
const sqlStatements = [];
|
|
1731
|
-
const enums = [];
|
|
1732
1764
|
const indexes = [];
|
|
1733
1765
|
const triggers = [];
|
|
1734
1766
|
for (const table of schema.database) {
|
|
@@ -1740,10 +1772,7 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1740
1772
|
const tableColumns = [];
|
|
1741
1773
|
for (const column of table.columns) {
|
|
1742
1774
|
let columnSql = "";
|
|
1743
|
-
|
|
1744
|
-
enums.push(`CREATE TYPE ${schemaToPsqlType(column, table.name)} AS ENUM (${column.value});`);
|
|
1745
|
-
}
|
|
1746
|
-
columnSql += ` "${column.name}" ${schemaToPsqlType(column, table.name)}`;
|
|
1775
|
+
columnSql += ` "${column.name}" ${schemaToPsqlType(column)}`;
|
|
1747
1776
|
let value = column.value;
|
|
1748
1777
|
if (column.type === "JSON") value = "";
|
|
1749
1778
|
if (column.type === "JSONB") value = "";
|
|
@@ -1762,6 +1791,9 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1762
1791
|
if (column.isNullable) columnSql += " NULL";
|
|
1763
1792
|
else columnSql += " NOT NULL";
|
|
1764
1793
|
if (column.default) columnSql += ` DEFAULT ${column.default}`;
|
|
1794
|
+
if (value && column.type === "ENUM") {
|
|
1795
|
+
columnSql += ` CHECK ("${column.name}" IN (${value}))`;
|
|
1796
|
+
}
|
|
1765
1797
|
tableColumns.push(columnSql);
|
|
1766
1798
|
}
|
|
1767
1799
|
sql += tableColumns.join(", \n");
|
|
@@ -1804,16 +1836,18 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1804
1836
|
}
|
|
1805
1837
|
sqlStatements.push(indexes.join("\n"));
|
|
1806
1838
|
sqlStatements.push(triggers.join("\n"));
|
|
1807
|
-
return
|
|
1839
|
+
return sqlStatements.join("\n\n");
|
|
1808
1840
|
}
|
|
1809
1841
|
async getScratchPool() {
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1842
|
+
var _a2, _b;
|
|
1843
|
+
const scratchDbExists = await this.psqlConnectionPool.runQuery(
|
|
1844
|
+
`SELECT *
|
|
1845
|
+
FROM pg_database
|
|
1846
|
+
WHERE datname = '${this.psqlConnectionPool.poolConfig.database}_scratch';`,
|
|
1813
1847
|
[],
|
|
1814
1848
|
systemUser
|
|
1815
1849
|
);
|
|
1816
|
-
if (
|
|
1850
|
+
if (scratchDbExists.length === 0) {
|
|
1817
1851
|
await this.psqlConnectionPool.runQuery(
|
|
1818
1852
|
`CREATE DATABASE ${this.psqlConnectionPool.poolConfig.database}_scratch;`,
|
|
1819
1853
|
[],
|
|
@@ -1830,12 +1864,27 @@ var PsqlEngine = class extends SqlEngine {
|
|
|
1830
1864
|
idleTimeoutMillis: this.psqlConnectionPool.poolConfig.idleTimeoutMillis,
|
|
1831
1865
|
connectionTimeoutMillis: this.psqlConnectionPool.poolConfig.connectionTimeoutMillis
|
|
1832
1866
|
});
|
|
1833
|
-
await scratchPool.runQuery(`
|
|
1867
|
+
await scratchPool.runQuery(`DROP SCHEMA public CASCADE;`, [], systemUser);
|
|
1834
1868
|
await scratchPool.runQuery(
|
|
1835
|
-
`
|
|
1869
|
+
`CREATE SCHEMA public AUTHORIZATION ${this.psqlConnectionPool.poolConfig.user};`,
|
|
1870
|
+
[],
|
|
1871
|
+
systemUser
|
|
1872
|
+
);
|
|
1873
|
+
const schemaComment = await this.psqlConnectionPool.runQuery(
|
|
1874
|
+
`SELECT pg_description.description
|
|
1875
|
+
FROM pg_description
|
|
1876
|
+
JOIN pg_namespace ON pg_namespace.oid = pg_description.objoid
|
|
1877
|
+
WHERE pg_namespace.nspname = 'public';`,
|
|
1836
1878
|
[],
|
|
1837
1879
|
systemUser
|
|
1838
1880
|
);
|
|
1881
|
+
if ((_a2 = schemaComment[0]) == null ? void 0 : _a2.description) {
|
|
1882
|
+
await scratchPool.runQuery(
|
|
1883
|
+
`COMMENT ON SCHEMA public IS '${(_b = schemaComment[0]) == null ? void 0 : _b.description}';`,
|
|
1884
|
+
[],
|
|
1885
|
+
systemUser
|
|
1886
|
+
);
|
|
1887
|
+
}
|
|
1839
1888
|
return scratchPool;
|
|
1840
1889
|
}
|
|
1841
1890
|
async diffDatabaseToSchema(schema) {
|
|
@@ -2205,9 +2254,9 @@ __decorateClass([
|
|
|
2205
2254
|
__decorateClass([
|
|
2206
2255
|
boundMethod
|
|
2207
2256
|
], PsqlEngine.prototype, "createInsertTriggers", 1);
|
|
2208
|
-
function schemaToPsqlType(column
|
|
2257
|
+
function schemaToPsqlType(column) {
|
|
2209
2258
|
if (column.hasAutoIncrement) return "BIGSERIAL";
|
|
2210
|
-
if (column.type === "ENUM") return `
|
|
2259
|
+
if (column.type === "ENUM") return `TEXT`;
|
|
2211
2260
|
if (column.type === "DATETIME") return "TIMESTAMPTZ";
|
|
2212
2261
|
if (column.type === "MEDIUMINT") return "INT";
|
|
2213
2262
|
return column.type;
|
|
@@ -2750,7 +2799,7 @@ __decorateClass([
|
|
|
2750
2799
|
__decorateClass([
|
|
2751
2800
|
boundMethod
|
|
2752
2801
|
], ResturaEngine.prototype, "runCustomRouteLogic", 1);
|
|
2753
|
-
|
|
2802
|
+
function setupPgReturnTypes() {
|
|
2754
2803
|
const TIMESTAMPTZ_OID = 1184;
|
|
2755
2804
|
types.setTypeParser(TIMESTAMPTZ_OID, (val) => {
|
|
2756
2805
|
return val === null ? null : new Date(val).toISOString();
|
|
@@ -2759,7 +2808,7 @@ var setupPgReturnTypes = () => {
|
|
|
2759
2808
|
types.setTypeParser(BIGINT_OID, (val) => {
|
|
2760
2809
|
return val === null ? null : Number(val);
|
|
2761
2810
|
});
|
|
2762
|
-
}
|
|
2811
|
+
}
|
|
2763
2812
|
setupPgReturnTypes();
|
|
2764
2813
|
var restura = new ResturaEngine();
|
|
2765
2814
|
|