pqb 0.23.4 → 0.24.0
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.ts +3936 -3908
- package/dist/index.js +1064 -456
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1065 -457
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -140,13 +140,9 @@ class ColumnType extends orchidCore.ColumnTypeBase {
|
|
|
140
140
|
* ```
|
|
141
141
|
*/
|
|
142
142
|
primaryKey() {
|
|
143
|
-
return orchidCore.setColumnData(
|
|
144
|
-
this,
|
|
145
|
-
"isPrimaryKey",
|
|
146
|
-
true
|
|
147
|
-
);
|
|
143
|
+
return orchidCore.setColumnData(this, "isPrimaryKey", true);
|
|
148
144
|
}
|
|
149
|
-
foreignKey(fnOrTable, column, options =
|
|
145
|
+
foreignKey(fnOrTable, column, options = orchidCore.emptyObject) {
|
|
150
146
|
const item = typeof fnOrTable === "string" ? __spreadValues$g({ table: fnOrTable, columns: [column] }, options) : __spreadValues$g({ fn: fnOrTable, columns: [column] }, options);
|
|
151
147
|
return orchidCore.pushColumnData(this, "foreignKeys", item);
|
|
152
148
|
}
|
|
@@ -729,7 +725,7 @@ const columnToSqlWithAs = (ctx, data, column, quotedAs, select) => {
|
|
|
729
725
|
const col = data.shape[column];
|
|
730
726
|
if (col) {
|
|
731
727
|
if (col.data.name && col.data.name !== column) {
|
|
732
|
-
return `${quotedAs ? `${quotedAs}.` : ""}"${col.data.name}"
|
|
728
|
+
return `${quotedAs ? `${quotedAs}.` : ""}"${col.data.name}" "${column}"`;
|
|
733
729
|
}
|
|
734
730
|
if (col.data.computed) {
|
|
735
731
|
return `${col.data.computed.toSQL(ctx, quotedAs)} "${column}"`;
|
|
@@ -740,7 +736,7 @@ const columnToSqlWithAs = (ctx, data, column, quotedAs, select) => {
|
|
|
740
736
|
const ownColumnToSql = (data, column, quotedAs) => {
|
|
741
737
|
var _a;
|
|
742
738
|
const name = (_a = data.shape[column]) == null ? void 0 : _a.data.name;
|
|
743
|
-
return `${quotedAs ? `${quotedAs}.` : ""}"${name || column}"${name && name !== column ? `
|
|
739
|
+
return `${quotedAs ? `${quotedAs}.` : ""}"${name || column}"${name && name !== column ? ` "${column}"` : ""}`;
|
|
744
740
|
};
|
|
745
741
|
const rawOrColumnToSql = (ctx, data, expr, quotedAs, shape = data.shape, select) => {
|
|
746
742
|
return typeof expr === "string" ? columnToSql(ctx, data, shape, expr, quotedAs, select) : expr.toSQL(ctx, quotedAs);
|
|
@@ -832,7 +828,7 @@ class JSONColumn extends ColumnType {
|
|
|
832
828
|
JSONColumn.prototype.encodeFn = JSON.stringify;
|
|
833
829
|
class JSONTextColumn extends ColumnType {
|
|
834
830
|
constructor(schema) {
|
|
835
|
-
super(schema, schema.
|
|
831
|
+
super(schema, schema.stringSchema);
|
|
836
832
|
this.dataType = "json";
|
|
837
833
|
this.operators = Operators.text;
|
|
838
834
|
}
|
|
@@ -1107,8 +1103,7 @@ var __spreadProps$8 = (a, b) => __defProps$8(a, __getOwnPropDescs$8(b));
|
|
|
1107
1103
|
const processJoinItem = (ctx, table, query, item, quotedAs) => {
|
|
1108
1104
|
let target;
|
|
1109
1105
|
let conditions;
|
|
1110
|
-
const { args } = item;
|
|
1111
|
-
const [first] = args;
|
|
1106
|
+
const { first, args } = item;
|
|
1112
1107
|
if (typeof first === "string") {
|
|
1113
1108
|
if (first in table.relations) {
|
|
1114
1109
|
const { query: toQuery, joinQuery } = table.relations[first].relationConfig;
|
|
@@ -1129,8 +1124,8 @@ const processJoinItem = (ctx, table, query, item, quotedAs) => {
|
|
|
1129
1124
|
and: j.and ? [...j.and] : [],
|
|
1130
1125
|
or: j.or ? [...j.or] : []
|
|
1131
1126
|
};
|
|
1132
|
-
if (args[
|
|
1133
|
-
const arg = args[
|
|
1127
|
+
if (args[0]) {
|
|
1128
|
+
const arg = args[0](
|
|
1134
1129
|
new ctx.queryBuilder.onQueryBuilder(jq, j, table)
|
|
1135
1130
|
).q;
|
|
1136
1131
|
if (arg.and)
|
|
@@ -1207,8 +1202,8 @@ const processJoinItem = (ctx, table, query, item, quotedAs) => {
|
|
|
1207
1202
|
};
|
|
1208
1203
|
const processArgs = (args, ctx, table, query, first, joinAs, joinShape, quotedAs) => {
|
|
1209
1204
|
var _a;
|
|
1210
|
-
if (args.length ===
|
|
1211
|
-
const arg = args[
|
|
1205
|
+
if (args.length === 1) {
|
|
1206
|
+
const arg = args[0];
|
|
1212
1207
|
if (typeof arg === "function") {
|
|
1213
1208
|
const joinedShapes = __spreadProps$8(__spreadValues$e({}, query.joinedShapes), {
|
|
1214
1209
|
[table.q.as || table.table]: table.shape
|
|
@@ -1269,7 +1264,7 @@ const processArgs = (args, ctx, table, query, first, joinAs, joinShape, quotedAs
|
|
|
1269
1264
|
joinShape
|
|
1270
1265
|
);
|
|
1271
1266
|
}
|
|
1272
|
-
} else if (args.length >=
|
|
1267
|
+
} else if (args.length >= 2) {
|
|
1273
1268
|
return getConditionsFor3Or4LengthItem(
|
|
1274
1269
|
ctx,
|
|
1275
1270
|
query,
|
|
@@ -1282,7 +1277,7 @@ const processArgs = (args, ctx, table, query, first, joinAs, joinShape, quotedAs
|
|
|
1282
1277
|
return void 0;
|
|
1283
1278
|
};
|
|
1284
1279
|
const getConditionsFor3Or4LengthItem = (ctx, query, target, quotedAs, args, joinShape) => {
|
|
1285
|
-
const [
|
|
1280
|
+
const [leftColumn, opOrRightColumn, maybeRightColumn] = args;
|
|
1286
1281
|
const op = maybeRightColumn ? opOrRightColumn : "=";
|
|
1287
1282
|
const rightColumn = maybeRightColumn ? maybeRightColumn : opOrRightColumn;
|
|
1288
1283
|
return `${rawOrColumnToSql(
|
|
@@ -1381,17 +1376,16 @@ var __spreadValues$d = (a, b) => {
|
|
|
1381
1376
|
return a;
|
|
1382
1377
|
};
|
|
1383
1378
|
var __spreadProps$7 = (a, b) => __defProps$7(a, __getOwnPropDescs$7(b));
|
|
1384
|
-
const _join = (q, require2, type, args) => {
|
|
1379
|
+
const _join = (q, require2, type, first, args) => {
|
|
1385
1380
|
var _a;
|
|
1386
1381
|
let joinKey;
|
|
1387
1382
|
let shape;
|
|
1388
1383
|
let parsers;
|
|
1389
1384
|
let isSubQuery = false;
|
|
1390
|
-
if (typeof
|
|
1391
|
-
|
|
1392
|
-
|
|
1385
|
+
if (typeof first === "function") {
|
|
1386
|
+
first = first(q.relations);
|
|
1387
|
+
first.joinQueryAfterCallback = first.joinQuery;
|
|
1393
1388
|
}
|
|
1394
|
-
const first = args[0];
|
|
1395
1389
|
if (typeof first === "object") {
|
|
1396
1390
|
isSubQuery = getIsJoinSubQuery(first.q, first.baseQuery.q);
|
|
1397
1391
|
joinKey = first.q.as || first.table;
|
|
@@ -1399,8 +1393,8 @@ const _join = (q, require2, type, args) => {
|
|
|
1399
1393
|
shape = getShapeFromSelect(first, isSubQuery);
|
|
1400
1394
|
parsers = first.q.parsers;
|
|
1401
1395
|
if (isSubQuery) {
|
|
1402
|
-
|
|
1403
|
-
|
|
1396
|
+
first = first.clone();
|
|
1397
|
+
first.shape = shape;
|
|
1404
1398
|
}
|
|
1405
1399
|
}
|
|
1406
1400
|
} else {
|
|
@@ -1430,12 +1424,14 @@ const _join = (q, require2, type, args) => {
|
|
|
1430
1424
|
}
|
|
1431
1425
|
return pushQueryValue(q, "join", {
|
|
1432
1426
|
type,
|
|
1427
|
+
first,
|
|
1433
1428
|
args,
|
|
1434
1429
|
isSubQuery
|
|
1435
1430
|
});
|
|
1436
1431
|
};
|
|
1437
|
-
const _joinLateral = (
|
|
1432
|
+
const _joinLateral = (self, type, arg, cb, as) => {
|
|
1438
1433
|
var _a, _b, _c;
|
|
1434
|
+
const q = self;
|
|
1439
1435
|
let relation;
|
|
1440
1436
|
if (typeof arg === "string") {
|
|
1441
1437
|
relation = q.relations[arg];
|
|
@@ -1478,6 +1474,129 @@ const _joinLateral = (q, type, arg, cb, as) => {
|
|
|
1478
1474
|
]);
|
|
1479
1475
|
};
|
|
1480
1476
|
|
|
1477
|
+
const dateTimeEncode = (input) => {
|
|
1478
|
+
return typeof input === "number" ? new Date(input) : input;
|
|
1479
|
+
};
|
|
1480
|
+
const skipDateMethodsFromToCode = { encodeFn: dateTimeEncode };
|
|
1481
|
+
class DateBaseColumn extends ColumnType {
|
|
1482
|
+
constructor(schema) {
|
|
1483
|
+
super(schema, schema.stringNumberDate);
|
|
1484
|
+
this.operators = Operators.date;
|
|
1485
|
+
this.encodeFn = dateTimeEncode;
|
|
1486
|
+
this.asNumber = schema.dateAsNumber;
|
|
1487
|
+
this.asDate = schema.dateAsDate;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
class DateColumn extends DateBaseColumn {
|
|
1491
|
+
constructor() {
|
|
1492
|
+
super(...arguments);
|
|
1493
|
+
this.dataType = "date";
|
|
1494
|
+
}
|
|
1495
|
+
toCode(t) {
|
|
1496
|
+
return columnCode(
|
|
1497
|
+
this,
|
|
1498
|
+
t,
|
|
1499
|
+
`date()${orchidCore.dateDataToCode(this.data)}`,
|
|
1500
|
+
this.data,
|
|
1501
|
+
skipDateMethodsFromToCode
|
|
1502
|
+
);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
class DateTimeBaseClass extends DateBaseColumn {
|
|
1506
|
+
constructor(schema, dateTimePrecision) {
|
|
1507
|
+
super(schema);
|
|
1508
|
+
this.data.dateTimePrecision = dateTimePrecision;
|
|
1509
|
+
}
|
|
1510
|
+
toSQL() {
|
|
1511
|
+
return orchidCore.joinTruthy(
|
|
1512
|
+
this.dataType,
|
|
1513
|
+
this.data.dateTimePrecision !== void 0 && `(${this.data.dateTimePrecision})`
|
|
1514
|
+
);
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
class DateTimeTzBaseClass extends DateTimeBaseClass {
|
|
1518
|
+
toSQL() {
|
|
1519
|
+
return orchidCore.joinTruthy(
|
|
1520
|
+
this.baseDataType,
|
|
1521
|
+
this.data.dateTimePrecision !== void 0 && `(${this.data.dateTimePrecision})`,
|
|
1522
|
+
" with time zone"
|
|
1523
|
+
);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
const timestampToCode = (self, t) => {
|
|
1527
|
+
const { dateTimePrecision: p } = self.data;
|
|
1528
|
+
return columnCode(
|
|
1529
|
+
self,
|
|
1530
|
+
t,
|
|
1531
|
+
`${self instanceof TimestampColumn ? "timestampNoTZ" : "timestamp"}(${p && p !== 6 ? p : ""})${orchidCore.dateDataToCode(self.data)}`,
|
|
1532
|
+
self.data,
|
|
1533
|
+
skipDateMethodsFromToCode
|
|
1534
|
+
);
|
|
1535
|
+
};
|
|
1536
|
+
class TimestampColumn extends DateTimeBaseClass {
|
|
1537
|
+
constructor() {
|
|
1538
|
+
super(...arguments);
|
|
1539
|
+
this.dataType = "timestamp";
|
|
1540
|
+
}
|
|
1541
|
+
toCode(t) {
|
|
1542
|
+
return timestampToCode(this, t);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
class TimestampTZColumn extends DateTimeTzBaseClass {
|
|
1546
|
+
constructor() {
|
|
1547
|
+
super(...arguments);
|
|
1548
|
+
this.dataType = "timestamptz";
|
|
1549
|
+
this.baseDataType = "timestamp";
|
|
1550
|
+
}
|
|
1551
|
+
toCode(t) {
|
|
1552
|
+
return timestampToCode(this, t);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
class TimeColumn extends ColumnType {
|
|
1556
|
+
constructor(schema, dateTimePrecision) {
|
|
1557
|
+
super(schema, schema.stringSchema);
|
|
1558
|
+
this.dataType = "time";
|
|
1559
|
+
this.operators = Operators.time;
|
|
1560
|
+
this.data.dateTimePrecision = dateTimePrecision;
|
|
1561
|
+
}
|
|
1562
|
+
toCode(t) {
|
|
1563
|
+
const { dateTimePrecision } = this.data;
|
|
1564
|
+
return columnCode(
|
|
1565
|
+
this,
|
|
1566
|
+
t,
|
|
1567
|
+
`time(${dateTimePrecision || ""})${orchidCore.dateDataToCode(this.data)}`,
|
|
1568
|
+
this.data,
|
|
1569
|
+
skipDateMethodsFromToCode
|
|
1570
|
+
);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
class IntervalColumn extends ColumnType {
|
|
1574
|
+
constructor(schema, fields, precision) {
|
|
1575
|
+
super(schema, schema.timeInterval);
|
|
1576
|
+
this.dataType = "interval";
|
|
1577
|
+
this.operators = Operators.date;
|
|
1578
|
+
this.data.fields = fields;
|
|
1579
|
+
this.data.precision = precision;
|
|
1580
|
+
}
|
|
1581
|
+
toCode(t) {
|
|
1582
|
+
const { fields, precision } = this.data;
|
|
1583
|
+
return columnCode(
|
|
1584
|
+
this,
|
|
1585
|
+
t,
|
|
1586
|
+
`interval(${[fields && `'${fields}'`, precision && String(precision)].filter((part) => part).join(", ")})`,
|
|
1587
|
+
this.data,
|
|
1588
|
+
skipDateMethodsFromToCode
|
|
1589
|
+
);
|
|
1590
|
+
}
|
|
1591
|
+
toSQL() {
|
|
1592
|
+
return orchidCore.joinTruthy(
|
|
1593
|
+
this.dataType,
|
|
1594
|
+
this.data.fields && ` ${this.data.fields}`,
|
|
1595
|
+
this.data.precision !== void 0 && ` (${this.data.precision})`
|
|
1596
|
+
);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1481
1600
|
class EnumColumn extends ColumnType {
|
|
1482
1601
|
constructor(schema, enumName, options, schemaType) {
|
|
1483
1602
|
super(schema, schemaType);
|
|
@@ -1636,7 +1755,25 @@ const defaultSchemaConfig = {
|
|
|
1636
1755
|
json() {
|
|
1637
1756
|
return new JSONColumn(defaultSchemaConfig, void 0);
|
|
1638
1757
|
},
|
|
1639
|
-
setErrors: orchidCore.noop
|
|
1758
|
+
setErrors: orchidCore.noop,
|
|
1759
|
+
smallint: () => new SmallIntColumn(defaultSchemaConfig),
|
|
1760
|
+
integer: () => new IntegerColumn(defaultSchemaConfig),
|
|
1761
|
+
real: () => new RealColumn(defaultSchemaConfig),
|
|
1762
|
+
smallSerial: () => new SmallSerialColumn(defaultSchemaConfig),
|
|
1763
|
+
serial: () => new SerialColumn(defaultSchemaConfig),
|
|
1764
|
+
bigint: () => new BigIntColumn(defaultSchemaConfig),
|
|
1765
|
+
decimal: (precision, scale) => new DecimalColumn(defaultSchemaConfig, precision, scale),
|
|
1766
|
+
doublePrecision: () => new DoublePrecisionColumn(defaultSchemaConfig),
|
|
1767
|
+
bigSerial: () => new BigSerialColumn(defaultSchemaConfig),
|
|
1768
|
+
money: () => new MoneyColumn(defaultSchemaConfig),
|
|
1769
|
+
varchar: (limit) => new VarCharColumn(defaultSchemaConfig, limit),
|
|
1770
|
+
char: (limit) => new CharColumn(defaultSchemaConfig, limit),
|
|
1771
|
+
text: (min, max) => new TextColumn(defaultSchemaConfig, min, max),
|
|
1772
|
+
string: (limit) => new StringColumn(defaultSchemaConfig, limit),
|
|
1773
|
+
citext: (min, max) => new CitextColumn(defaultSchemaConfig, min, max),
|
|
1774
|
+
date: () => new DateColumn(defaultSchemaConfig),
|
|
1775
|
+
timestampNoTZ: (precision) => new TimestampColumn(defaultSchemaConfig, precision),
|
|
1776
|
+
timestamp: (precision) => new TimestampTZColumn(defaultSchemaConfig, precision)
|
|
1640
1777
|
};
|
|
1641
1778
|
|
|
1642
1779
|
const addParserForRawExpression = (q, key, raw) => {
|
|
@@ -1677,17 +1814,15 @@ const addParserForSelectItem = (q, as, key, arg) => {
|
|
|
1677
1814
|
});
|
|
1678
1815
|
}
|
|
1679
1816
|
}
|
|
1680
|
-
|
|
1681
|
-
setParserForSelectedString(q, arg, as, key);
|
|
1817
|
+
return arg;
|
|
1682
1818
|
}
|
|
1683
|
-
return arg;
|
|
1819
|
+
return setParserForSelectedString(q, arg, as, key);
|
|
1684
1820
|
};
|
|
1685
1821
|
const emptyArrSQL = new RawSQL("'[]'");
|
|
1686
1822
|
const processSelectArg = (q, as, arg, columnAs) => {
|
|
1687
1823
|
var _a, _b, _c, _d;
|
|
1688
1824
|
if (typeof arg === "string") {
|
|
1689
|
-
setParserForSelectedString(q, arg, as, columnAs);
|
|
1690
|
-
return arg;
|
|
1825
|
+
return setParserForSelectedString(q, arg, as, columnAs);
|
|
1691
1826
|
}
|
|
1692
1827
|
const selectAs = {};
|
|
1693
1828
|
for (const key in arg) {
|
|
@@ -1736,7 +1871,12 @@ const processSelectArg = (q, as, arg, columnAs) => {
|
|
|
1736
1871
|
value = value.q.expr;
|
|
1737
1872
|
}
|
|
1738
1873
|
}
|
|
1739
|
-
selectAs[key] = addParserForSelectItem(
|
|
1874
|
+
selectAs[key] = addParserForSelectItem(
|
|
1875
|
+
q,
|
|
1876
|
+
as,
|
|
1877
|
+
key,
|
|
1878
|
+
value
|
|
1879
|
+
);
|
|
1740
1880
|
}
|
|
1741
1881
|
return { selectAs };
|
|
1742
1882
|
};
|
|
@@ -1748,21 +1888,25 @@ const setParserForSelectedString = (q, arg, as, columnAs) => {
|
|
|
1748
1888
|
const column = arg.slice(index + 1);
|
|
1749
1889
|
if (column === "*") {
|
|
1750
1890
|
addParsersForSelectJoined(q, table, columnAs);
|
|
1891
|
+
return table === as ? column : arg;
|
|
1751
1892
|
} else {
|
|
1752
1893
|
if (table === as) {
|
|
1753
1894
|
const parser = (_a = q.q.parsers) == null ? void 0 : _a[column];
|
|
1754
1895
|
if (parser)
|
|
1755
1896
|
orchidCore.setParserToQuery(q.q, columnAs || column, parser);
|
|
1897
|
+
return column;
|
|
1756
1898
|
} else {
|
|
1757
1899
|
const parser = (_c = (_b = q.q.joinedParsers) == null ? void 0 : _b[table]) == null ? void 0 : _c[column];
|
|
1758
1900
|
if (parser)
|
|
1759
1901
|
orchidCore.setParserToQuery(q.q, columnAs || column, parser);
|
|
1902
|
+
return arg;
|
|
1760
1903
|
}
|
|
1761
1904
|
}
|
|
1762
1905
|
} else {
|
|
1763
1906
|
const parser = (_d = q.q.parsers) == null ? void 0 : _d[arg];
|
|
1764
1907
|
if (parser)
|
|
1765
1908
|
orchidCore.setParserToQuery(q.q, columnAs || arg, parser);
|
|
1909
|
+
return arg;
|
|
1766
1910
|
}
|
|
1767
1911
|
};
|
|
1768
1912
|
const getShapeFromSelect = (q, isSubQuery) => {
|
|
@@ -1894,40 +2038,46 @@ class SelectItemExpression extends orchidCore.Expression {
|
|
|
1894
2038
|
}
|
|
1895
2039
|
}
|
|
1896
2040
|
|
|
1897
|
-
const _get = (
|
|
2041
|
+
const _get = (query, returnType, arg) => {
|
|
1898
2042
|
var _a, _b;
|
|
1899
|
-
q
|
|
2043
|
+
const q = query.q;
|
|
2044
|
+
q.returnType = returnType;
|
|
1900
2045
|
let type;
|
|
1901
2046
|
if (typeof arg === "string") {
|
|
1902
|
-
type = q.
|
|
2047
|
+
type = q.shape[arg];
|
|
1903
2048
|
if (!type) {
|
|
1904
2049
|
const index = arg.indexOf(".");
|
|
1905
2050
|
if (index !== -1) {
|
|
1906
2051
|
const table = arg.slice(0, index);
|
|
1907
2052
|
const column = arg.slice(index + 1);
|
|
1908
|
-
if (table === (q.
|
|
1909
|
-
type = q.
|
|
2053
|
+
if (table === (q.as || query.table)) {
|
|
2054
|
+
type = q.shape[column];
|
|
1910
2055
|
} else {
|
|
1911
|
-
type = (_b = (_a = q.
|
|
2056
|
+
type = (_b = (_a = q.joinedShapes) == null ? void 0 : _a[table]) == null ? void 0 : _b[column];
|
|
1912
2057
|
}
|
|
1913
2058
|
}
|
|
1914
2059
|
}
|
|
1915
|
-
q
|
|
1916
|
-
setParserForSelectedString(
|
|
1917
|
-
|
|
1918
|
-
|
|
2060
|
+
q[orchidCore.getValueKey] = type;
|
|
2061
|
+
setParserForSelectedString(
|
|
2062
|
+
query,
|
|
2063
|
+
arg,
|
|
2064
|
+
getQueryAs(query),
|
|
2065
|
+
orchidCore.getValueKey
|
|
2066
|
+
);
|
|
2067
|
+
q.expr = new SelectItemExpression(
|
|
2068
|
+
query,
|
|
1919
2069
|
arg,
|
|
1920
2070
|
type || orchidCore.emptyObject
|
|
1921
2071
|
);
|
|
1922
2072
|
} else {
|
|
1923
2073
|
type = arg._type;
|
|
1924
|
-
q
|
|
1925
|
-
addParserForRawExpression(
|
|
1926
|
-
q.
|
|
2074
|
+
q[orchidCore.getValueKey] = type;
|
|
2075
|
+
addParserForRawExpression(query, orchidCore.getValueKey, arg);
|
|
2076
|
+
q.expr = arg;
|
|
1927
2077
|
}
|
|
1928
|
-
q.
|
|
2078
|
+
q.select = [q.expr];
|
|
1929
2079
|
return setQueryOperators(
|
|
1930
|
-
|
|
2080
|
+
query,
|
|
1931
2081
|
(type == null ? void 0 : type.operators) || Operators.any
|
|
1932
2082
|
);
|
|
1933
2083
|
};
|
|
@@ -1938,27 +2088,11 @@ function _queryGetOptional(self, arg) {
|
|
|
1938
2088
|
return _get(self, "value", arg);
|
|
1939
2089
|
}
|
|
1940
2090
|
|
|
1941
|
-
class QueryBase {
|
|
1942
|
-
constructor() {
|
|
1943
|
-
this.q = {};
|
|
1944
|
-
}
|
|
1945
|
-
/**
|
|
1946
|
-
* Clones the current query chain, useful for re-using partial query snippets in other queries without mutating the original.
|
|
1947
|
-
*
|
|
1948
|
-
* Used under the hood, and not really needed on the app side.
|
|
1949
|
-
*/
|
|
1950
|
-
clone() {
|
|
1951
|
-
const cloned = Object.create(this.baseQuery);
|
|
1952
|
-
cloned.q = getClonedQueryData(this.q);
|
|
1953
|
-
return cloned;
|
|
1954
|
-
}
|
|
1955
|
-
}
|
|
1956
|
-
|
|
1957
2091
|
const _queryAs = (self, as) => {
|
|
1958
2092
|
self.q.as = as;
|
|
1959
2093
|
return self;
|
|
1960
2094
|
};
|
|
1961
|
-
class AsMethods
|
|
2095
|
+
class AsMethods {
|
|
1962
2096
|
/**
|
|
1963
2097
|
* Sets table alias:
|
|
1964
2098
|
*
|
|
@@ -1977,30 +2111,30 @@ class AsMethods extends QueryBase {
|
|
|
1977
2111
|
}
|
|
1978
2112
|
|
|
1979
2113
|
function queryFrom(self, args) {
|
|
1980
|
-
var _a, _b, _c;
|
|
1981
2114
|
if (Array.isArray(args[0])) {
|
|
1982
2115
|
return queryFrom(self, [
|
|
1983
2116
|
new RawSQL(args)
|
|
1984
2117
|
]);
|
|
1985
2118
|
}
|
|
2119
|
+
const data = self.q;
|
|
1986
2120
|
if (typeof args[0] === "string") {
|
|
1987
|
-
|
|
2121
|
+
data.as || (data.as = args[0]);
|
|
1988
2122
|
} else if (!orchidCore.isExpression(args[0])) {
|
|
1989
2123
|
const q = args[0];
|
|
1990
|
-
|
|
1991
|
-
|
|
2124
|
+
data.as || (data.as = q.q.as || q.table || "t");
|
|
2125
|
+
data.shape = getShapeFromSelect(
|
|
1992
2126
|
args[0],
|
|
1993
2127
|
true
|
|
1994
2128
|
);
|
|
1995
|
-
|
|
2129
|
+
data.parsers = q.q.parsers;
|
|
1996
2130
|
} else {
|
|
1997
|
-
|
|
2131
|
+
data.as || (data.as = "t");
|
|
1998
2132
|
}
|
|
1999
2133
|
const options = args[1];
|
|
2000
2134
|
if (options == null ? void 0 : options.only) {
|
|
2001
|
-
|
|
2135
|
+
data.fromOnly = options.only;
|
|
2002
2136
|
}
|
|
2003
|
-
|
|
2137
|
+
data.from = args[0];
|
|
2004
2138
|
return self;
|
|
2005
2139
|
}
|
|
2006
2140
|
class From {
|
|
@@ -2033,19 +2167,22 @@ class From {
|
|
|
2033
2167
|
* @param args - query, raw SQL, name of CTE table, or a template string
|
|
2034
2168
|
*/
|
|
2035
2169
|
from(...args) {
|
|
2036
|
-
return queryFrom(
|
|
2170
|
+
return queryFrom(
|
|
2171
|
+
this.clone(),
|
|
2172
|
+
args
|
|
2173
|
+
);
|
|
2037
2174
|
}
|
|
2038
2175
|
}
|
|
2039
2176
|
|
|
2040
2177
|
function queryWrap(self, query, as = "t") {
|
|
2041
|
-
return _queryAs(
|
|
2042
|
-
queryFrom(query, [self]),
|
|
2043
|
-
as
|
|
2044
|
-
);
|
|
2178
|
+
return _queryAs(queryFrom(query, [self]), as);
|
|
2045
2179
|
}
|
|
2046
2180
|
|
|
2047
2181
|
function queryJson(self, coalesce) {
|
|
2048
|
-
const q = queryWrap(
|
|
2182
|
+
const q = queryWrap(
|
|
2183
|
+
self,
|
|
2184
|
+
self.baseQuery.clone()
|
|
2185
|
+
);
|
|
2049
2186
|
_queryGetOptional(
|
|
2050
2187
|
q,
|
|
2051
2188
|
new RawSQL(
|
|
@@ -2115,7 +2252,7 @@ const selectToSql = (ctx, table, query, quotedAs) => {
|
|
|
2115
2252
|
const value = obj[as];
|
|
2116
2253
|
if (typeof value === "object" || typeof value === "function") {
|
|
2117
2254
|
if (orchidCore.isExpression(value)) {
|
|
2118
|
-
list.push(`${value.toSQL(ctx, quotedAs)}
|
|
2255
|
+
list.push(`${value.toSQL(ctx, quotedAs)} "${as}"`);
|
|
2119
2256
|
} else {
|
|
2120
2257
|
pushSubQuerySql(ctx, value, as, list, quotedAs);
|
|
2121
2258
|
}
|
|
@@ -2128,7 +2265,7 @@ const selectToSql = (ctx, table, query, quotedAs) => {
|
|
|
2128
2265
|
value,
|
|
2129
2266
|
quotedAs,
|
|
2130
2267
|
true
|
|
2131
|
-
)}
|
|
2268
|
+
)} "${as}"`
|
|
2132
2269
|
);
|
|
2133
2270
|
}
|
|
2134
2271
|
}
|
|
@@ -2214,7 +2351,7 @@ const pushSubQuerySql = (ctx, query, as, list, quotedAs) => {
|
|
|
2214
2351
|
query,
|
|
2215
2352
|
`(${makeSQL(query, ctx).text})`,
|
|
2216
2353
|
quotedAs
|
|
2217
|
-
)}
|
|
2354
|
+
)} "${as}"`
|
|
2218
2355
|
);
|
|
2219
2356
|
};
|
|
2220
2357
|
const coalesce = (ctx, query, sql, quotedAs) => {
|
|
@@ -3240,16 +3377,17 @@ var __spreadValues$a = (a, b) => {
|
|
|
3240
3377
|
return a;
|
|
3241
3378
|
};
|
|
3242
3379
|
var __spreadProps$6 = (a, b) => __defProps$6(a, __getOwnPropDescs$6(b));
|
|
3243
|
-
function setQueryOperators(
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3380
|
+
function setQueryOperators(query, operators) {
|
|
3381
|
+
const q = query.q;
|
|
3382
|
+
if (q.operators) {
|
|
3383
|
+
if (q.operators === operators)
|
|
3384
|
+
return query;
|
|
3385
|
+
query.baseQuery = q.originalQuery;
|
|
3248
3386
|
} else {
|
|
3249
|
-
q.
|
|
3387
|
+
q.originalQuery = query.baseQuery;
|
|
3250
3388
|
}
|
|
3251
|
-
q.
|
|
3252
|
-
return extendQuery(
|
|
3389
|
+
q.operators = operators;
|
|
3390
|
+
return extendQuery(query, operators);
|
|
3253
3391
|
}
|
|
3254
3392
|
const make = (_op) => {
|
|
3255
3393
|
return Object.assign(
|
|
@@ -3382,13 +3520,13 @@ class IntegerBaseColumn extends NumberBaseColumn {
|
|
|
3382
3520
|
}
|
|
3383
3521
|
class NumberAsStringBaseColumn extends ColumnType {
|
|
3384
3522
|
constructor(schema) {
|
|
3385
|
-
super(schema, schema.
|
|
3523
|
+
super(schema, schema.stringSchema);
|
|
3386
3524
|
this.operators = Operators.number;
|
|
3387
3525
|
}
|
|
3388
3526
|
}
|
|
3389
3527
|
class DecimalColumn extends ColumnType {
|
|
3390
3528
|
constructor(schema, numericPrecision, numericScale) {
|
|
3391
|
-
super(schema, schema.
|
|
3529
|
+
super(schema, schema.stringSchema);
|
|
3392
3530
|
this.operators = Operators.number;
|
|
3393
3531
|
this.dataType = "decimal";
|
|
3394
3532
|
this.data.numericPrecision = numericPrecision;
|
|
@@ -3547,14 +3685,14 @@ var __spreadValues$9 = (a, b) => {
|
|
|
3547
3685
|
};
|
|
3548
3686
|
var __spreadProps$5 = (a, b) => __defProps$5(a, __getOwnPropDescs$5(b));
|
|
3549
3687
|
class TextBaseColumn extends ColumnType {
|
|
3550
|
-
constructor(schema, schemaType = schema.
|
|
3688
|
+
constructor(schema, schemaType = schema.stringSchema) {
|
|
3551
3689
|
super(schema, schemaType);
|
|
3552
3690
|
this.operators = Operators.text;
|
|
3553
3691
|
}
|
|
3554
3692
|
}
|
|
3555
3693
|
class LimitedTextBaseColumn extends TextBaseColumn {
|
|
3556
3694
|
constructor(schema, limit) {
|
|
3557
|
-
super(schema, limit ? schema.stringMax(limit) : schema.
|
|
3695
|
+
super(schema, limit ? schema.stringMax(limit) : schema.stringSchema);
|
|
3558
3696
|
this.data.maxChars = limit;
|
|
3559
3697
|
}
|
|
3560
3698
|
toSQL() {
|
|
@@ -3637,7 +3775,7 @@ const textColumnToCode = (column, t) => {
|
|
|
3637
3775
|
`${column.dataType}(${args})${orchidCore.stringDataToCode(data)}`
|
|
3638
3776
|
);
|
|
3639
3777
|
};
|
|
3640
|
-
const minMaxToSchema = (schema, min, max) => min ? max ? schema.stringMinMax(min, max) : schema.stringMin(min) : schema.
|
|
3778
|
+
const minMaxToSchema = (schema, min, max) => min ? max ? schema.stringMinMax(min, max) : schema.stringMin(min) : schema.stringSchema;
|
|
3641
3779
|
class TextColumn extends TextBaseColumn {
|
|
3642
3780
|
constructor(schema, min, max) {
|
|
3643
3781
|
super(schema, minMaxToSchema(schema, min, max));
|
|
@@ -3660,7 +3798,7 @@ class ByteaColumn extends ColumnType {
|
|
|
3660
3798
|
}
|
|
3661
3799
|
class PointColumn extends ColumnType {
|
|
3662
3800
|
constructor(schema) {
|
|
3663
|
-
super(schema, schema.
|
|
3801
|
+
super(schema, schema.stringSchema);
|
|
3664
3802
|
this.dataType = "point";
|
|
3665
3803
|
this.operators = Operators.text;
|
|
3666
3804
|
}
|
|
@@ -3670,7 +3808,7 @@ class PointColumn extends ColumnType {
|
|
|
3670
3808
|
}
|
|
3671
3809
|
class LineColumn extends ColumnType {
|
|
3672
3810
|
constructor(schema) {
|
|
3673
|
-
super(schema, schema.
|
|
3811
|
+
super(schema, schema.stringSchema);
|
|
3674
3812
|
this.dataType = "line";
|
|
3675
3813
|
this.operators = Operators.text;
|
|
3676
3814
|
}
|
|
@@ -3680,7 +3818,7 @@ class LineColumn extends ColumnType {
|
|
|
3680
3818
|
}
|
|
3681
3819
|
class LsegColumn extends ColumnType {
|
|
3682
3820
|
constructor(schema) {
|
|
3683
|
-
super(schema, schema.
|
|
3821
|
+
super(schema, schema.stringSchema);
|
|
3684
3822
|
this.dataType = "lseg";
|
|
3685
3823
|
this.operators = Operators.text;
|
|
3686
3824
|
}
|
|
@@ -3690,7 +3828,7 @@ class LsegColumn extends ColumnType {
|
|
|
3690
3828
|
}
|
|
3691
3829
|
class BoxColumn extends ColumnType {
|
|
3692
3830
|
constructor(schema) {
|
|
3693
|
-
super(schema, schema.
|
|
3831
|
+
super(schema, schema.stringSchema);
|
|
3694
3832
|
this.dataType = "box";
|
|
3695
3833
|
this.operators = Operators.text;
|
|
3696
3834
|
}
|
|
@@ -3700,7 +3838,7 @@ class BoxColumn extends ColumnType {
|
|
|
3700
3838
|
}
|
|
3701
3839
|
class PathColumn extends ColumnType {
|
|
3702
3840
|
constructor(schema) {
|
|
3703
|
-
super(schema, schema.
|
|
3841
|
+
super(schema, schema.stringSchema);
|
|
3704
3842
|
this.dataType = "path";
|
|
3705
3843
|
this.operators = Operators.text;
|
|
3706
3844
|
}
|
|
@@ -3710,7 +3848,7 @@ class PathColumn extends ColumnType {
|
|
|
3710
3848
|
}
|
|
3711
3849
|
class PolygonColumn extends ColumnType {
|
|
3712
3850
|
constructor(schema) {
|
|
3713
|
-
super(schema, schema.
|
|
3851
|
+
super(schema, schema.stringSchema);
|
|
3714
3852
|
this.dataType = "polygon";
|
|
3715
3853
|
this.operators = Operators.text;
|
|
3716
3854
|
}
|
|
@@ -3720,7 +3858,7 @@ class PolygonColumn extends ColumnType {
|
|
|
3720
3858
|
}
|
|
3721
3859
|
class CircleColumn extends ColumnType {
|
|
3722
3860
|
constructor(schema) {
|
|
3723
|
-
super(schema, schema.
|
|
3861
|
+
super(schema, schema.stringSchema);
|
|
3724
3862
|
this.dataType = "circle";
|
|
3725
3863
|
this.operators = Operators.text;
|
|
3726
3864
|
}
|
|
@@ -3730,7 +3868,7 @@ class CircleColumn extends ColumnType {
|
|
|
3730
3868
|
}
|
|
3731
3869
|
class MoneyColumn extends NumberBaseColumn {
|
|
3732
3870
|
constructor(schema) {
|
|
3733
|
-
super(schema, schema.
|
|
3871
|
+
super(schema, schema.stringSchema);
|
|
3734
3872
|
this.dataType = "money";
|
|
3735
3873
|
this.parseFn = Object.assign(
|
|
3736
3874
|
function(input) {
|
|
@@ -3747,7 +3885,7 @@ class MoneyColumn extends NumberBaseColumn {
|
|
|
3747
3885
|
}
|
|
3748
3886
|
class CidrColumn extends ColumnType {
|
|
3749
3887
|
constructor(schema) {
|
|
3750
|
-
super(schema, schema.
|
|
3888
|
+
super(schema, schema.stringSchema);
|
|
3751
3889
|
this.dataType = "cidr";
|
|
3752
3890
|
this.operators = Operators.text;
|
|
3753
3891
|
}
|
|
@@ -3757,7 +3895,7 @@ class CidrColumn extends ColumnType {
|
|
|
3757
3895
|
}
|
|
3758
3896
|
class InetColumn extends ColumnType {
|
|
3759
3897
|
constructor(schema) {
|
|
3760
|
-
super(schema, schema.
|
|
3898
|
+
super(schema, schema.stringSchema);
|
|
3761
3899
|
this.dataType = "inet";
|
|
3762
3900
|
this.operators = Operators.text;
|
|
3763
3901
|
}
|
|
@@ -3767,7 +3905,7 @@ class InetColumn extends ColumnType {
|
|
|
3767
3905
|
}
|
|
3768
3906
|
class MacAddrColumn extends ColumnType {
|
|
3769
3907
|
constructor(schema) {
|
|
3770
|
-
super(schema, schema.
|
|
3908
|
+
super(schema, schema.stringSchema);
|
|
3771
3909
|
this.dataType = "macaddr";
|
|
3772
3910
|
this.operators = Operators.text;
|
|
3773
3911
|
}
|
|
@@ -3777,7 +3915,7 @@ class MacAddrColumn extends ColumnType {
|
|
|
3777
3915
|
}
|
|
3778
3916
|
class MacAddr8Column extends ColumnType {
|
|
3779
3917
|
constructor(schema) {
|
|
3780
|
-
super(schema, schema.
|
|
3918
|
+
super(schema, schema.stringSchema);
|
|
3781
3919
|
this.dataType = "macaddr8";
|
|
3782
3920
|
this.operators = Operators.text;
|
|
3783
3921
|
}
|
|
@@ -3823,7 +3961,7 @@ class BitVaryingColumn extends ColumnType {
|
|
|
3823
3961
|
}
|
|
3824
3962
|
class TsVectorColumn extends ColumnType {
|
|
3825
3963
|
constructor(schema, defaultLanguage = orchidCore.getDefaultLanguage()) {
|
|
3826
|
-
super(schema, schema.
|
|
3964
|
+
super(schema, schema.stringSchema);
|
|
3827
3965
|
this.defaultLanguage = defaultLanguage;
|
|
3828
3966
|
this.dataType = "tsvector";
|
|
3829
3967
|
this.operators = Operators.text;
|
|
@@ -3877,7 +4015,7 @@ class TsVectorColumn extends ColumnType {
|
|
|
3877
4015
|
}
|
|
3878
4016
|
class TsQueryColumn extends ColumnType {
|
|
3879
4017
|
constructor(schema) {
|
|
3880
|
-
super(schema, schema.
|
|
4018
|
+
super(schema, schema.stringSchema);
|
|
3881
4019
|
this.dataType = "tsquery";
|
|
3882
4020
|
this.operators = Operators.text;
|
|
3883
4021
|
}
|
|
@@ -3912,7 +4050,7 @@ class UUIDColumn extends ColumnType {
|
|
|
3912
4050
|
}
|
|
3913
4051
|
class XMLColumn extends ColumnType {
|
|
3914
4052
|
constructor(schema) {
|
|
3915
|
-
super(schema, schema.
|
|
4053
|
+
super(schema, schema.stringSchema);
|
|
3916
4054
|
this.dataType = "xml";
|
|
3917
4055
|
this.operators = Operators.text;
|
|
3918
4056
|
}
|
|
@@ -3931,166 +4069,43 @@ class CitextColumn extends TextBaseColumn {
|
|
|
3931
4069
|
}
|
|
3932
4070
|
}
|
|
3933
4071
|
|
|
3934
|
-
|
|
3935
|
-
return typeof input === "number" ? new Date(input) : input;
|
|
3936
|
-
};
|
|
3937
|
-
const skipDateMethodsFromToCode = { encodeFn: dateTimeEncode };
|
|
3938
|
-
class DateBaseColumn extends ColumnType {
|
|
4072
|
+
class BooleanColumn extends ColumnType {
|
|
3939
4073
|
constructor(schema) {
|
|
3940
|
-
super(schema, schema.
|
|
3941
|
-
this.
|
|
3942
|
-
this.
|
|
3943
|
-
this.
|
|
3944
|
-
this.asDate = schema.dateAsDate;
|
|
3945
|
-
}
|
|
3946
|
-
}
|
|
3947
|
-
class DateColumn extends DateBaseColumn {
|
|
3948
|
-
constructor() {
|
|
3949
|
-
super(...arguments);
|
|
3950
|
-
this.dataType = "date";
|
|
4074
|
+
super(schema, schema.boolean);
|
|
4075
|
+
this.dataType = "boolean";
|
|
4076
|
+
this.operators = Operators.boolean;
|
|
4077
|
+
this.parseItem = (input) => input[0] === "t";
|
|
3951
4078
|
}
|
|
3952
4079
|
toCode(t) {
|
|
3953
|
-
return columnCode(
|
|
3954
|
-
this,
|
|
3955
|
-
t,
|
|
3956
|
-
`date()${orchidCore.dateDataToCode(this.data)}`,
|
|
3957
|
-
this.data,
|
|
3958
|
-
skipDateMethodsFromToCode
|
|
3959
|
-
);
|
|
4080
|
+
return columnCode(this, t, "boolean()");
|
|
3960
4081
|
}
|
|
3961
4082
|
}
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
4083
|
+
|
|
4084
|
+
class CustomTypeColumn extends ColumnType {
|
|
4085
|
+
constructor(schema, dataType) {
|
|
4086
|
+
super(schema, schema.unknown, schema.unknown, schema.unknown);
|
|
4087
|
+
this.dataType = dataType;
|
|
4088
|
+
this.operators = Operators.any;
|
|
4089
|
+
this.data.isOfCustomType = true;
|
|
3966
4090
|
}
|
|
3967
|
-
|
|
3968
|
-
return orchidCore.
|
|
3969
|
-
this.dataType,
|
|
3970
|
-
this.data.dateTimePrecision !== void 0 && `(${this.data.dateTimePrecision})`
|
|
3971
|
-
);
|
|
4091
|
+
toCode(t) {
|
|
4092
|
+
return columnCode(this, t, `type(${orchidCore.singleQuote(this.dataType)})`);
|
|
3972
4093
|
}
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
this.data.dateTimePrecision !== void 0 && `(${this.data.dateTimePrecision})`,
|
|
3979
|
-
" with time zone"
|
|
4094
|
+
as(column) {
|
|
4095
|
+
const c = orchidCore.setColumnData(
|
|
4096
|
+
this,
|
|
4097
|
+
"as",
|
|
4098
|
+
column
|
|
3980
4099
|
);
|
|
4100
|
+
c.inputSchema = column.inputSchema;
|
|
4101
|
+
c.outputSchema = column.outputSchema;
|
|
4102
|
+
c.querySchema = column.querySchema;
|
|
4103
|
+
return c;
|
|
3981
4104
|
}
|
|
3982
4105
|
}
|
|
3983
|
-
|
|
3984
|
-
const { dateTimePrecision: p } = self.data;
|
|
3985
|
-
return columnCode(
|
|
3986
|
-
self,
|
|
3987
|
-
t,
|
|
3988
|
-
`${self instanceof TimestampColumn ? "timestampNoTZ" : "timestamp"}(${p && p !== 6 ? p : ""})${orchidCore.dateDataToCode(self.data)}`,
|
|
3989
|
-
self.data,
|
|
3990
|
-
skipDateMethodsFromToCode
|
|
3991
|
-
);
|
|
3992
|
-
};
|
|
3993
|
-
class TimestampColumn extends DateTimeBaseClass {
|
|
3994
|
-
constructor() {
|
|
3995
|
-
super(...arguments);
|
|
3996
|
-
this.dataType = "timestamp";
|
|
3997
|
-
}
|
|
3998
|
-
toCode(t) {
|
|
3999
|
-
return timestampToCode(this, t);
|
|
4000
|
-
}
|
|
4001
|
-
}
|
|
4002
|
-
class TimestampTZColumn extends DateTimeTzBaseClass {
|
|
4003
|
-
constructor() {
|
|
4004
|
-
super(...arguments);
|
|
4005
|
-
this.dataType = "timestamptz";
|
|
4006
|
-
this.baseDataType = "timestamp";
|
|
4007
|
-
}
|
|
4106
|
+
class DomainColumn extends CustomTypeColumn {
|
|
4008
4107
|
toCode(t) {
|
|
4009
|
-
return
|
|
4010
|
-
}
|
|
4011
|
-
}
|
|
4012
|
-
class TimeColumn extends ColumnType {
|
|
4013
|
-
constructor(schema, dateTimePrecision) {
|
|
4014
|
-
super(schema, schema.string);
|
|
4015
|
-
this.dataType = "time";
|
|
4016
|
-
this.operators = Operators.time;
|
|
4017
|
-
this.data.dateTimePrecision = dateTimePrecision;
|
|
4018
|
-
}
|
|
4019
|
-
toCode(t) {
|
|
4020
|
-
const { dateTimePrecision } = this.data;
|
|
4021
|
-
return columnCode(
|
|
4022
|
-
this,
|
|
4023
|
-
t,
|
|
4024
|
-
`time(${dateTimePrecision || ""})${orchidCore.dateDataToCode(this.data)}`,
|
|
4025
|
-
this.data,
|
|
4026
|
-
skipDateMethodsFromToCode
|
|
4027
|
-
);
|
|
4028
|
-
}
|
|
4029
|
-
}
|
|
4030
|
-
class IntervalColumn extends ColumnType {
|
|
4031
|
-
constructor(schema, fields, precision) {
|
|
4032
|
-
super(schema, schema.timeInterval);
|
|
4033
|
-
this.dataType = "interval";
|
|
4034
|
-
this.operators = Operators.date;
|
|
4035
|
-
this.data.fields = fields;
|
|
4036
|
-
this.data.precision = precision;
|
|
4037
|
-
}
|
|
4038
|
-
toCode(t) {
|
|
4039
|
-
const { fields, precision } = this.data;
|
|
4040
|
-
return columnCode(
|
|
4041
|
-
this,
|
|
4042
|
-
t,
|
|
4043
|
-
`interval(${[fields && `'${fields}'`, precision && String(precision)].filter((part) => part).join(", ")})`,
|
|
4044
|
-
this.data,
|
|
4045
|
-
skipDateMethodsFromToCode
|
|
4046
|
-
);
|
|
4047
|
-
}
|
|
4048
|
-
toSQL() {
|
|
4049
|
-
return orchidCore.joinTruthy(
|
|
4050
|
-
this.dataType,
|
|
4051
|
-
this.data.fields && ` ${this.data.fields}`,
|
|
4052
|
-
this.data.precision !== void 0 && ` (${this.data.precision})`
|
|
4053
|
-
);
|
|
4054
|
-
}
|
|
4055
|
-
}
|
|
4056
|
-
|
|
4057
|
-
class BooleanColumn extends ColumnType {
|
|
4058
|
-
constructor(schema) {
|
|
4059
|
-
super(schema, schema.boolean);
|
|
4060
|
-
this.dataType = "boolean";
|
|
4061
|
-
this.operators = Operators.boolean;
|
|
4062
|
-
this.parseItem = (input) => input[0] === "t";
|
|
4063
|
-
}
|
|
4064
|
-
toCode(t) {
|
|
4065
|
-
return columnCode(this, t, "boolean()");
|
|
4066
|
-
}
|
|
4067
|
-
}
|
|
4068
|
-
|
|
4069
|
-
class CustomTypeColumn extends ColumnType {
|
|
4070
|
-
constructor(schema, dataType) {
|
|
4071
|
-
super(schema, schema.unknown, schema.unknown, schema.unknown);
|
|
4072
|
-
this.dataType = dataType;
|
|
4073
|
-
this.operators = Operators.any;
|
|
4074
|
-
this.data.isOfCustomType = true;
|
|
4075
|
-
}
|
|
4076
|
-
toCode(t) {
|
|
4077
|
-
return columnCode(this, t, `type(${orchidCore.singleQuote(this.dataType)})`);
|
|
4078
|
-
}
|
|
4079
|
-
as(column) {
|
|
4080
|
-
const c = orchidCore.setColumnData(
|
|
4081
|
-
this,
|
|
4082
|
-
"as",
|
|
4083
|
-
column
|
|
4084
|
-
);
|
|
4085
|
-
c.inputSchema = column.inputSchema;
|
|
4086
|
-
c.outputSchema = column.outputSchema;
|
|
4087
|
-
c.querySchema = column.querySchema;
|
|
4088
|
-
return c;
|
|
4089
|
-
}
|
|
4090
|
-
}
|
|
4091
|
-
class DomainColumn extends CustomTypeColumn {
|
|
4092
|
-
toCode(t) {
|
|
4093
|
-
return columnCode(this, t, `domain(${orchidCore.singleQuote(this.dataType)})`);
|
|
4108
|
+
return columnCode(this, t, `domain(${orchidCore.singleQuote(this.dataType)})`);
|
|
4094
4109
|
}
|
|
4095
4110
|
}
|
|
4096
4111
|
|
|
@@ -4128,19 +4143,6 @@ const getColumnTypes = (types, fn, nowSQL, language, data = newTableData()) => {
|
|
|
4128
4143
|
return fn(types);
|
|
4129
4144
|
};
|
|
4130
4145
|
const makeColumnTypes = (schema) => {
|
|
4131
|
-
const columnsWithMethods = {};
|
|
4132
|
-
function columnWithMethods(klass, methods, ...args) {
|
|
4133
|
-
if (columnsWithMethods[klass.name]) {
|
|
4134
|
-
return new columnsWithMethods[klass.name](...args);
|
|
4135
|
-
}
|
|
4136
|
-
const withMethods = class extends klass {
|
|
4137
|
-
};
|
|
4138
|
-
Object.assign(withMethods.prototype, methods);
|
|
4139
|
-
return new (columnsWithMethods[klass.name] = withMethods)(...args);
|
|
4140
|
-
}
|
|
4141
|
-
const numberMethods = schema.numberMethods;
|
|
4142
|
-
const stringMethods = schema.stringMethods;
|
|
4143
|
-
const dateMethods = schema.dateMethods;
|
|
4144
4146
|
return __spreadValues$8({
|
|
4145
4147
|
schema,
|
|
4146
4148
|
enum: schema.enum,
|
|
@@ -4163,90 +4165,33 @@ const makeColumnTypes = (schema) => {
|
|
|
4163
4165
|
}
|
|
4164
4166
|
return (...args2) => new RawSQL(args2, arg);
|
|
4165
4167
|
},
|
|
4166
|
-
smallint
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
return columnWithMethods(BigIntColumn, stringMethods, schema);
|
|
4174
|
-
},
|
|
4175
|
-
numeric(precision, scale) {
|
|
4176
|
-
return columnWithMethods(
|
|
4177
|
-
DecimalColumn,
|
|
4178
|
-
stringMethods,
|
|
4179
|
-
schema,
|
|
4180
|
-
precision,
|
|
4181
|
-
scale
|
|
4182
|
-
);
|
|
4183
|
-
},
|
|
4184
|
-
decimal(precision, scale) {
|
|
4185
|
-
return columnWithMethods(
|
|
4186
|
-
DecimalColumn,
|
|
4187
|
-
stringMethods,
|
|
4188
|
-
schema,
|
|
4189
|
-
precision,
|
|
4190
|
-
scale
|
|
4191
|
-
);
|
|
4192
|
-
},
|
|
4193
|
-
real() {
|
|
4194
|
-
return columnWithMethods(RealColumn, numberMethods, schema);
|
|
4195
|
-
},
|
|
4196
|
-
doublePrecision() {
|
|
4197
|
-
return columnWithMethods(DoublePrecisionColumn, stringMethods, schema);
|
|
4198
|
-
},
|
|
4168
|
+
smallint: schema.smallint,
|
|
4169
|
+
integer: schema.integer,
|
|
4170
|
+
bigint: schema.bigint,
|
|
4171
|
+
numeric: schema.decimal,
|
|
4172
|
+
decimal: schema.decimal,
|
|
4173
|
+
real: schema.real,
|
|
4174
|
+
doublePrecision: schema.doublePrecision,
|
|
4199
4175
|
identity(options) {
|
|
4200
|
-
return
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
schema
|
|
4204
|
-
).identity(options);
|
|
4205
|
-
},
|
|
4206
|
-
smallSerial() {
|
|
4207
|
-
return columnWithMethods(SmallSerialColumn, numberMethods, schema);
|
|
4208
|
-
},
|
|
4209
|
-
serial() {
|
|
4210
|
-
return columnWithMethods(SerialColumn, numberMethods, schema);
|
|
4211
|
-
},
|
|
4212
|
-
bigSerial() {
|
|
4213
|
-
return columnWithMethods(BigSerialColumn, stringMethods, schema);
|
|
4214
|
-
},
|
|
4215
|
-
money() {
|
|
4216
|
-
return columnWithMethods(MoneyColumn, stringMethods, schema);
|
|
4217
|
-
},
|
|
4218
|
-
varchar(limit) {
|
|
4219
|
-
return columnWithMethods(VarCharColumn, stringMethods, schema, limit);
|
|
4220
|
-
},
|
|
4221
|
-
char(limit) {
|
|
4222
|
-
return columnWithMethods(CharColumn, stringMethods, schema, limit);
|
|
4223
|
-
},
|
|
4224
|
-
text(min, max) {
|
|
4225
|
-
return columnWithMethods(TextColumn, stringMethods, schema, min, max);
|
|
4226
|
-
},
|
|
4227
|
-
string(limit = 255) {
|
|
4228
|
-
return columnWithMethods(StringColumn, stringMethods, schema, limit);
|
|
4229
|
-
},
|
|
4230
|
-
citext(min, max) {
|
|
4231
|
-
return columnWithMethods(CitextColumn, stringMethods, schema, min, max);
|
|
4176
|
+
return schema.integer().identity(
|
|
4177
|
+
options
|
|
4178
|
+
);
|
|
4232
4179
|
},
|
|
4180
|
+
smallSerial: schema.smallSerial,
|
|
4181
|
+
serial: schema.serial,
|
|
4182
|
+
bigSerial: schema.bigSerial,
|
|
4183
|
+
money: schema.money,
|
|
4184
|
+
varchar: schema.varchar,
|
|
4185
|
+
char: schema.char,
|
|
4186
|
+
text: schema.text,
|
|
4187
|
+
string: schema.string,
|
|
4188
|
+
citext: schema.citext,
|
|
4233
4189
|
bytea() {
|
|
4234
4190
|
return new ByteaColumn(schema);
|
|
4235
4191
|
},
|
|
4236
|
-
date
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
timestampNoTZ(precision) {
|
|
4240
|
-
return columnWithMethods(TimestampColumn, dateMethods, schema, precision);
|
|
4241
|
-
},
|
|
4242
|
-
timestamp(precision) {
|
|
4243
|
-
return columnWithMethods(
|
|
4244
|
-
TimestampTZColumn,
|
|
4245
|
-
dateMethods,
|
|
4246
|
-
schema,
|
|
4247
|
-
precision
|
|
4248
|
-
);
|
|
4249
|
-
},
|
|
4192
|
+
date: schema.date,
|
|
4193
|
+
timestampNoTZ: schema.timestampNoTZ,
|
|
4194
|
+
timestamp: schema.timestamp,
|
|
4250
4195
|
time(precision) {
|
|
4251
4196
|
return new TimeColumn(schema, precision);
|
|
4252
4197
|
},
|
|
@@ -4820,7 +4765,10 @@ class AggregateMethods {
|
|
|
4820
4765
|
* ```
|
|
4821
4766
|
*/
|
|
4822
4767
|
exists() {
|
|
4823
|
-
const q = _queryGetOptional(
|
|
4768
|
+
const q = _queryGetOptional(
|
|
4769
|
+
this.clone(),
|
|
4770
|
+
new RawSQL("true")
|
|
4771
|
+
);
|
|
4824
4772
|
q.q.notFoundDefault = false;
|
|
4825
4773
|
q.q.coalesceValue = new RawSQL("false");
|
|
4826
4774
|
return q;
|
|
@@ -4850,13 +4798,7 @@ class AggregateMethods {
|
|
|
4850
4798
|
* @param options - aggregation options
|
|
4851
4799
|
*/
|
|
4852
4800
|
count(arg = "*", options) {
|
|
4853
|
-
return makeFnExpression(
|
|
4854
|
-
this,
|
|
4855
|
-
int,
|
|
4856
|
-
"count",
|
|
4857
|
-
[arg],
|
|
4858
|
-
options
|
|
4859
|
-
);
|
|
4801
|
+
return makeFnExpression(this, int, "count", [arg], options);
|
|
4860
4802
|
}
|
|
4861
4803
|
/**
|
|
4862
4804
|
* Get the minimum value for the specified numeric column, returns number or `null` if there are no records.
|
|
@@ -6074,16 +6016,17 @@ class OnConflictQueryBuilder {
|
|
|
6074
6016
|
}
|
|
6075
6017
|
}
|
|
6076
6018
|
|
|
6077
|
-
const _queryDelete = (
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6019
|
+
const _queryDelete = (query) => {
|
|
6020
|
+
const q = query.q;
|
|
6021
|
+
if (!q.select) {
|
|
6022
|
+
if (q.returnType === "oneOrThrow" || q.returnType === "valueOrThrow") {
|
|
6023
|
+
q.throwOnNotFound = true;
|
|
6081
6024
|
}
|
|
6082
|
-
q.
|
|
6025
|
+
q.returnType = "rowCount";
|
|
6083
6026
|
}
|
|
6084
|
-
throwIfNoWhere(
|
|
6085
|
-
q.
|
|
6086
|
-
return
|
|
6027
|
+
throwIfNoWhere(query, "delete");
|
|
6028
|
+
q.type = "delete";
|
|
6029
|
+
return query;
|
|
6087
6030
|
};
|
|
6088
6031
|
class Delete {
|
|
6089
6032
|
/**
|
|
@@ -6156,8 +6099,8 @@ const forMethods = {
|
|
|
6156
6099
|
return q;
|
|
6157
6100
|
}
|
|
6158
6101
|
};
|
|
6159
|
-
const forQueryBuilder = (
|
|
6160
|
-
q = extendQuery(
|
|
6102
|
+
const forQueryBuilder = (arg, type, tableNames) => {
|
|
6103
|
+
const q = extendQuery(arg, forMethods);
|
|
6161
6104
|
q.q.for = {
|
|
6162
6105
|
type,
|
|
6163
6106
|
tableNames
|
|
@@ -6336,7 +6279,7 @@ const _queryHookAfterDelete = (q, select, cb) => {
|
|
|
6336
6279
|
const _queryHookAfterDeleteCommit = (q, select, cb) => {
|
|
6337
6280
|
return after(q, "Delete", select, cb, true);
|
|
6338
6281
|
};
|
|
6339
|
-
class QueryHooks
|
|
6282
|
+
class QueryHooks {
|
|
6340
6283
|
/**
|
|
6341
6284
|
* Run the function before any kind of query.
|
|
6342
6285
|
*
|
|
@@ -6373,7 +6316,11 @@ class QueryHooks extends QueryBase {
|
|
|
6373
6316
|
* @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
|
|
6374
6317
|
*/
|
|
6375
6318
|
afterCreate(select, cb) {
|
|
6376
|
-
return _queryHookAfterCreate(
|
|
6319
|
+
return _queryHookAfterCreate(
|
|
6320
|
+
this.clone(),
|
|
6321
|
+
select,
|
|
6322
|
+
cb
|
|
6323
|
+
);
|
|
6377
6324
|
}
|
|
6378
6325
|
/**
|
|
6379
6326
|
* Run the function after transaction for a `create` kind of query will be committed.
|
|
@@ -6383,7 +6330,11 @@ class QueryHooks extends QueryBase {
|
|
|
6383
6330
|
* @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
|
|
6384
6331
|
*/
|
|
6385
6332
|
afterCreateCommit(select, cb) {
|
|
6386
|
-
return _queryHookAfterCreateCommit(
|
|
6333
|
+
return _queryHookAfterCreateCommit(
|
|
6334
|
+
this.clone(),
|
|
6335
|
+
select,
|
|
6336
|
+
cb
|
|
6337
|
+
);
|
|
6387
6338
|
}
|
|
6388
6339
|
/**
|
|
6389
6340
|
* Run the function before an `update` kind of query.
|
|
@@ -6404,7 +6355,11 @@ class QueryHooks extends QueryBase {
|
|
|
6404
6355
|
* @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
|
|
6405
6356
|
*/
|
|
6406
6357
|
afterUpdate(select, cb) {
|
|
6407
|
-
return _queryHookAfterUpdate(
|
|
6358
|
+
return _queryHookAfterUpdate(
|
|
6359
|
+
this.clone(),
|
|
6360
|
+
select,
|
|
6361
|
+
cb
|
|
6362
|
+
);
|
|
6408
6363
|
}
|
|
6409
6364
|
/**
|
|
6410
6365
|
* Run the function after transaction for an `update` kind of query will be committed.
|
|
@@ -6415,7 +6370,11 @@ class QueryHooks extends QueryBase {
|
|
|
6415
6370
|
* @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
|
|
6416
6371
|
*/
|
|
6417
6372
|
afterUpdateCommit(select, cb) {
|
|
6418
|
-
return _queryHookAfterUpdateCommit(
|
|
6373
|
+
return _queryHookAfterUpdateCommit(
|
|
6374
|
+
this.clone(),
|
|
6375
|
+
select,
|
|
6376
|
+
cb
|
|
6377
|
+
);
|
|
6419
6378
|
}
|
|
6420
6379
|
/**
|
|
6421
6380
|
* Run the function before a `create` or an `update` kind of query.
|
|
@@ -6436,7 +6395,11 @@ class QueryHooks extends QueryBase {
|
|
|
6436
6395
|
* @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
|
|
6437
6396
|
*/
|
|
6438
6397
|
afterSave(select, cb) {
|
|
6439
|
-
return _queryHookAfterSave(
|
|
6398
|
+
return _queryHookAfterSave(
|
|
6399
|
+
this.clone(),
|
|
6400
|
+
select,
|
|
6401
|
+
cb
|
|
6402
|
+
);
|
|
6440
6403
|
}
|
|
6441
6404
|
/**
|
|
6442
6405
|
* Run the function after transaction for a `create` or an `update` kind of query will be committed.
|
|
@@ -6447,7 +6410,11 @@ class QueryHooks extends QueryBase {
|
|
|
6447
6410
|
* @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
|
|
6448
6411
|
*/
|
|
6449
6412
|
afterSaveCommit(select, cb) {
|
|
6450
|
-
return _queryAfterSaveCommit(
|
|
6413
|
+
return _queryAfterSaveCommit(
|
|
6414
|
+
this.clone(),
|
|
6415
|
+
select,
|
|
6416
|
+
cb
|
|
6417
|
+
);
|
|
6451
6418
|
}
|
|
6452
6419
|
/**
|
|
6453
6420
|
* Run the function before a `delete` kind of query.
|
|
@@ -6468,7 +6435,11 @@ class QueryHooks extends QueryBase {
|
|
|
6468
6435
|
* @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
|
|
6469
6436
|
*/
|
|
6470
6437
|
afterDelete(select, cb) {
|
|
6471
|
-
return _queryHookAfterDelete(
|
|
6438
|
+
return _queryHookAfterDelete(
|
|
6439
|
+
this.clone(),
|
|
6440
|
+
select,
|
|
6441
|
+
cb
|
|
6442
|
+
);
|
|
6472
6443
|
}
|
|
6473
6444
|
/**
|
|
6474
6445
|
* Run the function after transaction for a `delete` kind of query will be committed.
|
|
@@ -6479,7 +6450,27 @@ class QueryHooks extends QueryBase {
|
|
|
6479
6450
|
* @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
|
|
6480
6451
|
*/
|
|
6481
6452
|
afterDeleteCommit(select, cb) {
|
|
6482
|
-
return _queryHookAfterDeleteCommit(
|
|
6453
|
+
return _queryHookAfterDeleteCommit(
|
|
6454
|
+
this.clone(),
|
|
6455
|
+
select,
|
|
6456
|
+
cb
|
|
6457
|
+
);
|
|
6458
|
+
}
|
|
6459
|
+
}
|
|
6460
|
+
|
|
6461
|
+
class QueryBase {
|
|
6462
|
+
constructor() {
|
|
6463
|
+
this.q = {};
|
|
6464
|
+
}
|
|
6465
|
+
/**
|
|
6466
|
+
* Clones the current query chain, useful for re-using partial query snippets in other queries without mutating the original.
|
|
6467
|
+
*
|
|
6468
|
+
* Used under the hood, and not really needed on the app side.
|
|
6469
|
+
*/
|
|
6470
|
+
clone() {
|
|
6471
|
+
const cloned = Object.create(this.baseQuery);
|
|
6472
|
+
cloned.q = getClonedQueryData(this.q);
|
|
6473
|
+
return cloned;
|
|
6483
6474
|
}
|
|
6484
6475
|
}
|
|
6485
6476
|
|
|
@@ -6491,7 +6482,11 @@ const _queryWhere = (q, args) => {
|
|
|
6491
6482
|
new RawSQL(args)
|
|
6492
6483
|
);
|
|
6493
6484
|
}
|
|
6494
|
-
return pushQueryArray(
|
|
6485
|
+
return pushQueryArray(
|
|
6486
|
+
q,
|
|
6487
|
+
"and",
|
|
6488
|
+
args
|
|
6489
|
+
);
|
|
6495
6490
|
};
|
|
6496
6491
|
const _queryWhereNot = (q, args) => {
|
|
6497
6492
|
if (Array.isArray(args[0])) {
|
|
@@ -6545,14 +6540,13 @@ const _queryWhereIn = (q, and, arg, values, not) => {
|
|
|
6545
6540
|
}
|
|
6546
6541
|
return q;
|
|
6547
6542
|
};
|
|
6548
|
-
const existsArgs = (args) => {
|
|
6549
|
-
const q = args[0];
|
|
6543
|
+
const existsArgs = (q, args) => {
|
|
6550
6544
|
let isSubQuery;
|
|
6551
6545
|
if (typeof q === "object") {
|
|
6552
6546
|
isSubQuery = getIsJoinSubQuery(q.q, q.baseQuery.q);
|
|
6553
6547
|
if (isSubQuery) {
|
|
6554
|
-
|
|
6555
|
-
|
|
6548
|
+
q = q.clone();
|
|
6549
|
+
q.shape = getShapeFromSelect(q, true);
|
|
6556
6550
|
}
|
|
6557
6551
|
} else {
|
|
6558
6552
|
isSubQuery = false;
|
|
@@ -6560,6 +6554,7 @@ const existsArgs = (args) => {
|
|
|
6560
6554
|
return [
|
|
6561
6555
|
{
|
|
6562
6556
|
EXISTS: {
|
|
6557
|
+
first: q,
|
|
6563
6558
|
args,
|
|
6564
6559
|
isSubQuery
|
|
6565
6560
|
}
|
|
@@ -6956,7 +6951,10 @@ class Where {
|
|
|
6956
6951
|
* @param args - {@link WhereArgs}
|
|
6957
6952
|
*/
|
|
6958
6953
|
where(...args) {
|
|
6959
|
-
return _queryWhere(
|
|
6954
|
+
return _queryWhere(
|
|
6955
|
+
this.clone(),
|
|
6956
|
+
args
|
|
6957
|
+
);
|
|
6960
6958
|
}
|
|
6961
6959
|
/**
|
|
6962
6960
|
* `whereNot` takes the same argument as `where`,
|
|
@@ -6974,7 +6972,10 @@ class Where {
|
|
|
6974
6972
|
* @param args - {@link WhereArgs}
|
|
6975
6973
|
*/
|
|
6976
6974
|
whereNot(...args) {
|
|
6977
|
-
return _queryWhereNot(
|
|
6975
|
+
return _queryWhereNot(
|
|
6976
|
+
this.clone(),
|
|
6977
|
+
args
|
|
6978
|
+
);
|
|
6978
6979
|
}
|
|
6979
6980
|
/**
|
|
6980
6981
|
* `orWhere` is accepting the same arguments as {@link where}, joining arguments with `OR`.
|
|
@@ -7008,35 +7009,172 @@ class Where {
|
|
|
7008
7009
|
* @param args - {@link WhereArgs} will be prefixed with `NOT` and joined with `OR`
|
|
7009
7010
|
*/
|
|
7010
7011
|
orWhereNot(...args) {
|
|
7011
|
-
return _queryOrNot(
|
|
7012
|
+
return _queryOrNot(
|
|
7013
|
+
this.clone(),
|
|
7014
|
+
args
|
|
7015
|
+
);
|
|
7012
7016
|
}
|
|
7013
|
-
|
|
7014
|
-
|
|
7017
|
+
/**
|
|
7018
|
+
* `whereIn` and related methods are for the `IN` operator to check for inclusion in a list of values.
|
|
7019
|
+
*
|
|
7020
|
+
* When used with a single column it works equivalent to the `in` column operator:
|
|
7021
|
+
*
|
|
7022
|
+
* ```ts
|
|
7023
|
+
* db.table.whereIn('column', [1, 2, 3]);
|
|
7024
|
+
* // the same as:
|
|
7025
|
+
* db.table.where({ column: [1, 2, 3] });
|
|
7026
|
+
* ```
|
|
7027
|
+
*
|
|
7028
|
+
* `whereIn` can support a tuple of columns, that's what the `in` operator cannot support:
|
|
7029
|
+
*
|
|
7030
|
+
* ```ts
|
|
7031
|
+
* db.table.whereIn(
|
|
7032
|
+
* ['id', 'name'],
|
|
7033
|
+
* [
|
|
7034
|
+
* [1, 'Alice'],
|
|
7035
|
+
* [2, 'Bob'],
|
|
7036
|
+
* ],
|
|
7037
|
+
* );
|
|
7038
|
+
* ```
|
|
7039
|
+
*
|
|
7040
|
+
* It supports sub query which should return records with columns of the same type:
|
|
7041
|
+
*
|
|
7042
|
+
* ```ts
|
|
7043
|
+
* db.table.whereIn(['id', 'name'], OtherTable.select('id', 'name'));
|
|
7044
|
+
* ```
|
|
7045
|
+
*
|
|
7046
|
+
* It supports raw SQL expression:
|
|
7047
|
+
*
|
|
7048
|
+
* ```ts
|
|
7049
|
+
* db.table.whereIn(['id', 'name'], db.table.sql`((1, 'one'), (2, 'two'))`);
|
|
7050
|
+
* ```
|
|
7051
|
+
*/
|
|
7052
|
+
whereIn(...args) {
|
|
7053
|
+
return _queryWhereIn(
|
|
7054
|
+
this.clone(),
|
|
7055
|
+
true,
|
|
7056
|
+
args[0],
|
|
7057
|
+
args[1]
|
|
7058
|
+
);
|
|
7015
7059
|
}
|
|
7016
|
-
|
|
7017
|
-
|
|
7060
|
+
/**
|
|
7061
|
+
* Takes the same arguments as {@link whereIn}.
|
|
7062
|
+
* Add a `WHERE IN` condition prefixed with `OR` to the query:
|
|
7063
|
+
*
|
|
7064
|
+
* ```ts
|
|
7065
|
+
* db.table.whereIn('a', [1, 2, 3]).orWhereIn('b', ['one', 'two']);
|
|
7066
|
+
* ```
|
|
7067
|
+
*/
|
|
7068
|
+
orWhereIn(...args) {
|
|
7069
|
+
return _queryWhereIn(
|
|
7070
|
+
this.clone(),
|
|
7071
|
+
false,
|
|
7072
|
+
args[0],
|
|
7073
|
+
args[1]
|
|
7074
|
+
);
|
|
7018
7075
|
}
|
|
7019
|
-
|
|
7020
|
-
|
|
7076
|
+
/**
|
|
7077
|
+
* Acts as `whereIn`, but negates the condition with `NOT`:
|
|
7078
|
+
*
|
|
7079
|
+
* ```ts
|
|
7080
|
+
* db.table.whereNotIn('color', ['red', 'green', 'blue']);
|
|
7081
|
+
* ```
|
|
7082
|
+
*/
|
|
7083
|
+
whereNotIn(...args) {
|
|
7084
|
+
return _queryWhereIn(
|
|
7085
|
+
this.clone(),
|
|
7086
|
+
true,
|
|
7087
|
+
args[0],
|
|
7088
|
+
args[1],
|
|
7089
|
+
true
|
|
7090
|
+
);
|
|
7021
7091
|
}
|
|
7022
|
-
|
|
7023
|
-
|
|
7092
|
+
/**
|
|
7093
|
+
* Acts as `whereIn`, but prepends `OR` to the condition and negates it with `NOT`:
|
|
7094
|
+
*
|
|
7095
|
+
* ```ts
|
|
7096
|
+
* db.table.whereNotIn('a', [1, 2, 3]).orWhereNoIn('b', ['one', 'two']);
|
|
7097
|
+
* ```
|
|
7098
|
+
*/
|
|
7099
|
+
orWhereNotIn(...args) {
|
|
7100
|
+
return _queryWhereIn(
|
|
7101
|
+
this.clone(),
|
|
7102
|
+
false,
|
|
7103
|
+
args[0],
|
|
7104
|
+
args[1],
|
|
7105
|
+
true
|
|
7106
|
+
);
|
|
7024
7107
|
}
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7108
|
+
/**
|
|
7109
|
+
* `whereExists` is for support of the `WHERE EXISTS (query)` clause.
|
|
7110
|
+
*
|
|
7111
|
+
* This method is accepting the same arguments as `join`, see the {@link Join.join} section for more details.
|
|
7112
|
+
*
|
|
7113
|
+
* ```ts
|
|
7114
|
+
* // find users who have accounts
|
|
7115
|
+
* // find by a relation name if it's defined
|
|
7116
|
+
* db.user.whereExists('account');
|
|
7117
|
+
*
|
|
7118
|
+
* // find using a table and a join conditions
|
|
7119
|
+
* db.user.whereExists(db.account, 'account.id', 'user.id');
|
|
7120
|
+
*
|
|
7121
|
+
* // find using a query builder in a callback:
|
|
7122
|
+
* db.user.whereExists(db.account, (q) => q.on('account.id', '=', 'user.id'));
|
|
7123
|
+
* ```
|
|
7124
|
+
*/
|
|
7125
|
+
whereExists(arg, ...args) {
|
|
7126
|
+
return _queryWhere(
|
|
7127
|
+
this.clone(),
|
|
7128
|
+
existsArgs(arg, args)
|
|
7129
|
+
);
|
|
7028
7130
|
}
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7131
|
+
/**
|
|
7132
|
+
* Acts as `whereExists`, but prepends the condition with `OR`:
|
|
7133
|
+
*
|
|
7134
|
+
* ```ts
|
|
7135
|
+
* // find users who have an account or a profile,
|
|
7136
|
+
* // imagine that the user has both `account` and `profile` relations defined.
|
|
7137
|
+
* db.user.whereExist('account').orWhereExists('profile');
|
|
7138
|
+
* ```
|
|
7139
|
+
*/
|
|
7140
|
+
orWhereExists(arg, ...args) {
|
|
7141
|
+
return _queryOr(
|
|
7142
|
+
this.clone(),
|
|
7143
|
+
existsArgs(arg, args)
|
|
7144
|
+
);
|
|
7032
7145
|
}
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7146
|
+
/**
|
|
7147
|
+
* Acts as `whereExists`, but negates the condition with `NOT`:
|
|
7148
|
+
*
|
|
7149
|
+
* ```ts
|
|
7150
|
+
* // find users who don't have an account,
|
|
7151
|
+
* // image that the user `belongsTo` or `hasOne` account.
|
|
7152
|
+
* db.user.whereNotExist('account');
|
|
7153
|
+
* ```
|
|
7154
|
+
*
|
|
7155
|
+
* @param arg - relation name, or a query object, or a `with` table alias, or a callback returning a query object.
|
|
7156
|
+
* @param args - no arguments needed when the first argument is a relation name, or conditions to join the table with.
|
|
7157
|
+
*/
|
|
7158
|
+
whereNotExists(arg, ...args) {
|
|
7159
|
+
return _queryWhereNot(
|
|
7160
|
+
this.clone(),
|
|
7161
|
+
existsArgs(arg, args)
|
|
7162
|
+
);
|
|
7036
7163
|
}
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7164
|
+
/**
|
|
7165
|
+
* Acts as `whereExists`, but prepends the condition with `OR` and negates it with `NOT`:
|
|
7166
|
+
*
|
|
7167
|
+
* ```ts
|
|
7168
|
+
* // find users who don't have an account OR who don't have a profile
|
|
7169
|
+
* // imagine that the user has both `account` and `profile` relations defined.
|
|
7170
|
+
* db.user.whereNotExists('account').orWhereNotExists('profile');
|
|
7171
|
+
* ```
|
|
7172
|
+
*/
|
|
7173
|
+
orWhereNotExists(arg, ...args) {
|
|
7174
|
+
return _queryOrNot(
|
|
7175
|
+
this.clone(),
|
|
7176
|
+
existsArgs(arg, args)
|
|
7177
|
+
);
|
|
7040
7178
|
}
|
|
7041
7179
|
}
|
|
7042
7180
|
class WhereQueryBase extends QueryBase {
|
|
@@ -7044,21 +7182,447 @@ class WhereQueryBase extends QueryBase {
|
|
|
7044
7182
|
orchidCore.applyMixins(WhereQueryBase, [Where]);
|
|
7045
7183
|
|
|
7046
7184
|
class Join {
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7185
|
+
/**
|
|
7186
|
+
* ## Select relation
|
|
7187
|
+
*
|
|
7188
|
+
* Before joining a table, consider if selecting a relation is enough for your case:
|
|
7189
|
+
*
|
|
7190
|
+
* ```ts
|
|
7191
|
+
* // select users with profiles
|
|
7192
|
+
* // result type is Array<{ name: string, profile: Profile }>
|
|
7193
|
+
* await db.user.select('name', {
|
|
7194
|
+
* profile: (q) => q.profile,
|
|
7195
|
+
* });
|
|
7196
|
+
*
|
|
7197
|
+
* // select posts with counts of comments, order by comments count
|
|
7198
|
+
* // result type is Array<Post & { commentsCount: number }>
|
|
7199
|
+
* await db.post
|
|
7200
|
+
* .select('*', {
|
|
7201
|
+
* commentsCount: (q) => q.comments.count(),
|
|
7202
|
+
* })
|
|
7203
|
+
* .order({
|
|
7204
|
+
* commentsCount: 'DESC',
|
|
7205
|
+
* });
|
|
7206
|
+
*
|
|
7207
|
+
* // select authors with array of their book titles
|
|
7208
|
+
* // result type is Array<Author & { books: string[] }>
|
|
7209
|
+
* await db.author.select('*', {
|
|
7210
|
+
* books: (q) => q.books.pluck('title'),
|
|
7211
|
+
* });
|
|
7212
|
+
* ```
|
|
7213
|
+
*
|
|
7214
|
+
* Internally, such selects will use `LEFT JOIN LATERAL` to join a relation.
|
|
7215
|
+
* If you're loading users with profiles (one-to-one relation), and some users don't have a profile, `profile` property will have `NULL` for such users.
|
|
7216
|
+
* If you want to load only users that have profiles, and filter out the rest, add `.join()` method to the relation without arguments:
|
|
7217
|
+
*
|
|
7218
|
+
* ```ts
|
|
7219
|
+
* // load only users who have a profile
|
|
7220
|
+
* await db.user.select('*', {
|
|
7221
|
+
* profile: (q) => q.profile.join(),
|
|
7222
|
+
* });
|
|
7223
|
+
*
|
|
7224
|
+
* // load only users who have a specific profile
|
|
7225
|
+
* await db.user.select('*', {
|
|
7226
|
+
* profile: (q) => q.profile.join().where({ age: { gt: 20 } }),
|
|
7227
|
+
* });
|
|
7228
|
+
* ```
|
|
7229
|
+
*
|
|
7230
|
+
* You can also use this `.join()` method on the one-to-many relations, and records with empty array will be filtered out:
|
|
7231
|
+
*
|
|
7232
|
+
* ```ts
|
|
7233
|
+
* // posts that have no tags won't be loaded
|
|
7234
|
+
* // result type is Array<Post & { tags: Tag[] }>
|
|
7235
|
+
* db.post.select('*', {
|
|
7236
|
+
* tags: (q) => q.tags.join(),
|
|
7237
|
+
* });
|
|
7238
|
+
* ```
|
|
7239
|
+
*
|
|
7240
|
+
* # Joins
|
|
7241
|
+
*
|
|
7242
|
+
* `join` methods allows to join other tables, relations by name, [with](/guide/advanced-queries#with) statements, sub queries.
|
|
7243
|
+
*
|
|
7244
|
+
* All the `join` methods accept the same arguments, but returning type is different because with `join` it's guaranteed to load joined table, and with `leftJoin` the joined table columns may be `NULL` when no matching record was found.
|
|
7245
|
+
*
|
|
7246
|
+
* For the following examples, imagine we have a `User` table with `id` and `name`, and `Message` table with `id`, `text`, messages belongs to user via `userId` column:
|
|
7247
|
+
*
|
|
7248
|
+
* ```ts
|
|
7249
|
+
* export class UserTable extends BaseTable {
|
|
7250
|
+
* readonly table = 'user';
|
|
7251
|
+
* columns = this.setColumns((t) => ({
|
|
7252
|
+
* id: t.identity().primaryKey(),
|
|
7253
|
+
* name: t.text(),
|
|
7254
|
+
* }));
|
|
7255
|
+
*
|
|
7256
|
+
* relations = {
|
|
7257
|
+
* messages: this.hasMany(() => MessageTable, {
|
|
7258
|
+
* primaryKey: 'id',
|
|
7259
|
+
* foreignKey: 'userId',
|
|
7260
|
+
* }),
|
|
7261
|
+
* };
|
|
7262
|
+
* }
|
|
7263
|
+
*
|
|
7264
|
+
* export class MessageTable extends BaseTable {
|
|
7265
|
+
* readonly table = 'message';
|
|
7266
|
+
* columns = this.setColumns((t) => ({
|
|
7267
|
+
* id: t.identity().primaryKey(),
|
|
7268
|
+
* text: t.text(),
|
|
7269
|
+
* ...t.timestamps(),
|
|
7270
|
+
* }));
|
|
7271
|
+
*
|
|
7272
|
+
* relations = {
|
|
7273
|
+
* user: this.belongsTo(() => UserTable, {
|
|
7274
|
+
* primaryKey: 'id',
|
|
7275
|
+
* foreignKey: 'userId',
|
|
7276
|
+
* }),
|
|
7277
|
+
* };
|
|
7278
|
+
* }
|
|
7279
|
+
* ```
|
|
7280
|
+
*
|
|
7281
|
+
* ## join
|
|
7282
|
+
*
|
|
7283
|
+
* `join` is a method for SQL `JOIN`, which is equivalent to `INNER JOIN`, `LEFT INNERT JOIN`.
|
|
7284
|
+
*
|
|
7285
|
+
* When no matching record is found, it will skip records of the main table.
|
|
7286
|
+
*
|
|
7287
|
+
* ### join relation
|
|
7288
|
+
*
|
|
7289
|
+
* When relations are defined between the tables, you can join them by a relation name.
|
|
7290
|
+
* Joined table can be references from `where` and `select` by a relation name.
|
|
7291
|
+
*
|
|
7292
|
+
* ```ts
|
|
7293
|
+
* const result = await db.user
|
|
7294
|
+
* .join('messages')
|
|
7295
|
+
* // after joining a table, we can use it in `where` conditions:
|
|
7296
|
+
* .where({ 'messages.text': { startsWith: 'Hi' } })
|
|
7297
|
+
* .select(
|
|
7298
|
+
* 'name', // name is User column, table name may be omitted
|
|
7299
|
+
* 'messages.text', // text is the Message column, and the table name is required
|
|
7300
|
+
* );
|
|
7301
|
+
*
|
|
7302
|
+
* // result has the following type:
|
|
7303
|
+
* const ok: { name: string; text: string }[] = result;
|
|
7304
|
+
* ```
|
|
7305
|
+
*
|
|
7306
|
+
* The first argument can also be a callback, where instead of relation name as a string we're picking it as a property of `q`.
|
|
7307
|
+
* In such a way, we can alias the relation with `as`, add `where` conditions, use other query methods.
|
|
7308
|
+
*
|
|
7309
|
+
* ```ts
|
|
7310
|
+
* const result = await db.user.join((q) =>
|
|
7311
|
+
* q.messages.as('m').where({ text: 'some text' }),
|
|
7312
|
+
* );
|
|
7313
|
+
* ```
|
|
7314
|
+
*
|
|
7315
|
+
* Optionally, you can pass a second callback argument, it makes `on` and `orOn` methods available.
|
|
7316
|
+
*
|
|
7317
|
+
* But remember that when joining a relation, the needed `ON` conditions are already handled automatically.
|
|
7318
|
+
*
|
|
7319
|
+
* ```ts
|
|
7320
|
+
* const result = await db.user.join(
|
|
7321
|
+
* (q) => q.messages.as('m'),
|
|
7322
|
+
* (q) =>
|
|
7323
|
+
* q
|
|
7324
|
+
* .on('text', 'name') // additionally, match message with user name
|
|
7325
|
+
* .where({ text: 'some text' }), // you can add `where` in a second callback as well.
|
|
7326
|
+
* );
|
|
7327
|
+
* ```
|
|
7328
|
+
*
|
|
7329
|
+
* ### Selecting full joined records
|
|
7330
|
+
*
|
|
7331
|
+
* `select` supports selecting a full record of a previously joined table by passing a table name with `.*` at the end:
|
|
7332
|
+
*
|
|
7333
|
+
* ```ts
|
|
7334
|
+
* const result = await db.book.join('author').select('title', {
|
|
7335
|
+
* author: 'author.*',
|
|
7336
|
+
* });
|
|
7337
|
+
*
|
|
7338
|
+
* // result has the following type:
|
|
7339
|
+
* const ok: {
|
|
7340
|
+
* // title of the book
|
|
7341
|
+
* title: string;
|
|
7342
|
+
* // a full author record is included:
|
|
7343
|
+
* author: { id: number; name: string; updatedAt: Date; createdAt: Date };
|
|
7344
|
+
* }[] = result;
|
|
7345
|
+
* ```
|
|
7346
|
+
*
|
|
7347
|
+
* It works fine for `1:1` (`belongsTo`, `hasOne`) relations, but it may have an unexpected result for `1:M` or `M:M` (`hasMany`, `hasAndBelongsToMany`) relations.
|
|
7348
|
+
* For any kind of relation, it results in one main table record with data of exactly one joined table record, i.e. when selecting in this way, the records **won't** be collected into arrays.
|
|
7349
|
+
*
|
|
7350
|
+
* ```ts
|
|
7351
|
+
* const result = await db.user
|
|
7352
|
+
* .join('messages')
|
|
7353
|
+
* .where({ 'messages.text': { startsWith: 'Hi' } })
|
|
7354
|
+
* .select('name', { messages: 'messages.*' });
|
|
7355
|
+
*
|
|
7356
|
+
* // result has the following type:
|
|
7357
|
+
* const ok: {
|
|
7358
|
+
* name: string;
|
|
7359
|
+
* // full message is included:
|
|
7360
|
+
* messages: { id: number; text: string; updatedAt: Date; createdAt: Date };
|
|
7361
|
+
* }[] = result;
|
|
7362
|
+
* ```
|
|
7363
|
+
*
|
|
7364
|
+
* Because it's a one-to-many relation, one user has many messages, the user data will be duplicated for different messages data:
|
|
7365
|
+
*
|
|
7366
|
+
* | name | msg |
|
|
7367
|
+
* | ------ | ------------------------------ |
|
|
7368
|
+
* | user 1 | `{ id: 1, text: 'message 1' }` |
|
|
7369
|
+
* | user 1 | `{ id: 2, text: 'message 2' }` |
|
|
7370
|
+
* | user 1 | `{ id: 3, text: 'message 3' }` |
|
|
7371
|
+
*
|
|
7372
|
+
* ### join table
|
|
7373
|
+
*
|
|
7374
|
+
* If relation wasn't defined, provide a `db.table` instance and specify columns for the join.
|
|
7375
|
+
* Joined table can be references from `where` and `select` by a table name.
|
|
7376
|
+
*
|
|
7377
|
+
* ```ts
|
|
7378
|
+
* // Join message where userId = id:
|
|
7379
|
+
* db.user
|
|
7380
|
+
* .join(db.message, 'userId', 'id')
|
|
7381
|
+
* .where({ 'message.text': { startsWith: 'Hi' } })
|
|
7382
|
+
* .select('name', 'message.text');
|
|
7383
|
+
* ```
|
|
7384
|
+
*
|
|
7385
|
+
* Columns in the join list may be prefixed with table names for clarity:
|
|
7386
|
+
*
|
|
7387
|
+
* ```ts
|
|
7388
|
+
* db.user.join(db.message, 'message.userId', 'user.id');
|
|
7389
|
+
* ```
|
|
7390
|
+
*
|
|
7391
|
+
* Joined table can have an alias for referencing it further:
|
|
7392
|
+
*
|
|
7393
|
+
* ```ts
|
|
7394
|
+
* db.user
|
|
7395
|
+
* .join(db.message.as('m'), 'message.userId', 'user.id')
|
|
7396
|
+
* .where({ 'm.text': { startsWith: 'Hi' } })
|
|
7397
|
+
* .select('name', 'm.text');
|
|
7398
|
+
* ```
|
|
7399
|
+
*
|
|
7400
|
+
* Joined table can be selected as an object as well as the relation join above:
|
|
7401
|
+
*
|
|
7402
|
+
* ```ts
|
|
7403
|
+
* const result = await db.user
|
|
7404
|
+
* .join(db.message.as('m'), 'message.userId', 'user.id')
|
|
7405
|
+
* .where({ 'm.text': { startsWith: 'Hi' } })
|
|
7406
|
+
* .select('name', { msg: 'm.*' });
|
|
7407
|
+
*
|
|
7408
|
+
* // result has the following type:
|
|
7409
|
+
* const ok: {
|
|
7410
|
+
* name: string;
|
|
7411
|
+
* // full message is included as msg:
|
|
7412
|
+
* msg: { id: number; text: string; updatedAt: Date; createdAt: Date };
|
|
7413
|
+
* }[] = result;
|
|
7414
|
+
* ```
|
|
7415
|
+
*
|
|
7416
|
+
* You can provide a custom comparison operator
|
|
7417
|
+
*
|
|
7418
|
+
* ```ts
|
|
7419
|
+
* db.user.join(db.message, 'userId', '!=', 'id');
|
|
7420
|
+
* ```
|
|
7421
|
+
*
|
|
7422
|
+
* Join can accept raw SQL for the `ON` part of join:
|
|
7423
|
+
*
|
|
7424
|
+
* ```ts
|
|
7425
|
+
* db.user.join(
|
|
7426
|
+
* db.message,
|
|
7427
|
+
* db.user.sql`lower("message"."text") = lower("user"."name")`,
|
|
7428
|
+
* );
|
|
7429
|
+
* ```
|
|
7430
|
+
*
|
|
7431
|
+
* Join can accept raw SQL instead of columns:
|
|
7432
|
+
*
|
|
7433
|
+
* ```ts
|
|
7434
|
+
* db.user.join(
|
|
7435
|
+
* db.message,
|
|
7436
|
+
* db.user.sql`lower("message"."text")`,
|
|
7437
|
+
* db.user.sql`lower("user"."name")`,
|
|
7438
|
+
* );
|
|
7439
|
+
*
|
|
7440
|
+
* // with operator:
|
|
7441
|
+
* db.user.join(
|
|
7442
|
+
* db.message,
|
|
7443
|
+
* db.user.sql`lower("message"."text")`,
|
|
7444
|
+
* '!=',
|
|
7445
|
+
* db.user.sql`lower("user"."name")`,
|
|
7446
|
+
* );
|
|
7447
|
+
* ```
|
|
7448
|
+
*
|
|
7449
|
+
* To join based on multiple columns, you can provide an object where keys are joining table columns, and values are main table columns or a raw SQL:
|
|
7450
|
+
*
|
|
7451
|
+
* ```ts
|
|
7452
|
+
* db.user.join(db.message, {
|
|
7453
|
+
* userId: 'id',
|
|
7454
|
+
*
|
|
7455
|
+
* // with table names:
|
|
7456
|
+
* 'message.userId': 'user.id',
|
|
7457
|
+
*
|
|
7458
|
+
* // value can be a raw SQL expression:
|
|
7459
|
+
* text: db.user.sql`lower("user"."name")`,
|
|
7460
|
+
* });
|
|
7461
|
+
* ```
|
|
7462
|
+
*
|
|
7463
|
+
* Join all records without conditions by providing `true`:
|
|
7464
|
+
*
|
|
7465
|
+
* ```ts
|
|
7466
|
+
* db.user.join(db.message, true);
|
|
7467
|
+
* ```
|
|
7468
|
+
*
|
|
7469
|
+
* Join methods can accept a callback with a special query builder that has `on` and `orOn` methods for handling advanced cases:
|
|
7470
|
+
*
|
|
7471
|
+
* ```ts
|
|
7472
|
+
* db.user.join(
|
|
7473
|
+
* db.message,
|
|
7474
|
+
* (q) =>
|
|
7475
|
+
* q
|
|
7476
|
+
* // left column is the db.message column, right column is the db.user column
|
|
7477
|
+
* .on('userId', 'id')
|
|
7478
|
+
* // table names can be provided:
|
|
7479
|
+
* .on('message.userId', 'user.id')
|
|
7480
|
+
* // operator can be specified:
|
|
7481
|
+
* .on('userId', '!=', 'id')
|
|
7482
|
+
* // operator can be specified with table names as well:
|
|
7483
|
+
* .on('message.userId', '!=', 'user.id')
|
|
7484
|
+
* // `.orOn` takes the same arguments as `.on` and acts like `.or`:
|
|
7485
|
+
* .on('userId', 'id') // where message.userId = user.id
|
|
7486
|
+
* .orOn('text', 'name'), // or message.text = user.name
|
|
7487
|
+
* );
|
|
7488
|
+
* ```
|
|
7489
|
+
*
|
|
7490
|
+
* Join query builder supports all `where` methods: `.where`, `.whereIn`, `.whereExists`, and all `.or`, `.not`, and `.orNot` forms.
|
|
7491
|
+
*
|
|
7492
|
+
* Column names in the where conditions are applied for the joined table, but you can specify a table name to add a condition for the main table.
|
|
7493
|
+
*
|
|
7494
|
+
* ```ts
|
|
7495
|
+
* db.user.join(db.message, (q) =>
|
|
7496
|
+
* q
|
|
7497
|
+
* .on('userId', 'id')
|
|
7498
|
+
* .where({
|
|
7499
|
+
* // not prefixed column name is for joined table:
|
|
7500
|
+
* text: { startsWith: 'hello' },
|
|
7501
|
+
* // specify a table name to set condition on the main table:
|
|
7502
|
+
* 'user.name': 'Bob',
|
|
7503
|
+
* })
|
|
7504
|
+
* // id is a column of a joined table Message
|
|
7505
|
+
* .whereIn('id', [1, 2, 3])
|
|
7506
|
+
* // condition for id of a user
|
|
7507
|
+
* .whereIn('user.id', [4, 5, 6]),
|
|
7508
|
+
* );
|
|
7509
|
+
* ```
|
|
7510
|
+
*
|
|
7511
|
+
* The query above will generate the following SQL (simplified):
|
|
7512
|
+
*
|
|
7513
|
+
* ```sql
|
|
7514
|
+
* SELECT * FROM "user"
|
|
7515
|
+
* JOIN "message"
|
|
7516
|
+
* ON "message"."userId" = "user"."id"
|
|
7517
|
+
* AND "message"."text" ILIKE 'hello%'
|
|
7518
|
+
* AND "user"."name" = 'Bob'
|
|
7519
|
+
* AND "message"."id" IN (1, 2, 3)
|
|
7520
|
+
* AND "user"."id" IN (4, 5, 6)
|
|
7521
|
+
* ```
|
|
7522
|
+
*
|
|
7523
|
+
* The join argument can be a query with `select`, `where`, and other methods. In such case, it will be handled as a sub query:
|
|
7524
|
+
*
|
|
7525
|
+
* ```ts
|
|
7526
|
+
* db.user.join(
|
|
7527
|
+
* db.message
|
|
7528
|
+
* .select('id', 'userId', 'text')
|
|
7529
|
+
* .where({ text: { startsWith: 'Hi' } })
|
|
7530
|
+
* .as('t'),
|
|
7531
|
+
* 'userId',
|
|
7532
|
+
* 'id',
|
|
7533
|
+
* );
|
|
7534
|
+
* ```
|
|
7535
|
+
*
|
|
7536
|
+
* It will produce such SQL:
|
|
7537
|
+
*
|
|
7538
|
+
* ```sql
|
|
7539
|
+
* SELECT * FROM "user"
|
|
7540
|
+
* JOIN (
|
|
7541
|
+
* SELECT "t"."id", "t"."userId", "t"."text"
|
|
7542
|
+
* FROM "message" AS "t"
|
|
7543
|
+
* ) "t" ON "t"."userId" = "user"."id"
|
|
7544
|
+
* ```
|
|
7545
|
+
*
|
|
7546
|
+
* @param arg - {@link JoinFirstArg}
|
|
7547
|
+
* @param args - {@link JoinArgs}
|
|
7548
|
+
*/
|
|
7549
|
+
join(arg, ...args) {
|
|
7550
|
+
return _join(this.clone(), true, "JOIN", arg, args);
|
|
7050
7551
|
}
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7552
|
+
/**
|
|
7553
|
+
* `leftJoin` is a method for SQL `LEFT JOIN`, which is equivalent to `OUTER JOIN`, `LEFT OUTER JOIN`.
|
|
7554
|
+
*
|
|
7555
|
+
* When no matching record is found, it will fill joined table columns with `NULL` values in the result rows.
|
|
7556
|
+
*
|
|
7557
|
+
* Works just like `join`, except for result type that may have `null`:
|
|
7558
|
+
*
|
|
7559
|
+
* ```ts
|
|
7560
|
+
* const result = await db.user
|
|
7561
|
+
* .leftJoin('messages')
|
|
7562
|
+
* .select('name', 'messages.text');
|
|
7563
|
+
*
|
|
7564
|
+
* // the same query, but joining table explicitly
|
|
7565
|
+
* const result2: typeof result = await db.user
|
|
7566
|
+
* .leftJoin(db.message, 'userId', 'id')
|
|
7567
|
+
* .select('name', 'message.text');
|
|
7568
|
+
*
|
|
7569
|
+
* // result has the following type:
|
|
7570
|
+
* const ok: { name: string; text: string | null }[] = result;
|
|
7571
|
+
* ```
|
|
7572
|
+
*
|
|
7573
|
+
* @param arg - {@link JoinFirstArg}
|
|
7574
|
+
* @param args - {@link JoinArgs}
|
|
7575
|
+
*/
|
|
7576
|
+
leftJoin(arg, ...args) {
|
|
7577
|
+
return _join(this.clone(), false, "LEFT JOIN", arg, args);
|
|
7054
7578
|
}
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7579
|
+
/**
|
|
7580
|
+
* `rightJoin` is a method for SQL `RIGHT JOIN`, which is equivalent to `RIGHT OUTER JOIN`.
|
|
7581
|
+
*
|
|
7582
|
+
* Takes the same arguments as `json`.
|
|
7583
|
+
*
|
|
7584
|
+
* It will load all records from the joining table, and fill the main table columns with `null` when no match is found.
|
|
7585
|
+
*
|
|
7586
|
+
* The columns of the table you're joining to are becoming nullable when using `rightJoin`.
|
|
7587
|
+
*
|
|
7588
|
+
* ```ts
|
|
7589
|
+
* const result = await db.user
|
|
7590
|
+
* .rightJoin('messages')
|
|
7591
|
+
* .select('name', 'messages.text');
|
|
7592
|
+
*
|
|
7593
|
+
* // even though name is not a nullable column, it becomes nullable after using rightJoin
|
|
7594
|
+
* const ok: { name: string | null; text: string }[] = result;
|
|
7595
|
+
* ```
|
|
7596
|
+
*
|
|
7597
|
+
* @param arg - {@link JoinFirstArg}
|
|
7598
|
+
* @param args - {@link JoinArgs}
|
|
7599
|
+
*/
|
|
7600
|
+
rightJoin(arg, ...args) {
|
|
7601
|
+
return _join(this.clone(), true, "RIGHT JOIN", arg, args);
|
|
7058
7602
|
}
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
7603
|
+
/**
|
|
7604
|
+
* `fullJoin` is a method for SQL `FULL JOIN`, which is equivalent to `FULL OUTER JOIN`.
|
|
7605
|
+
*
|
|
7606
|
+
* Takes the same arguments as `json`.
|
|
7607
|
+
*
|
|
7608
|
+
* It will load all records from the joining table, both sides of the join may result in `null` values when there is no match.
|
|
7609
|
+
*
|
|
7610
|
+
* All columns become nullable after using `fullJoin`.
|
|
7611
|
+
*
|
|
7612
|
+
* ```ts
|
|
7613
|
+
* const result = await db.user
|
|
7614
|
+
* .rightJoin('messages')
|
|
7615
|
+
* .select('name', 'messages.text');
|
|
7616
|
+
*
|
|
7617
|
+
* // all columns can be null
|
|
7618
|
+
* const ok: { name: string | null; text: string | null }[] = result;
|
|
7619
|
+
* ```
|
|
7620
|
+
*
|
|
7621
|
+
* @param arg - {@link JoinFirstArg}
|
|
7622
|
+
* @param args - {@link JoinArgs}
|
|
7623
|
+
*/
|
|
7624
|
+
fullJoin(arg, ...args) {
|
|
7625
|
+
return _join(this.clone(), false, "FULL JOIN", arg, args);
|
|
7062
7626
|
}
|
|
7063
7627
|
/**
|
|
7064
7628
|
* `joinLateral` allows joining a table with a sub-query that can reference the main table of current query and the other joined tables.
|
|
@@ -7247,7 +7811,7 @@ class OnQueryBuilder extends WhereQueryBase {
|
|
|
7247
7811
|
}
|
|
7248
7812
|
}
|
|
7249
7813
|
|
|
7250
|
-
class JsonModifiers
|
|
7814
|
+
class JsonModifiers {
|
|
7251
7815
|
/**
|
|
7252
7816
|
* Return a JSON value/object/array where a given value is set at the given path.
|
|
7253
7817
|
* The path is an array of keys to access the value.
|
|
@@ -7450,7 +8014,10 @@ class JsonMethods {
|
|
|
7450
8014
|
* @param coalesce
|
|
7451
8015
|
*/
|
|
7452
8016
|
json(coalesce) {
|
|
7453
|
-
return queryJson(
|
|
8017
|
+
return queryJson(
|
|
8018
|
+
this.clone(),
|
|
8019
|
+
coalesce
|
|
8020
|
+
);
|
|
7454
8021
|
}
|
|
7455
8022
|
}
|
|
7456
8023
|
|
|
@@ -8034,12 +8601,7 @@ class With {
|
|
|
8034
8601
|
});
|
|
8035
8602
|
}
|
|
8036
8603
|
pushQueryValue(q, "with", [args[0], options || orchidCore.emptyObject, query]);
|
|
8037
|
-
return setQueryObjectValue(
|
|
8038
|
-
q,
|
|
8039
|
-
"withShapes",
|
|
8040
|
-
args[0],
|
|
8041
|
-
shape
|
|
8042
|
-
);
|
|
8604
|
+
return setQueryObjectValue(q, "withShapes", args[0], shape);
|
|
8043
8605
|
}
|
|
8044
8606
|
}
|
|
8045
8607
|
|
|
@@ -8152,12 +8714,13 @@ var __spreadValues$3 = (a, b) => {
|
|
|
8152
8714
|
return a;
|
|
8153
8715
|
};
|
|
8154
8716
|
const _queryChangeCounter = (self, op, data) => {
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8717
|
+
const q = self.q;
|
|
8718
|
+
q.type = "update";
|
|
8719
|
+
if (!q.select) {
|
|
8720
|
+
if (q.returnType === "oneOrThrow" || q.returnType === "valueOrThrow") {
|
|
8721
|
+
q.throwOnNotFound = true;
|
|
8159
8722
|
}
|
|
8160
|
-
|
|
8723
|
+
q.returnType = "rowCount";
|
|
8161
8724
|
}
|
|
8162
8725
|
let map;
|
|
8163
8726
|
if (typeof data === "object") {
|
|
@@ -8171,13 +8734,14 @@ const _queryChangeCounter = (self, op, data) => {
|
|
|
8171
8734
|
pushQueryValue(self, "updateData", map);
|
|
8172
8735
|
return self;
|
|
8173
8736
|
};
|
|
8174
|
-
const update = (
|
|
8175
|
-
q
|
|
8176
|
-
|
|
8177
|
-
|
|
8737
|
+
const update = (self) => {
|
|
8738
|
+
const q = self.q;
|
|
8739
|
+
q.type = "update";
|
|
8740
|
+
if (!q.select) {
|
|
8741
|
+
q.returnType = "rowCount";
|
|
8178
8742
|
}
|
|
8179
|
-
throwIfNoWhere(
|
|
8180
|
-
return
|
|
8743
|
+
throwIfNoWhere(self, "update");
|
|
8744
|
+
return self;
|
|
8181
8745
|
};
|
|
8182
8746
|
const _queryUpdate = (query, arg) => {
|
|
8183
8747
|
const { q } = query;
|
|
@@ -8210,8 +8774,16 @@ const _queryUpdate = (query, arg) => {
|
|
|
8210
8774
|
if (value !== null && value !== void 0 && !orchidCore.isExpression(value)) {
|
|
8211
8775
|
if (value instanceof Db) {
|
|
8212
8776
|
if (value.q.type) {
|
|
8213
|
-
const as = saveSearchAlias(
|
|
8214
|
-
|
|
8777
|
+
const as = saveSearchAlias(
|
|
8778
|
+
query,
|
|
8779
|
+
"q",
|
|
8780
|
+
"withShapes"
|
|
8781
|
+
);
|
|
8782
|
+
pushQueryValue(query, "with", [
|
|
8783
|
+
as,
|
|
8784
|
+
orchidCore.emptyObject,
|
|
8785
|
+
value
|
|
8786
|
+
]);
|
|
8215
8787
|
set[key] = new RawSQL(`(SELECT * FROM "${as}")`);
|
|
8216
8788
|
}
|
|
8217
8789
|
} else {
|
|
@@ -8417,7 +8989,10 @@ class Update {
|
|
|
8417
8989
|
* @param arg - data to update records with, may have specific values, raw SQL, queries, or callbacks with sub-queries.
|
|
8418
8990
|
*/
|
|
8419
8991
|
update(arg) {
|
|
8420
|
-
return _queryUpdate(
|
|
8992
|
+
return _queryUpdate(
|
|
8993
|
+
this.clone(),
|
|
8994
|
+
arg
|
|
8995
|
+
);
|
|
8421
8996
|
}
|
|
8422
8997
|
/**
|
|
8423
8998
|
* `updateRaw` is for updating records with raw expression.
|
|
@@ -8473,7 +9048,10 @@ class Update {
|
|
|
8473
9048
|
* @param arg - data to update records with, may have specific values, raw SQL, queries, or callbacks with sub-queries.
|
|
8474
9049
|
*/
|
|
8475
9050
|
updateOrThrow(arg) {
|
|
8476
|
-
return _queryUpdateOrThrow(
|
|
9051
|
+
return _queryUpdateOrThrow(
|
|
9052
|
+
this.clone(),
|
|
9053
|
+
arg
|
|
9054
|
+
);
|
|
8477
9055
|
}
|
|
8478
9056
|
/**
|
|
8479
9057
|
* Increments a column by `1`, returns a count of updated records by default.
|
|
@@ -8514,7 +9092,11 @@ class Update {
|
|
|
8514
9092
|
* @param data - name of the column to increment, or an object with columns and values to add
|
|
8515
9093
|
*/
|
|
8516
9094
|
increment(data) {
|
|
8517
|
-
return _queryChangeCounter(
|
|
9095
|
+
return _queryChangeCounter(
|
|
9096
|
+
this.clone(),
|
|
9097
|
+
"+",
|
|
9098
|
+
data
|
|
9099
|
+
);
|
|
8518
9100
|
}
|
|
8519
9101
|
/**
|
|
8520
9102
|
* Decrements a column by `1`, returns a count of updated records by default.
|
|
@@ -8555,7 +9137,11 @@ class Update {
|
|
|
8555
9137
|
* @param data - name of the column to decrement, or an object with columns and values to subtract
|
|
8556
9138
|
*/
|
|
8557
9139
|
decrement(data) {
|
|
8558
|
-
return _queryChangeCounter(
|
|
9140
|
+
return _queryChangeCounter(
|
|
9141
|
+
this.clone(),
|
|
9142
|
+
"-",
|
|
9143
|
+
data
|
|
9144
|
+
);
|
|
8559
9145
|
}
|
|
8560
9146
|
}
|
|
8561
9147
|
|
|
@@ -8696,14 +9282,12 @@ class Headline extends orchidCore.Expression {
|
|
|
8696
9282
|
}
|
|
8697
9283
|
AggregateMethods.prototype.headline = function(search, params) {
|
|
8698
9284
|
var _a;
|
|
8699
|
-
const
|
|
9285
|
+
const q = this;
|
|
9286
|
+
const source = (_a = q.q.sources) == null ? void 0 : _a[search];
|
|
8700
9287
|
if (!source)
|
|
8701
|
-
throw new OrchidOrmInternalError(
|
|
8702
|
-
this,
|
|
8703
|
-
`Search \`${search}\` is not defined`
|
|
8704
|
-
);
|
|
9288
|
+
throw new OrchidOrmInternalError(q, `Search \`${search}\` is not defined`);
|
|
8705
9289
|
return new Headline(
|
|
8706
|
-
|
|
9290
|
+
q.q,
|
|
8707
9291
|
source,
|
|
8708
9292
|
params
|
|
8709
9293
|
);
|
|
@@ -9208,7 +9792,7 @@ class ScopeMethods {
|
|
|
9208
9792
|
var _a;
|
|
9209
9793
|
const q = this.clone();
|
|
9210
9794
|
if (!((_a = q.q.scopes) == null ? void 0 : _a[scope])) {
|
|
9211
|
-
const s =
|
|
9795
|
+
const s = q.internal.scopes[scope];
|
|
9212
9796
|
if (s.and)
|
|
9213
9797
|
pushQueryArray(q, "and", s.and);
|
|
9214
9798
|
if (s.or)
|
|
@@ -9297,7 +9881,9 @@ class SoftDeleteMethods {
|
|
|
9297
9881
|
* ```
|
|
9298
9882
|
*/
|
|
9299
9883
|
hardDelete(..._args) {
|
|
9300
|
-
return _queryDelete(
|
|
9884
|
+
return _queryDelete(
|
|
9885
|
+
this.clone().unscope("nonDeleted")
|
|
9886
|
+
);
|
|
9301
9887
|
}
|
|
9302
9888
|
}
|
|
9303
9889
|
|
|
@@ -9465,7 +10051,11 @@ class QueryMethods {
|
|
|
9465
10051
|
* @param columns - column names or a raw SQL
|
|
9466
10052
|
*/
|
|
9467
10053
|
distinct(...columns) {
|
|
9468
|
-
return pushQueryArray(
|
|
10054
|
+
return pushQueryArray(
|
|
10055
|
+
this.clone(),
|
|
10056
|
+
"distinct",
|
|
10057
|
+
columns
|
|
10058
|
+
);
|
|
9469
10059
|
}
|
|
9470
10060
|
/**
|
|
9471
10061
|
* The `find` method is available only for tables which has exactly one primary key.
|
|
@@ -9534,7 +10124,10 @@ class QueryMethods {
|
|
|
9534
10124
|
* @param args - `where` conditions
|
|
9535
10125
|
*/
|
|
9536
10126
|
findBy(...args) {
|
|
9537
|
-
return _queryFindBy(
|
|
10127
|
+
return _queryFindBy(
|
|
10128
|
+
this.clone(),
|
|
10129
|
+
args
|
|
10130
|
+
);
|
|
9538
10131
|
}
|
|
9539
10132
|
/**
|
|
9540
10133
|
* The same as `where(conditions).takeOptional()`, it will filter records and add a `LIMIT 1`.
|
|
@@ -9549,7 +10142,10 @@ class QueryMethods {
|
|
|
9549
10142
|
* @param args - `where` conditions
|
|
9550
10143
|
*/
|
|
9551
10144
|
findByOptional(...args) {
|
|
9552
|
-
return _queryFindByOptional(
|
|
10145
|
+
return _queryFindByOptional(
|
|
10146
|
+
this.clone(),
|
|
10147
|
+
args
|
|
10148
|
+
);
|
|
9553
10149
|
}
|
|
9554
10150
|
/**
|
|
9555
10151
|
* Specifies the schema to be used as a prefix of a table name.
|
|
@@ -9605,7 +10201,11 @@ class QueryMethods {
|
|
|
9605
10201
|
* @param columns - column names or a raw SQL
|
|
9606
10202
|
*/
|
|
9607
10203
|
group(...columns) {
|
|
9608
|
-
return pushQueryArray(
|
|
10204
|
+
return pushQueryArray(
|
|
10205
|
+
this.clone(),
|
|
10206
|
+
"group",
|
|
10207
|
+
columns
|
|
10208
|
+
);
|
|
9609
10209
|
}
|
|
9610
10210
|
/**
|
|
9611
10211
|
* Add a window with `window` and use it later by its name for aggregate or window functions:
|
|
@@ -9691,7 +10291,11 @@ class QueryMethods {
|
|
|
9691
10291
|
new RawSQL(args)
|
|
9692
10292
|
);
|
|
9693
10293
|
}
|
|
9694
|
-
return pushQueryArray(
|
|
10294
|
+
return pushQueryArray(
|
|
10295
|
+
this.clone(),
|
|
10296
|
+
"order",
|
|
10297
|
+
args
|
|
10298
|
+
);
|
|
9695
10299
|
}
|
|
9696
10300
|
/**
|
|
9697
10301
|
* Adds a limit clause to the query.
|
|
@@ -9869,7 +10473,11 @@ class QueryMethods {
|
|
|
9869
10473
|
* @param fn - helper function
|
|
9870
10474
|
*/
|
|
9871
10475
|
makeHelper(fn) {
|
|
9872
|
-
return
|
|
10476
|
+
return (query, ...args) => {
|
|
10477
|
+
const q = query.clone();
|
|
10478
|
+
q.q.as = void 0;
|
|
10479
|
+
return fn(q, ...args);
|
|
10480
|
+
};
|
|
9873
10481
|
}
|
|
9874
10482
|
/**
|
|
9875
10483
|
* Use `column` method to interpolate column names inside SQL templates.
|