pqb 0.30.5 → 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.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as orchid_core from 'orchid-core';
2
- import { QueryResultRow, AdapterConfigBase, AdapterBase, QueryInput, Sql, RecordUnknown, RecordKeyTrue, EmptyObject, QueryBaseCommon, QueryColumns, QueryMetaBase, QueryReturnType, QueryThen, Expression, QueryColumn, MaybeArray, SelectableBase, TemplateLiteralArgs, PickOutputTypeAndOperators, PickQueryResult, OperatorToSQL, ColumnsShapeBase, ColumnsParsers, RecordString, PickQueryTable, FnUnknownToUnknown, ExpressionChain, getValueKey, PickQueryShape, PickQueryTableMetaResult, EmptyTuple, PickQueryMeta, PickQueryMetaResultReturnType, QueryColumnToNullable, PickQueryMetaShape, PickQueryTableMetaResultShape, PickQueryMetaResultWindows, QueryColumnBooleanOrNull, ExpressionData, ValExpression, PickOutputType, SQLQueryArgs, ColumnSchemaConfig, DateColumnData, Code, TimeInterval, ColumnTypeSchemaArg, ColumnDataBase, ArrayMethodsData, RawSQLBase, RawSQLValues, ExpressionTypeMethod, DynamicSQLArg, StaticSQLArgs, ForeignKeyTable, ColumnNameOfTable, BaseNumberData, PickColumnBaseData, ColumnWithDefault, StringTypeData, PrimaryKeyColumn, ParseColumn, EncodeColumn, PickQueryMetaResult, QueryColumnsInit, DefaultSelectColumns, CoreQueryScopes, DbBase, QueryCatch, TransactionState, ColumnTypeBase, CoreBaseOperators, PickQueryUniqueProperties, IsQuery, PickQueryMetaShapeResultReturnType, MergeObjects, PickQueryResultUniqueColumns, QueryInternalBase, PickQueryReturnType, PickType, ColumnShapeOutput, PickQueryMetaReturnType, UniqueColumn, TimestampHelpers, Codes, ColumnDataCheckBase, PickQueryTableMetaShape } from 'orchid-core';
2
+ import { QueryResultRow, AdapterConfigBase, AdapterBase, QueryInput, Sql, RecordUnknown, RecordKeyTrue, EmptyObject, QueryBaseCommon, QueryColumns, QueryMetaBase, QueryReturnType, QueryThen, Expression, QueryColumn, MaybeArray, SelectableBase, TemplateLiteralArgs, PickOutputTypeAndOperators, PickQueryResult, OperatorToSQL, ColumnsShapeBase, ColumnsParsers, RecordString, PickQueryTable, FnUnknownToUnknown, ExpressionChain, getValueKey, PickQueryShape, PickQueryTableMetaResult, EmptyTuple, PickQueryMeta, PickQueryMetaResultReturnType, QueryColumnToNullable, PickQueryMetaShape, PickQueryTableMetaResultShape, PickQueryMetaResultWindows, QueryColumnBooleanOrNull, ExpressionData, ValExpression, PickOutputType, SQLQueryArgs, ColumnSchemaConfig, DateColumnData, Code, TimeInterval, ColumnTypeSchemaArg, ColumnDataBase, ArrayMethodsData, RawSQLBase, RawSQLValues, ExpressionTypeMethod, DynamicSQLArg, StaticSQLArgs, ForeignKeyTable, ColumnNameOfTable, BaseNumberData, PickColumnBaseData, ColumnWithDefault, StringTypeData, PrimaryKeyColumn, ParseColumn, EncodeColumn, PickQueryMetaResult, QueryColumnsInit, DefaultSelectColumns, CoreQueryScopes, DbBase, QueryCatch, TransactionState, ColumnTypeBase, CoreBaseOperators, PickQueryUniqueProperties, IsQuery, PickQueryMetaShapeResultReturnType, MergeObjects, PickQueryResultUniqueColumns, QueryInternalBase, PickQueryReturnType, PickType, ColumnShapeOutput, OperatorsNullable, PickQueryMetaReturnType, UniqueColumn, TimestampHelpers, Codes, ColumnDataCheckBase, PickQueryTableMetaShape } from 'orchid-core';
3
3
  import { PoolConfig, Pool, PoolClient } from 'pg';
4
4
  import { inspect } from 'node:util';
5
5
  import { AsyncLocalStorage } from 'node:async_hooks';
@@ -2155,6 +2155,15 @@ declare class Where {
2155
2155
  * ```ts
2156
2156
  * db.table.whereIn(['id', 'name'], sql`((1, 'one'), (2, 'two'))`);
2157
2157
  * ```
2158
+ *
2159
+ * When empty set of values is given, `whereIn` will resolve into a {@link QueryMethods.none} query that has a special behavior.
2160
+ *
2161
+ * ```ts
2162
+ * // following queries resolves into `none`:
2163
+ * db.table.where('id', [])
2164
+ * db.table.where(['id', 'name'], [])
2165
+ * db.table.where({ id: [] })
2166
+ * ```
2158
2167
  */
2159
2168
  whereIn<T extends PickQueryMetaRelations, Column extends WhereInColumn<T>>(this: T, ...args: [column: Column, values: WhereInValues<T, Column>] | [arg: WhereInArg<T>]): WhereResult<T>;
2160
2169
  /**
@@ -4124,6 +4133,7 @@ declare class Create {
4124
4133
  * db.table.create(data).onConflictDoNothing();
4125
4134
  *
4126
4135
  * // single column:
4136
+ * // (this requires a composite primary key or unique index, see below)
4127
4137
  * db.table.create(data).onConfict('email').merge();
4128
4138
  *
4129
4139
  * // array of columns:
@@ -4139,6 +4149,34 @@ declare class Create {
4139
4149
  * .merge();
4140
4150
  * ```
4141
4151
  *
4152
+ * :::info
4153
+ * A primary key or a unique index for a **single** column can be fined on a column:
4154
+ *
4155
+ * ```ts
4156
+ * export class MyTable extends BaseTable {
4157
+ * columns = this.setColumns((t) => ({
4158
+ * pkey: t.uuid().primaryKey(),
4159
+ * unique: t.string().unique(),
4160
+ * }));
4161
+ * }
4162
+ * ```
4163
+ *
4164
+ * But for composite primary keys or indexes (having multiple columns), define it in a separate function:
4165
+ *
4166
+ * ```ts
4167
+ * export class MyTable extends BaseTable {
4168
+ * columns = this.setColumns(
4169
+ * (t) => ({
4170
+ * one: t.integer(),
4171
+ * two: t.string(),
4172
+ * three: t.boolean(),
4173
+ * }),
4174
+ * (t) => [t.primaryKey(['one', 'two']), t.unique(['two', 'three'])],
4175
+ * );
4176
+ * }
4177
+ * ```
4178
+ * :::
4179
+ *
4142
4180
  * You can use the `sql` function exported from your `BaseTable` file in onConflict.
4143
4181
  * It can be useful to specify a condition when you have a partial index:
4144
4182
  *
@@ -4963,10 +5001,10 @@ type SelectAsSelectable<Arg> = {
4963
5001
  } : never;
4964
5002
  }[keyof Arg];
4965
5003
  type SelectAsValueResult<T extends SelectSelf, Arg> = Arg extends keyof T['meta']['selectable'] ? T['meta']['selectable'][Arg]['column'] : Arg extends Expression ? Arg['result']['value'] : Arg extends (q: never) => QueryBase ? SelectSubQueryResult<ReturnType<Arg>> : Arg extends (q: never) => Expression ? ReturnType<Arg>['result']['value'] : Arg extends (q: never) => QueryBase | Expression ? SelectSubQueryResult<Exclude<ReturnType<Arg>, Expression>> | Exclude<ReturnType<Arg>, QueryBase>['result']['value'] : never;
4966
- type SelectSubQueryResult<Arg extends SelectSelf> = QueryReturnsAll<Arg['returnType']> extends true ? ColumnsShapeToObjectArray<Arg['result']> : Arg['returnType'] extends 'valueOrThrow' ? Arg['result']['value'] : Arg['returnType'] extends 'pluck' ? ColumnsShapeToPluck<Arg['result']> : Arg['returnType'] extends 'one' ? ColumnsShapeToNullableObject<Arg['result']> : ColumnsShapeToObject<Arg['result']>;
5004
+ type SelectSubQueryResult<Arg extends SelectSelf> = QueryReturnsAll<Arg['returnType']> extends true ? ColumnsShapeToObjectArray<Arg['result']> : Arg['returnType'] extends 'value' | 'valueOrThrow' ? Arg['result']['value'] : Arg['returnType'] extends 'pluck' ? ColumnsShapeToPluck<Arg['result']> : Arg['returnType'] extends 'one' ? ColumnsShapeToNullableObject<Arg['result']> : ColumnsShapeToObject<Arg['result']>;
4967
5005
  declare const addParserForRawExpression: (q: PickQueryQ, key: string | getValueKey, raw: Expression) => void;
4968
5006
  declare const addParserForSelectItem: <T extends PickQueryMeta>(q: T, as: string | getValueKey | undefined, key: string, arg: SelectableOrExpression<T> | Query) => string | Expression | Query;
4969
- declare const processSelectArg: <T extends SelectSelf>(q: T, as: string | undefined, arg: SelectArg<T>, columnAs?: string | getValueKey) => SelectItem;
5007
+ declare const processSelectArg: <T extends SelectSelf>(q: T, as: string | undefined, arg: SelectArg<T>, columnAs?: string | getValueKey) => SelectItem | undefined;
4970
5008
  declare const setParserForSelectedString: (q: PickQueryQ, arg: string, as: string | getValueKey | undefined, columnAs?: string | getValueKey) => string;
4971
5009
  declare const getShapeFromSelect: (q: QueryBase, isSubQuery?: boolean) => QueryColumns;
4972
5010
  declare function _querySelect<T extends SelectSelf, Columns extends SelectArg<T>[]>(q: T, columns: Columns): SelectResult<T, Columns>;
@@ -6620,6 +6658,55 @@ declare class QueryMethods<ColumnTypes> {
6620
6658
  * await db.table.all().update(data); // -> 0
6621
6659
  * await db.table.all().delete(); // -> 0
6622
6660
  * ```
6661
+ *
6662
+ * When it's being used in sub-selects, it will return empty arrays, `undefined`'s, or `0` for count,
6663
+ * or it will throw if the sub-query require a result:
6664
+ *
6665
+ * ```ts
6666
+ * await db.user.select({
6667
+ * // returns empty array
6668
+ * pets: (q) => q.pets.none(),
6669
+ * // returns `undefined`
6670
+ * firstPet: (q) => q.pets.none().takeOptional(),
6671
+ * // throws NotFound error
6672
+ * requriedFirstPet: (q) => q.pets.none().take(),
6673
+ * // returns `undefined`
6674
+ * firstPetName: (q) => q.pets.none().getOptional('name'),
6675
+ * // throws NotFound error
6676
+ * requiredFirstPetName: (q) => q.pets.none().get('name'),
6677
+ * // returns empty array
6678
+ * petsNames: (q) => q.pets.none().pluck('name'),
6679
+ * // returns 0
6680
+ * petsCount: (q) => q.pets.none().count(),
6681
+ * });
6682
+ * ```
6683
+ *
6684
+ * When the `none` query is being used for joins that require match, the host query will return an empty result:
6685
+ *
6686
+ * ```ts
6687
+ * // all the following queries will resolve into empty arrays
6688
+ *
6689
+ * await db.user.select({
6690
+ * pets: (q) => q.pets.join().none(),
6691
+ * });
6692
+ *
6693
+ * await db.user.join(
6694
+ * (q) => q.pets.none(),
6695
+ * (q) => q,
6696
+ * );
6697
+ *
6698
+ * await db.user.join('pets', (q) => q.none());
6699
+ * ```
6700
+ *
6701
+ * When it's being used in `leftJoin` or `fullJoin`, it implicitly adds `ON false` into the join's SQL.
6702
+ *
6703
+ * ```ts
6704
+ * // this query can return user records
6705
+ * await db.user.leftJoin('pets', (q) => q.none());
6706
+ *
6707
+ * // this query won't return user records, because of the added where condition
6708
+ * await db.user.leftJoin('pets', (q) => q.none()).where({ 'pets.name': 'Kitty' });
6709
+ * ```
6623
6710
  */
6624
6711
  none<T>(this: T): T;
6625
6712
  /**
@@ -6967,7 +7054,9 @@ type SetQueryReturnsPluckColumnKindResult<T extends PickQueryMetaResult, Kind ex
6967
7054
  } : K extends 'returnType' ? 'pluck' : K extends 'result' ? Result : K extends 'then' ? QueryThen<T['result']['value']['outputType'][]> : T[K];
6968
7055
  } & QueryMetaHasSelect;
6969
7056
  type SetQueryReturnsValueOrThrow<T extends PickQueryMeta, Arg extends GetStringArg<T>> = SetQueryReturnsColumnOrThrow<T, T['meta']['selectable'][Arg]['column']> & T['meta']['selectable'][Arg]['column']['operators'];
6970
- type SetQueryReturnsValueOptional<T extends PickQueryMeta, Arg extends GetStringArg<T>> = SetQueryReturnsColumnOptional<T, T['meta']['selectable'][Arg]['column']> & T['meta']['selectable'][Arg]['column']['operators'];
7057
+ type SetQueryReturnsValueOptional<T extends PickQueryMeta, Arg extends GetStringArg<T>> = SetQueryReturnsColumnOptional<T, {
7058
+ [K in keyof T['meta']['selectable'][Arg]['column']]: K extends 'outputType' ? T['meta']['selectable'][Arg]['column'][K] | undefined : T['meta']['selectable'][Arg]['column'][K];
7059
+ }> & Omit<T['meta']['selectable'][Arg]['column']['operators'], 'equals' | 'not'> & OperatorsNullable<T['meta']['selectable'][Arg]['column']>;
6971
7060
  type SetQueryReturnsColumnOrThrow<T, Column extends PickOutputType> = {
6972
7061
  [K in keyof T]: K extends 'result' ? {
6973
7062
  value: Column;
@@ -7444,7 +7533,7 @@ interface ColumnsShapeToObject<Shape extends QueryColumns> {
7444
7533
  interface ColumnsShapeToNullableObject<Shape extends QueryColumns> {
7445
7534
  dataType: 'object';
7446
7535
  type: ObjectType<Shape>;
7447
- outputType: ObjectOutput<Shape> | null;
7536
+ outputType: ObjectOutput<Shape> | undefined;
7448
7537
  queryType: ObjectQuery<Shape> | null;
7449
7538
  operators: OperatorsAny;
7450
7539
  }
package/dist/index.js CHANGED
@@ -2593,6 +2593,32 @@ const makeJoinQueryBuilder = (joinedQuery, joinedShapes, joinTo) => {
2593
2593
  return q;
2594
2594
  };
2595
2595
 
2596
+ const noneMethods = {
2597
+ // `then` resolves or rejects based on return type of the query.
2598
+ // It is `async` so it returns a chainable Promise.
2599
+ async then(resolve, reject) {
2600
+ const type = this.q.returnType;
2601
+ if (!type || type === "all" || type === "rows" || type === "pluck")
2602
+ resolve == null ? void 0 : resolve([]);
2603
+ else if (type === "one" || type === "value" || type === "void")
2604
+ resolve == null ? void 0 : resolve();
2605
+ else if (type === "rowCount")
2606
+ resolve == null ? void 0 : resolve(0);
2607
+ else
2608
+ reject == null ? void 0 : reject(new NotFoundError(this));
2609
+ },
2610
+ // `catch` returns a Promise, so it is chainable with then/catch.
2611
+ catch: () => new Promise(orchidCore.noop)
2612
+ };
2613
+ const _queryNone = (q) => {
2614
+ if (isQueryNone(q))
2615
+ return q;
2616
+ q = extendQuery(q, noneMethods);
2617
+ pushQueryValue(q, "and", new RawSQL("false"));
2618
+ return q;
2619
+ };
2620
+ const isQueryNone = (q) => q.then === noneMethods.then;
2621
+
2596
2622
  var __defProp$b = Object.defineProperty;
2597
2623
  var __defProps$3 = Object.defineProperties;
2598
2624
  var __getOwnPropDescs$3 = Object.getOwnPropertyDescriptors;
@@ -2612,36 +2638,39 @@ var __spreadValues$b = (a, b) => {
2612
2638
  return a;
2613
2639
  };
2614
2640
  var __spreadProps$3 = (a, b) => __defProps$3(a, __getOwnPropDescs$3(b));
2615
- const _join = (q, require2, type, first, args) => {
2641
+ const _join = (query, require2, type, first, args) => {
2616
2642
  var _a, _b;
2617
2643
  let joinKey;
2618
2644
  let shape;
2619
2645
  let parsers;
2620
2646
  let joinSubQuery = false;
2621
2647
  if (typeof first === "function") {
2622
- first = first(q.relations);
2648
+ first = first(query.relations);
2623
2649
  first.joinQueryAfterCallback = first.joinQuery;
2624
2650
  }
2625
2651
  if (typeof first === "object") {
2626
- const q2 = first;
2627
- joinSubQuery = getIsJoinSubQuery(q2);
2628
- joinKey = q2.q.as || q2.table;
2652
+ if (require2 && isQueryNone(first)) {
2653
+ return _queryNone(query);
2654
+ }
2655
+ const q = first;
2656
+ joinSubQuery = getIsJoinSubQuery(q);
2657
+ joinKey = q.q.as || q.table;
2629
2658
  if (joinKey) {
2630
- shape = getShapeFromSelect(q2, joinSubQuery);
2631
- parsers = q2.q.parsers;
2659
+ shape = getShapeFromSelect(q, joinSubQuery);
2660
+ parsers = q.q.parsers;
2632
2661
  if (joinSubQuery) {
2633
- first = q2.clone();
2662
+ first = q.clone();
2634
2663
  first.shape = shape;
2635
2664
  }
2636
2665
  }
2637
2666
  } else {
2638
2667
  joinKey = first;
2639
- const relation = q.relations[joinKey];
2668
+ const relation = query.relations[joinKey];
2640
2669
  if (relation) {
2641
2670
  shape = getShapeFromSelect(relation.relationConfig.query);
2642
2671
  parsers = relation.relationConfig.query.q.parsers;
2643
2672
  } else {
2644
- shape = (_a = q.q.withShapes) == null ? void 0 : _a[joinKey];
2673
+ shape = (_a = query.q.withShapes) == null ? void 0 : _a[joinKey];
2645
2674
  if (shape) {
2646
2675
  if (!require2)
2647
2676
  shape = __spreadValues$b({}, shape);
@@ -2657,20 +2686,20 @@ const _join = (q, require2, type, first, args) => {
2657
2686
  }
2658
2687
  if (joinKey) {
2659
2688
  setQueryObjectValue(
2660
- q,
2689
+ query,
2661
2690
  "joinedShapes",
2662
2691
  joinKey,
2663
2692
  shape
2664
2693
  );
2665
2694
  setQueryObjectValue(
2666
- q,
2695
+ query,
2667
2696
  "joinedParsers",
2668
2697
  joinKey,
2669
2698
  parsers
2670
2699
  );
2671
2700
  }
2672
2701
  const joinArgs = processJoinArgs(
2673
- q,
2702
+ query,
2674
2703
  first,
2675
2704
  args,
2676
2705
  joinSubQuery
@@ -2680,20 +2709,22 @@ const _join = (q, require2, type, first, args) => {
2680
2709
  if (j.q.select || !j.internal.columnsForSelectAll) {
2681
2710
  const shape2 = getShapeFromSelect(j, true);
2682
2711
  setQueryObjectValue(
2683
- q,
2712
+ query,
2684
2713
  "joinedShapes",
2685
2714
  joinKey,
2686
2715
  shape2
2687
2716
  );
2688
2717
  setQueryObjectValue(
2689
- q,
2718
+ query,
2690
2719
  "joinedParsers",
2691
2720
  joinKey,
2692
2721
  j.q.parsers
2693
2722
  );
2694
2723
  }
2724
+ } else if (require2 && "r" in joinArgs && isQueryNone(joinArgs.r)) {
2725
+ return _queryNone(query);
2695
2726
  }
2696
- return pushQueryValue(q, "join", {
2727
+ return pushQueryValue(query, "join", {
2697
2728
  type,
2698
2729
  args: joinArgs
2699
2730
  });
@@ -3328,6 +3359,26 @@ const addParserForSelectItem = (q, as, key, arg) => {
3328
3359
  );
3329
3360
  });
3330
3361
  }
3362
+ if (query.returnType === "valueOrThrow" || query.returnType === "oneOrThrow") {
3363
+ pushQueryValue(
3364
+ q,
3365
+ "transform",
3366
+ (data) => {
3367
+ if (Array.isArray(data)) {
3368
+ for (const item of data) {
3369
+ if (item[key] === void 0) {
3370
+ throw new NotFoundError(q);
3371
+ }
3372
+ }
3373
+ } else {
3374
+ if (data[key] === void 0) {
3375
+ throw new NotFoundError(q);
3376
+ }
3377
+ }
3378
+ return data;
3379
+ }
3380
+ );
3381
+ }
3331
3382
  }
3332
3383
  return arg;
3333
3384
  }
@@ -3344,7 +3395,11 @@ const processSelectArg = (q, as, arg, columnAs) => {
3344
3395
  let value = arg[key];
3345
3396
  if (typeof value === "function") {
3346
3397
  value = resolveSubQueryCallback(q, value);
3347
- if (!orchidCore.isExpression(value) && value.joinQuery) {
3398
+ if (isQueryNone(value)) {
3399
+ if (value.q.innerJoinLateral) {
3400
+ return;
3401
+ }
3402
+ } else if (!orchidCore.isExpression(value) && value.joinQuery) {
3348
3403
  value = value.joinQuery(value, q);
3349
3404
  let query;
3350
3405
  const returnType = value.q.returnType;
@@ -3501,11 +3556,18 @@ const maybeUnNameColumn = (column, isSubQuery) => {
3501
3556
  return isSubQuery && (column == null ? void 0 : column.data.name) ? orchidCore.setColumnData(column, "name", void 0) : column;
3502
3557
  };
3503
3558
  function _querySelect(q, args) {
3504
- if (!args.length) {
3559
+ const len = args.length;
3560
+ if (!len) {
3505
3561
  return q;
3506
3562
  }
3507
3563
  const as = q.q.as || q.table;
3508
- const selectArgs = args.map((item) => processSelectArg(q, as, item));
3564
+ const selectArgs = new Array(len);
3565
+ for (let i = 0; i < len; i++) {
3566
+ selectArgs[i] = processSelectArg(q, as, args[i]);
3567
+ if (!selectArgs[i]) {
3568
+ return _queryNone(q);
3569
+ }
3570
+ }
3509
3571
  return pushQueryArray(q, "select", selectArgs);
3510
3572
  }
3511
3573
  class Select {
@@ -3855,7 +3917,37 @@ const selectAllSql = (table, query, quotedAs) => {
3855
3917
  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(", ")) || "*";
3856
3918
  };
3857
3919
  const pushSubQuerySql = (ctx, query, as, list, quotedAs) => {
3920
+ var _a;
3858
3921
  const { returnType = "all" } = query.q;
3922
+ if (isQueryNone(query)) {
3923
+ let sql;
3924
+ switch (returnType) {
3925
+ case "one":
3926
+ case "oneOrThrow":
3927
+ case "void":
3928
+ return;
3929
+ case "value":
3930
+ case "valueOrThrow":
3931
+ if (((_a = query.q.expr) == null ? void 0 : _a.result.value) instanceof IntegerBaseColumn) {
3932
+ sql = "0";
3933
+ } else {
3934
+ return;
3935
+ }
3936
+ break;
3937
+ case "all":
3938
+ case "pluck":
3939
+ case "rows":
3940
+ sql = `'[]'::json`;
3941
+ break;
3942
+ case "rowCount":
3943
+ sql = "0";
3944
+ break;
3945
+ default:
3946
+ throw new UnhandledTypeError(query, returnType);
3947
+ }
3948
+ list.push(`${sql} "${as}"`);
3949
+ return;
3950
+ }
3859
3951
  if (query.q.joinedForSelect) {
3860
3952
  let sql;
3861
3953
  switch (returnType) {
@@ -6509,6 +6601,7 @@ class Create {
6509
6601
  * db.table.create(data).onConflictDoNothing();
6510
6602
  *
6511
6603
  * // single column:
6604
+ * // (this requires a composite primary key or unique index, see below)
6512
6605
  * db.table.create(data).onConfict('email').merge();
6513
6606
  *
6514
6607
  * // array of columns:
@@ -6524,6 +6617,34 @@ class Create {
6524
6617
  * .merge();
6525
6618
  * ```
6526
6619
  *
6620
+ * :::info
6621
+ * A primary key or a unique index for a **single** column can be fined on a column:
6622
+ *
6623
+ * ```ts
6624
+ * export class MyTable extends BaseTable {
6625
+ * columns = this.setColumns((t) => ({
6626
+ * pkey: t.uuid().primaryKey(),
6627
+ * unique: t.string().unique(),
6628
+ * }));
6629
+ * }
6630
+ * ```
6631
+ *
6632
+ * But for composite primary keys or indexes (having multiple columns), define it in a separate function:
6633
+ *
6634
+ * ```ts
6635
+ * export class MyTable extends BaseTable {
6636
+ * columns = this.setColumns(
6637
+ * (t) => ({
6638
+ * one: t.integer(),
6639
+ * two: t.string(),
6640
+ * three: t.boolean(),
6641
+ * }),
6642
+ * (t) => [t.primaryKey(['one', 'two']), t.unique(['two', 'three'])],
6643
+ * );
6644
+ * }
6645
+ * ```
6646
+ * :::
6647
+ *
6527
6648
  * You can use the `sql` function exported from your `BaseTable` file in onConflict.
6528
6649
  * It can be useful to specify a condition when you have a partial index:
6529
6650
  *
@@ -8431,6 +8552,9 @@ const _queryOrNot = (q, args) => {
8431
8552
  const _queryWhereIn = (q, and, arg, values, not) => {
8432
8553
  let item;
8433
8554
  if (values) {
8555
+ if ("length" in values && !values.length) {
8556
+ return _queryNone(q);
8557
+ }
8434
8558
  if (Array.isArray(arg)) {
8435
8559
  item = {
8436
8560
  IN: {
@@ -8444,7 +8568,11 @@ const _queryWhereIn = (q, and, arg, values, not) => {
8444
8568
  } else {
8445
8569
  item = {};
8446
8570
  for (const key in arg) {
8447
- item[key] = { in: arg[key] };
8571
+ const values2 = arg[key];
8572
+ if ("length" in values2 && !values2.length) {
8573
+ return _queryNone(q);
8574
+ }
8575
+ item[key] = { in: values2 };
8448
8576
  }
8449
8577
  }
8450
8578
  if (not)
@@ -8993,6 +9121,15 @@ class Where {
8993
9121
  * ```ts
8994
9122
  * db.table.whereIn(['id', 'name'], sql`((1, 'one'), (2, 'two'))`);
8995
9123
  * ```
9124
+ *
9125
+ * When empty set of values is given, `whereIn` will resolve into a {@link QueryMethods.none} query that has a special behavior.
9126
+ *
9127
+ * ```ts
9128
+ * // following queries resolves into `none`:
9129
+ * db.table.where('id', [])
9130
+ * db.table.where(['id', 'name'], [])
9131
+ * db.table.where({ id: [] })
9132
+ * ```
8996
9133
  */
8997
9134
  whereIn(...args) {
8998
9135
  return _queryWhereIn(
@@ -10197,24 +10334,6 @@ class TransformMethods {
10197
10334
  }
10198
10335
  }
10199
10336
 
10200
- const noneMethods = {
10201
- // `then` resolves or rejects based on return type of the query.
10202
- // It is `async` so it returns a chainable Promise.
10203
- async then(resolve, reject) {
10204
- const type = this.q.returnType;
10205
- if (!type || type === "all" || type === "rows" || type === "pluck")
10206
- resolve == null ? void 0 : resolve([]);
10207
- else if (type === "one" || type === "value" || type === "void")
10208
- resolve == null ? void 0 : resolve();
10209
- else if (type === "rowCount")
10210
- resolve == null ? void 0 : resolve(0);
10211
- else
10212
- reject == null ? void 0 : reject(new NotFoundError(this));
10213
- },
10214
- // `catch` returns a Promise, so it is chainable with then/catch.
10215
- catch: () => new Promise(orchidCore.noop)
10216
- };
10217
-
10218
10337
  class ScopeMethods {
10219
10338
  /**
10220
10339
  * See {@link ScopeMethods}
@@ -10998,9 +11117,58 @@ class QueryMethods {
10998
11117
  * await db.table.all().update(data); // -> 0
10999
11118
  * await db.table.all().delete(); // -> 0
11000
11119
  * ```
11120
+ *
11121
+ * When it's being used in sub-selects, it will return empty arrays, `undefined`'s, or `0` for count,
11122
+ * or it will throw if the sub-query require a result:
11123
+ *
11124
+ * ```ts
11125
+ * await db.user.select({
11126
+ * // returns empty array
11127
+ * pets: (q) => q.pets.none(),
11128
+ * // returns `undefined`
11129
+ * firstPet: (q) => q.pets.none().takeOptional(),
11130
+ * // throws NotFound error
11131
+ * requriedFirstPet: (q) => q.pets.none().take(),
11132
+ * // returns `undefined`
11133
+ * firstPetName: (q) => q.pets.none().getOptional('name'),
11134
+ * // throws NotFound error
11135
+ * requiredFirstPetName: (q) => q.pets.none().get('name'),
11136
+ * // returns empty array
11137
+ * petsNames: (q) => q.pets.none().pluck('name'),
11138
+ * // returns 0
11139
+ * petsCount: (q) => q.pets.none().count(),
11140
+ * });
11141
+ * ```
11142
+ *
11143
+ * When the `none` query is being used for joins that require match, the host query will return an empty result:
11144
+ *
11145
+ * ```ts
11146
+ * // all the following queries will resolve into empty arrays
11147
+ *
11148
+ * await db.user.select({
11149
+ * pets: (q) => q.pets.join().none(),
11150
+ * });
11151
+ *
11152
+ * await db.user.join(
11153
+ * (q) => q.pets.none(),
11154
+ * (q) => q,
11155
+ * );
11156
+ *
11157
+ * await db.user.join('pets', (q) => q.none());
11158
+ * ```
11159
+ *
11160
+ * When it's being used in `leftJoin` or `fullJoin`, it implicitly adds `ON false` into the join's SQL.
11161
+ *
11162
+ * ```ts
11163
+ * // this query can return user records
11164
+ * await db.user.leftJoin('pets', (q) => q.none());
11165
+ *
11166
+ * // this query won't return user records, because of the added where condition
11167
+ * await db.user.leftJoin('pets', (q) => q.none()).where({ 'pets.name': 'Kitty' });
11168
+ * ```
11001
11169
  */
11002
11170
  none() {
11003
- return this.then === noneMethods.then ? this : extendQuery(this, noneMethods);
11171
+ return _queryNone(this);
11004
11172
  }
11005
11173
  /**
11006
11174
  * `modify` allows modifying the query with your function: