pqb 0.30.4 → 0.30.6

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, emptyObject, isTemplateLiteralArgs, ColumnTypeBase, setColumnData, pushColumnData, quoteObjectKey, toArray, singleQuote, addCode, singleQuoteArray, objectHasValues, columnDefaultArgumentToCode, columnErrorMessagesToCode, getValueKey, addValue, isExpression, joinTruthy, numberDataToCode, stringDataToCode, getDefaultLanguage, dateDataToCode, pushOrNewArrayToObject, arrayDataToCode, noop, emptyArray, callWithThis, setParserToQuery, applyTransforms, isRawSQL, pushOrNewArray, setDefaultNowFn, setDefaultLanguage, makeTimestampsHelpers, setCurrentColumnName, setAdapterConnectRetry, isObjectEmpty, ValExpression, applyMixins, toSnakeCase, snakeCaseKey } from 'orchid-core';
1
+ import { ExpressionTypeMethod, Expression, RawSQLBase, emptyObject, isTemplateLiteralArgs, ColumnTypeBase, setColumnData, pushColumnData, quoteObjectKey, toArray, singleQuote, addCode, singleQuoteArray, objectHasValues, columnDefaultArgumentToCode, columnErrorMessagesToCode, getValueKey, addValue, isExpression, joinTruthy, numberDataToCode, stringDataToCode, getDefaultLanguage, dateDataToCode, pushOrNewArrayToObject, noop, arrayDataToCode, emptyArray, callWithThis, setParserToQuery, applyTransforms, isRawSQL, pushOrNewArray, setDefaultNowFn, setDefaultLanguage, makeTimestampsHelpers, setCurrentColumnName, setAdapterConnectRetry, isObjectEmpty, ValExpression, applyMixins, 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';
@@ -2591,6 +2591,32 @@ const makeJoinQueryBuilder = (joinedQuery, joinedShapes, joinTo) => {
2591
2591
  return q;
2592
2592
  };
2593
2593
 
2594
+ const noneMethods = {
2595
+ // `then` resolves or rejects based on return type of the query.
2596
+ // It is `async` so it returns a chainable Promise.
2597
+ async then(resolve, reject) {
2598
+ const type = this.q.returnType;
2599
+ if (!type || type === "all" || type === "rows" || type === "pluck")
2600
+ resolve == null ? void 0 : resolve([]);
2601
+ else if (type === "one" || type === "value" || type === "void")
2602
+ resolve == null ? void 0 : resolve();
2603
+ else if (type === "rowCount")
2604
+ resolve == null ? void 0 : resolve(0);
2605
+ else
2606
+ reject == null ? void 0 : reject(new NotFoundError(this));
2607
+ },
2608
+ // `catch` returns a Promise, so it is chainable with then/catch.
2609
+ catch: () => new Promise(noop)
2610
+ };
2611
+ const _queryNone = (q) => {
2612
+ if (isQueryNone(q))
2613
+ return q;
2614
+ q = extendQuery(q, noneMethods);
2615
+ pushQueryValue(q, "and", new RawSQL("false"));
2616
+ return q;
2617
+ };
2618
+ const isQueryNone = (q) => q.then === noneMethods.then;
2619
+
2594
2620
  var __defProp$b = Object.defineProperty;
2595
2621
  var __defProps$3 = Object.defineProperties;
2596
2622
  var __getOwnPropDescs$3 = Object.getOwnPropertyDescriptors;
@@ -2610,36 +2636,39 @@ var __spreadValues$b = (a, b) => {
2610
2636
  return a;
2611
2637
  };
2612
2638
  var __spreadProps$3 = (a, b) => __defProps$3(a, __getOwnPropDescs$3(b));
2613
- const _join = (q, require2, type, first, args) => {
2639
+ const _join = (query, require2, type, first, args) => {
2614
2640
  var _a, _b;
2615
2641
  let joinKey;
2616
2642
  let shape;
2617
2643
  let parsers;
2618
2644
  let joinSubQuery = false;
2619
2645
  if (typeof first === "function") {
2620
- first = first(q.relations);
2646
+ first = first(query.relations);
2621
2647
  first.joinQueryAfterCallback = first.joinQuery;
2622
2648
  }
2623
2649
  if (typeof first === "object") {
2624
- const q2 = first;
2625
- joinSubQuery = getIsJoinSubQuery(q2);
2626
- joinKey = q2.q.as || q2.table;
2650
+ if (require2 && isQueryNone(first)) {
2651
+ return _queryNone(query);
2652
+ }
2653
+ const q = first;
2654
+ joinSubQuery = getIsJoinSubQuery(q);
2655
+ joinKey = q.q.as || q.table;
2627
2656
  if (joinKey) {
2628
- shape = getShapeFromSelect(q2, joinSubQuery);
2629
- parsers = q2.q.parsers;
2657
+ shape = getShapeFromSelect(q, joinSubQuery);
2658
+ parsers = q.q.parsers;
2630
2659
  if (joinSubQuery) {
2631
- first = q2.clone();
2660
+ first = q.clone();
2632
2661
  first.shape = shape;
2633
2662
  }
2634
2663
  }
2635
2664
  } else {
2636
2665
  joinKey = first;
2637
- const relation = q.relations[joinKey];
2666
+ const relation = query.relations[joinKey];
2638
2667
  if (relation) {
2639
2668
  shape = getShapeFromSelect(relation.relationConfig.query);
2640
2669
  parsers = relation.relationConfig.query.q.parsers;
2641
2670
  } else {
2642
- shape = (_a = q.q.withShapes) == null ? void 0 : _a[joinKey];
2671
+ shape = (_a = query.q.withShapes) == null ? void 0 : _a[joinKey];
2643
2672
  if (shape) {
2644
2673
  if (!require2)
2645
2674
  shape = __spreadValues$b({}, shape);
@@ -2655,20 +2684,20 @@ const _join = (q, require2, type, first, args) => {
2655
2684
  }
2656
2685
  if (joinKey) {
2657
2686
  setQueryObjectValue(
2658
- q,
2687
+ query,
2659
2688
  "joinedShapes",
2660
2689
  joinKey,
2661
2690
  shape
2662
2691
  );
2663
2692
  setQueryObjectValue(
2664
- q,
2693
+ query,
2665
2694
  "joinedParsers",
2666
2695
  joinKey,
2667
2696
  parsers
2668
2697
  );
2669
2698
  }
2670
2699
  const joinArgs = processJoinArgs(
2671
- q,
2700
+ query,
2672
2701
  first,
2673
2702
  args,
2674
2703
  joinSubQuery
@@ -2678,20 +2707,22 @@ const _join = (q, require2, type, first, args) => {
2678
2707
  if (j.q.select || !j.internal.columnsForSelectAll) {
2679
2708
  const shape2 = getShapeFromSelect(j, true);
2680
2709
  setQueryObjectValue(
2681
- q,
2710
+ query,
2682
2711
  "joinedShapes",
2683
2712
  joinKey,
2684
2713
  shape2
2685
2714
  );
2686
2715
  setQueryObjectValue(
2687
- q,
2716
+ query,
2688
2717
  "joinedParsers",
2689
2718
  joinKey,
2690
2719
  j.q.parsers
2691
2720
  );
2692
2721
  }
2722
+ } else if (require2 && "r" in joinArgs && isQueryNone(joinArgs.r)) {
2723
+ return _queryNone(query);
2693
2724
  }
2694
- return pushQueryValue(q, "join", {
2725
+ return pushQueryValue(query, "join", {
2695
2726
  type,
2696
2727
  args: joinArgs
2697
2728
  });
@@ -3326,6 +3357,26 @@ const addParserForSelectItem = (q, as, key, arg) => {
3326
3357
  );
3327
3358
  });
3328
3359
  }
3360
+ if (query.returnType === "valueOrThrow" || query.returnType === "oneOrThrow") {
3361
+ pushQueryValue(
3362
+ q,
3363
+ "transform",
3364
+ (data) => {
3365
+ if (Array.isArray(data)) {
3366
+ for (const item of data) {
3367
+ if (item[key] === void 0) {
3368
+ throw new NotFoundError(q);
3369
+ }
3370
+ }
3371
+ } else {
3372
+ if (data[key] === void 0) {
3373
+ throw new NotFoundError(q);
3374
+ }
3375
+ }
3376
+ return data;
3377
+ }
3378
+ );
3379
+ }
3329
3380
  }
3330
3381
  return arg;
3331
3382
  }
@@ -3342,7 +3393,11 @@ const processSelectArg = (q, as, arg, columnAs) => {
3342
3393
  let value = arg[key];
3343
3394
  if (typeof value === "function") {
3344
3395
  value = resolveSubQueryCallback(q, value);
3345
- if (!isExpression(value) && value.joinQuery) {
3396
+ if (isQueryNone(value)) {
3397
+ if (value.q.innerJoinLateral) {
3398
+ return;
3399
+ }
3400
+ } else if (!isExpression(value) && value.joinQuery) {
3346
3401
  value = value.joinQuery(value, q);
3347
3402
  let query;
3348
3403
  const returnType = value.q.returnType;
@@ -3499,11 +3554,18 @@ const maybeUnNameColumn = (column, isSubQuery) => {
3499
3554
  return isSubQuery && (column == null ? void 0 : column.data.name) ? setColumnData(column, "name", void 0) : column;
3500
3555
  };
3501
3556
  function _querySelect(q, args) {
3502
- if (!args.length) {
3557
+ const len = args.length;
3558
+ if (!len) {
3503
3559
  return q;
3504
3560
  }
3505
3561
  const as = q.q.as || q.table;
3506
- const selectArgs = args.map((item) => processSelectArg(q, as, item));
3562
+ const selectArgs = new Array(len);
3563
+ for (let i = 0; i < len; i++) {
3564
+ selectArgs[i] = processSelectArg(q, as, args[i]);
3565
+ if (!selectArgs[i]) {
3566
+ return _queryNone(q);
3567
+ }
3568
+ }
3507
3569
  return pushQueryArray(q, "select", selectArgs);
3508
3570
  }
3509
3571
  class Select {
@@ -3853,7 +3915,37 @@ const selectAllSql = (table, query, quotedAs) => {
3853
3915
  return ((_a = query.join) == null ? void 0 : _a.length) ? ((_b = table.internal.columnsForSelectAll) == null ? void 0 : _b.map((item) => `${quotedAs}.${item}`).join(", ")) || `${quotedAs}.*` : ((_c = table.internal.columnsForSelectAll) == null ? void 0 : _c.join(", ")) || "*";
3854
3916
  };
3855
3917
  const pushSubQuerySql = (ctx, query, as, list, quotedAs) => {
3918
+ var _a;
3856
3919
  const { returnType = "all" } = query.q;
3920
+ if (isQueryNone(query)) {
3921
+ let sql;
3922
+ switch (returnType) {
3923
+ case "one":
3924
+ case "oneOrThrow":
3925
+ case "void":
3926
+ return;
3927
+ case "value":
3928
+ case "valueOrThrow":
3929
+ if (((_a = query.q.expr) == null ? void 0 : _a.result.value) instanceof IntegerBaseColumn) {
3930
+ sql = "0";
3931
+ } else {
3932
+ return;
3933
+ }
3934
+ break;
3935
+ case "all":
3936
+ case "pluck":
3937
+ case "rows":
3938
+ sql = `'[]'::json`;
3939
+ break;
3940
+ case "rowCount":
3941
+ sql = "0";
3942
+ break;
3943
+ default:
3944
+ throw new UnhandledTypeError(query, returnType);
3945
+ }
3946
+ list.push(`${sql} "${as}"`);
3947
+ return;
3948
+ }
3857
3949
  if (query.q.joinedForSelect) {
3858
3950
  let sql;
3859
3951
  switch (returnType) {
@@ -6507,6 +6599,7 @@ class Create {
6507
6599
  * db.table.create(data).onConflictDoNothing();
6508
6600
  *
6509
6601
  * // single column:
6602
+ * // (this requires a composite primary key or unique index, see below)
6510
6603
  * db.table.create(data).onConfict('email').merge();
6511
6604
  *
6512
6605
  * // array of columns:
@@ -6522,6 +6615,34 @@ class Create {
6522
6615
  * .merge();
6523
6616
  * ```
6524
6617
  *
6618
+ * :::info
6619
+ * A primary key or a unique index for a **single** column can be fined on a column:
6620
+ *
6621
+ * ```ts
6622
+ * export class MyTable extends BaseTable {
6623
+ * columns = this.setColumns((t) => ({
6624
+ * pkey: t.uuid().primaryKey(),
6625
+ * unique: t.string().unique(),
6626
+ * }));
6627
+ * }
6628
+ * ```
6629
+ *
6630
+ * But for composite primary keys or indexes (having multiple columns), define it in a separate function:
6631
+ *
6632
+ * ```ts
6633
+ * export class MyTable extends BaseTable {
6634
+ * columns = this.setColumns(
6635
+ * (t) => ({
6636
+ * one: t.integer(),
6637
+ * two: t.string(),
6638
+ * three: t.boolean(),
6639
+ * }),
6640
+ * (t) => [t.primaryKey(['one', 'two']), t.unique(['two', 'three'])],
6641
+ * );
6642
+ * }
6643
+ * ```
6644
+ * :::
6645
+ *
6525
6646
  * You can use the `sql` function exported from your `BaseTable` file in onConflict.
6526
6647
  * It can be useful to specify a condition when you have a partial index:
6527
6648
  *
@@ -8429,6 +8550,9 @@ const _queryOrNot = (q, args) => {
8429
8550
  const _queryWhereIn = (q, and, arg, values, not) => {
8430
8551
  let item;
8431
8552
  if (values) {
8553
+ if ("length" in values && !values.length) {
8554
+ return _queryNone(q);
8555
+ }
8432
8556
  if (Array.isArray(arg)) {
8433
8557
  item = {
8434
8558
  IN: {
@@ -8442,7 +8566,11 @@ const _queryWhereIn = (q, and, arg, values, not) => {
8442
8566
  } else {
8443
8567
  item = {};
8444
8568
  for (const key in arg) {
8445
- item[key] = { in: arg[key] };
8569
+ const values2 = arg[key];
8570
+ if ("length" in values2 && !values2.length) {
8571
+ return _queryNone(q);
8572
+ }
8573
+ item[key] = { in: values2 };
8446
8574
  }
8447
8575
  }
8448
8576
  if (not)
@@ -8991,6 +9119,15 @@ class Where {
8991
9119
  * ```ts
8992
9120
  * db.table.whereIn(['id', 'name'], sql`((1, 'one'), (2, 'two'))`);
8993
9121
  * ```
9122
+ *
9123
+ * When empty set of values is given, `whereIn` will resolve into a {@link QueryMethods.none} query that has a special behavior.
9124
+ *
9125
+ * ```ts
9126
+ * // following queries resolves into `none`:
9127
+ * db.table.where('id', [])
9128
+ * db.table.where(['id', 'name'], [])
9129
+ * db.table.where({ id: [] })
9130
+ * ```
8994
9131
  */
8995
9132
  whereIn(...args) {
8996
9133
  return _queryWhereIn(
@@ -10195,24 +10332,6 @@ class TransformMethods {
10195
10332
  }
10196
10333
  }
10197
10334
 
10198
- const noneMethods = {
10199
- // `then` resolves or rejects based on return type of the query.
10200
- // It is `async` so it returns a chainable Promise.
10201
- async then(resolve, reject) {
10202
- const type = this.q.returnType;
10203
- if (!type || type === "all" || type === "rows" || type === "pluck")
10204
- resolve == null ? void 0 : resolve([]);
10205
- else if (type === "one" || type === "value" || type === "void")
10206
- resolve == null ? void 0 : resolve();
10207
- else if (type === "rowCount")
10208
- resolve == null ? void 0 : resolve(0);
10209
- else
10210
- reject == null ? void 0 : reject(new NotFoundError(this));
10211
- },
10212
- // `catch` returns a Promise, so it is chainable with then/catch.
10213
- catch: () => new Promise(noop)
10214
- };
10215
-
10216
10335
  class ScopeMethods {
10217
10336
  /**
10218
10337
  * See {@link ScopeMethods}
@@ -10996,9 +11115,58 @@ class QueryMethods {
10996
11115
  * await db.table.all().update(data); // -> 0
10997
11116
  * await db.table.all().delete(); // -> 0
10998
11117
  * ```
11118
+ *
11119
+ * When it's being used in sub-selects, it will return empty arrays, `undefined`'s, or `0` for count,
11120
+ * or it will throw if the sub-query require a result:
11121
+ *
11122
+ * ```ts
11123
+ * await db.user.select({
11124
+ * // returns empty array
11125
+ * pets: (q) => q.pets.none(),
11126
+ * // returns `undefined`
11127
+ * firstPet: (q) => q.pets.none().takeOptional(),
11128
+ * // throws NotFound error
11129
+ * requriedFirstPet: (q) => q.pets.none().take(),
11130
+ * // returns `undefined`
11131
+ * firstPetName: (q) => q.pets.none().getOptional('name'),
11132
+ * // throws NotFound error
11133
+ * requiredFirstPetName: (q) => q.pets.none().get('name'),
11134
+ * // returns empty array
11135
+ * petsNames: (q) => q.pets.none().pluck('name'),
11136
+ * // returns 0
11137
+ * petsCount: (q) => q.pets.none().count(),
11138
+ * });
11139
+ * ```
11140
+ *
11141
+ * When the `none` query is being used for joins that require match, the host query will return an empty result:
11142
+ *
11143
+ * ```ts
11144
+ * // all the following queries will resolve into empty arrays
11145
+ *
11146
+ * await db.user.select({
11147
+ * pets: (q) => q.pets.join().none(),
11148
+ * });
11149
+ *
11150
+ * await db.user.join(
11151
+ * (q) => q.pets.none(),
11152
+ * (q) => q,
11153
+ * );
11154
+ *
11155
+ * await db.user.join('pets', (q) => q.none());
11156
+ * ```
11157
+ *
11158
+ * When it's being used in `leftJoin` or `fullJoin`, it implicitly adds `ON false` into the join's SQL.
11159
+ *
11160
+ * ```ts
11161
+ * // this query can return user records
11162
+ * await db.user.leftJoin('pets', (q) => q.none());
11163
+ *
11164
+ * // this query won't return user records, because of the added where condition
11165
+ * await db.user.leftJoin('pets', (q) => q.none()).where({ 'pets.name': 'Kitty' });
11166
+ * ```
10999
11167
  */
11000
11168
  none() {
11001
- return this.then === noneMethods.then ? this : extendQuery(this, noneMethods);
11169
+ return _queryNone(this);
11002
11170
  }
11003
11171
  /**
11004
11172
  * `modify` allows modifying the query with your function: