pqb 0.23.5 → 0.24.1

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