@prisma-next/sql-orm-client 0.9.0-dev.3 → 0.9.0-dev.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +543 -8
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +454 -36
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -20
- package/src/collection.ts +538 -31
package/dist/index.d.mts
CHANGED
|
@@ -516,57 +516,489 @@ declare class Collection<TContract extends Contract<SqlStorage>, ModelName exten
|
|
|
516
516
|
/** @internal */
|
|
517
517
|
readonly includeRefinementMode: boolean;
|
|
518
518
|
constructor(ctx: CollectionContext<TContract>, modelName: ModelName, options?: CollectionInit<TContract>);
|
|
519
|
+
/**
|
|
520
|
+
* Narrow the collection with a `WHERE` predicate. Returns a new
|
|
521
|
+
* collection — chain further builders or run a terminal on it.
|
|
522
|
+
*
|
|
523
|
+
* Accepts a callback receiving a typed model accessor, a raw
|
|
524
|
+
* `WhereArg` expression, or a shorthand field/value object. Multiple
|
|
525
|
+
* calls are AND-combined.
|
|
526
|
+
*
|
|
527
|
+
* ```typescript
|
|
528
|
+
* // Callback form with column-level operators:
|
|
529
|
+
* const matches = await db.orm.User.where((u) => u.email.eq('alice@example.com')).all();
|
|
530
|
+
*
|
|
531
|
+
* // Shorthand object form:
|
|
532
|
+
* const user = await db.orm.User.where({ id: 1, active: true }).first();
|
|
533
|
+
*
|
|
534
|
+
* // Chained AND — still a builder, run a terminal to execute:
|
|
535
|
+
* const adults = await db.orm.User.where({ active: true }).where((u) => u.age.gt(18)).all();
|
|
536
|
+
* ```
|
|
537
|
+
*/
|
|
519
538
|
where(fn: (model: ModelAccessor<TContract, ModelName>) => WhereDirectInput): Collection<TContract, ModelName, Row, WithWhereState<State>>;
|
|
520
539
|
where(input: WhereDirectInput): Collection<TContract, ModelName, Row, WithWhereState<State>>;
|
|
521
540
|
where(fn: (model: ModelAccessor<TContract, ModelName>) => WhereArg): Collection<TContract, ModelName, Row, WithWhereState<State>>;
|
|
522
541
|
where(filters: ShorthandWhereFilter<TContract, ModelName>): Collection<TContract, ModelName, Row, WithWhereState<State>>;
|
|
542
|
+
/**
|
|
543
|
+
* Narrow a polymorphic model to a specific variant. The returned
|
|
544
|
+
* collection has the variant's row shape and a discriminator filter
|
|
545
|
+
* is automatically applied. Chaining `.variant(...)` again replaces
|
|
546
|
+
* the previous variant filter.
|
|
547
|
+
*
|
|
548
|
+
* ```typescript
|
|
549
|
+
* // Read only admin users (STI):
|
|
550
|
+
* const admins = await db.orm.User.variant('Admin').all();
|
|
551
|
+
*
|
|
552
|
+
* // Iterate the rows:
|
|
553
|
+
* for await (const admin of db.orm.User.variant('Admin').all()) {
|
|
554
|
+
* console.log(admin.role);
|
|
555
|
+
* }
|
|
556
|
+
*
|
|
557
|
+
* // Insert under a variant — discriminator is injected automatically:
|
|
558
|
+
* await db.orm.User.variant('Admin').create({ name: 'Ada', role: 'super' });
|
|
559
|
+
* ```
|
|
560
|
+
*/
|
|
523
561
|
variant<V extends VariantNames<TContract, ModelName>>(variantName: V): Collection<TContract, ModelName, VariantModelRow<TContract, ModelName, V>, WithVariantState<WithWhereState<State>, V>>;
|
|
562
|
+
/**
|
|
563
|
+
* Eagerly load a related model. The relation appears on every
|
|
564
|
+
* returned row under its declared name; to-one relations are mapped
|
|
565
|
+
* to a single object (or `null`), to-many relations to an array.
|
|
566
|
+
*
|
|
567
|
+
* An optional refinement callback receives a child collection that
|
|
568
|
+
* can be further constrained, projected, ordered, paginated, or
|
|
569
|
+
* reduced to scalars via `count()`/`sum()`/etc. or to multiple
|
|
570
|
+
* sub-aggregates via `combine()`.
|
|
571
|
+
*
|
|
572
|
+
* ```typescript
|
|
573
|
+
* // Simple include — every user comes back with its posts array:
|
|
574
|
+
* const users = await db.orm.User.include('posts').all();
|
|
575
|
+
*
|
|
576
|
+
* // Refine the related collection:
|
|
577
|
+
* const withRecent = await db.orm.User.include('posts', (posts) =>
|
|
578
|
+
* posts.where({ published: true }).orderBy((p) => p.createdAt.desc()).take(5),
|
|
579
|
+
* ).all();
|
|
580
|
+
*
|
|
581
|
+
* // Reduce a to-many relation to a scalar value:
|
|
582
|
+
* const withCounts = await db.orm.User.include('posts', (posts) => posts.count()).all();
|
|
583
|
+
*
|
|
584
|
+
* // Multiple sub-views via combine():
|
|
585
|
+
* const overview = await db.orm.User.include('posts', (posts) =>
|
|
586
|
+
* posts.combine({ recent: posts.take(3), total: posts.count() }),
|
|
587
|
+
* ).all();
|
|
588
|
+
* ```
|
|
589
|
+
*/
|
|
524
590
|
include<RelName extends RelationNames<TContract, ModelName>, RelatedName extends RelatedModelName<TContract, ModelName, RelName> & string = RelatedModelName<TContract, ModelName, RelName> & string, IsToMany extends boolean = IsToManyRelation<TContract, ModelName, RelName>, RefinedResult extends IncludeRefinementResult<TContract, RelatedName, IsToMany> = IncludeRefinementCollection<TContract, RelatedName, DefaultModelRow<TContract, RelatedName>, CollectionTypeState, IsToMany>>(relationName: RelName, refineFn?: (collection: IncludeRefinementCollection<TContract, RelatedName, DefaultModelRow<TContract, RelatedName>, DefaultCollectionTypeState, IsToMany>) => RefinedResult): Collection<TContract, ModelName, SimplifyDeep<Row & { [K in RelName]: IncludeRefinementValue<TContract, ModelName, K, DefaultModelRow<TContract, RelatedName>, RefinedResult> }>, State>;
|
|
591
|
+
/**
|
|
592
|
+
* Project the row down to a subset of scalar fields. Previously
|
|
593
|
+
* included relations are preserved on the resulting row shape; only
|
|
594
|
+
* scalar columns are narrowed.
|
|
595
|
+
*
|
|
596
|
+
* ```typescript
|
|
597
|
+
* const summaries = await db.orm.User.select('id', 'email').all();
|
|
598
|
+
* // typeof summaries[number] === { id: ...; email: ... }
|
|
599
|
+
*
|
|
600
|
+
* for await (const row of db.orm.User.select('id', 'email').all()) {
|
|
601
|
+
* console.log(row.id, row.email);
|
|
602
|
+
* }
|
|
603
|
+
* ```
|
|
604
|
+
*/
|
|
525
605
|
select<Fields extends readonly [keyof DefaultModelRow<TContract, ModelName> & string, ...(keyof DefaultModelRow<TContract, ModelName> & string)[]]>(...fields: Fields): Collection<TContract, ModelName, SimplifyDeep<Pick<DefaultModelRow<TContract, ModelName>, Fields[number]> & IncludedRelationsForRow<TContract, ModelName, Row>>, State>;
|
|
606
|
+
/**
|
|
607
|
+
* Append an `ORDER BY` clause. Pass a single selector callback or an
|
|
608
|
+
* array of callbacks; each receives a typed model accessor whose
|
|
609
|
+
* columns expose `.asc()` and `.desc()`. Multiple calls append to the
|
|
610
|
+
* existing list (left-to-right ordering preserved).
|
|
611
|
+
*
|
|
612
|
+
* Calling `orderBy(...)` unlocks `cursor(...)` and `distinctOn(...)`,
|
|
613
|
+
* which both require a defined sort order.
|
|
614
|
+
*
|
|
615
|
+
* ```typescript
|
|
616
|
+
* const newest = await db.orm.User.orderBy((u) => u.createdAt.desc()).all();
|
|
617
|
+
*
|
|
618
|
+
* const byName = await db.orm.User
|
|
619
|
+
* .orderBy([(u) => u.lastName.asc(), (u) => u.firstName.asc()])
|
|
620
|
+
* .all();
|
|
621
|
+
* ```
|
|
622
|
+
*/
|
|
526
623
|
orderBy(selection: ((model: ModelAccessor<TContract, ModelName>) => OrderByItem) | ReadonlyArray<(model: ModelAccessor<TContract, ModelName>) => OrderByItem>): Collection<TContract, ModelName, Row, WithOrderByState<State>>;
|
|
624
|
+
/**
|
|
625
|
+
* Switch to grouped-aggregate mode. Returns a `GroupedCollection`
|
|
626
|
+
* whose `.aggregate(...)` terminal produces one row per group with
|
|
627
|
+
* the chosen key columns plus the requested aggregates.
|
|
628
|
+
*
|
|
629
|
+
* ```typescript
|
|
630
|
+
* const stats = await db.orm.Post
|
|
631
|
+
* .where({ published: true })
|
|
632
|
+
* .groupBy('userId')
|
|
633
|
+
* .aggregate((agg) => ({ count: agg.count(), totalViews: agg.sum('views') }));
|
|
634
|
+
* // [{ userId: 1, count: 3, totalViews: 120 }, ...]
|
|
635
|
+
* ```
|
|
636
|
+
*/
|
|
527
637
|
groupBy<Fields extends readonly [keyof DefaultModelRow<TContract, ModelName> & string, ...(keyof DefaultModelRow<TContract, ModelName> & string)[]]>(...fields: Fields): GroupedCollection<TContract, ModelName, Fields>;
|
|
638
|
+
/**
|
|
639
|
+
* Scalar reducer — reduces a to-many relation to the number of
|
|
640
|
+
* related rows. Use inside an `include(...)` refinement callback as
|
|
641
|
+
* `include(..., (rel) => rel.count())`; throws if called elsewhere.
|
|
642
|
+
* The parent row's relation field becomes that count instead of an
|
|
643
|
+
* array.
|
|
644
|
+
*
|
|
645
|
+
* ```typescript
|
|
646
|
+
* const users = await db.orm.User.include('posts', (posts) => posts.count()).all();
|
|
647
|
+
* // each user row: { ...user, posts: number }
|
|
648
|
+
* ```
|
|
649
|
+
*/
|
|
528
650
|
count(): IncludeScalar<number>;
|
|
651
|
+
/**
|
|
652
|
+
* Scalar reducer — reduces a to-many relation to the sum of `field`
|
|
653
|
+
* across related rows. Returns `null` when there are no related
|
|
654
|
+
* rows. Use inside an `include(...)` refinement callback; throws if
|
|
655
|
+
* called elsewhere.
|
|
656
|
+
*
|
|
657
|
+
* ```typescript
|
|
658
|
+
* const users = await db.orm.User.include('posts', (posts) => posts.sum('views')).all();
|
|
659
|
+
* // each user row: { ...user, posts: number | null }
|
|
660
|
+
* ```
|
|
661
|
+
*/
|
|
529
662
|
sum<FieldName extends NumericFieldNames<TContract, ModelName>>(field: FieldName): IncludeScalar<number | null>;
|
|
663
|
+
/**
|
|
664
|
+
* Scalar reducer — reduces a to-many relation to the average of
|
|
665
|
+
* `field` across related rows. Returns `null` when there are no
|
|
666
|
+
* related rows. Use inside an `include(...)` refinement callback;
|
|
667
|
+
* throws if called elsewhere.
|
|
668
|
+
*
|
|
669
|
+
* ```typescript
|
|
670
|
+
* const users = await db.orm.User.include('posts', (posts) => posts.avg('views')).all();
|
|
671
|
+
* // each user row: { ...user, posts: number | null }
|
|
672
|
+
* ```
|
|
673
|
+
*/
|
|
530
674
|
avg<FieldName extends NumericFieldNames<TContract, ModelName>>(field: FieldName): IncludeScalar<number | null>;
|
|
675
|
+
/**
|
|
676
|
+
* Scalar reducer — reduces a to-many relation to the minimum value
|
|
677
|
+
* of `field` across related rows. Returns `null` when there are no
|
|
678
|
+
* related rows. Use inside an `include(...)` refinement callback;
|
|
679
|
+
* throws if called elsewhere.
|
|
680
|
+
*
|
|
681
|
+
* ```typescript
|
|
682
|
+
* const users = await db.orm.User.include('posts', (posts) => posts.min('views')).all();
|
|
683
|
+
* ```
|
|
684
|
+
*/
|
|
531
685
|
min<FieldName extends NumericFieldNames<TContract, ModelName>>(field: FieldName): IncludeScalar<number | null>;
|
|
686
|
+
/**
|
|
687
|
+
* Scalar reducer — reduces a to-many relation to the maximum value
|
|
688
|
+
* of `field` across related rows. Returns `null` when there are no
|
|
689
|
+
* related rows. Use inside an `include(...)` refinement callback;
|
|
690
|
+
* throws if called elsewhere.
|
|
691
|
+
*
|
|
692
|
+
* ```typescript
|
|
693
|
+
* const users = await db.orm.User.include('posts', (posts) => posts.max('views')).all();
|
|
694
|
+
* ```
|
|
695
|
+
*/
|
|
532
696
|
max<FieldName extends NumericFieldNames<TContract, ModelName>>(field: FieldName): IncludeScalar<number | null>;
|
|
697
|
+
/**
|
|
698
|
+
* Produce multiple named sub-views of a to-many relation in a
|
|
699
|
+
* single `include(...)`. Each branch is either another refined
|
|
700
|
+
* collection (mapped to a row array on the parent) or a scalar
|
|
701
|
+
* reducer such as `count()`/`sum(...)`. Only valid inside an
|
|
702
|
+
* `include(...)` refinement callback for to-many relations.
|
|
703
|
+
*
|
|
704
|
+
* ```typescript
|
|
705
|
+
* const users = await db.orm.User.include('posts', (posts) =>
|
|
706
|
+
* posts.combine({
|
|
707
|
+
* recent: posts.where({ published: true }).take(3),
|
|
708
|
+
* total: posts.count(),
|
|
709
|
+
* averageViews: posts.avg('views'),
|
|
710
|
+
* }),
|
|
711
|
+
* ).all();
|
|
712
|
+
* // each user row: {
|
|
713
|
+
* // ...user,
|
|
714
|
+
* // posts: { recent: Post[]; total: number; averageViews: number | null };
|
|
715
|
+
* // }
|
|
716
|
+
* ```
|
|
717
|
+
*/
|
|
533
718
|
combine<Spec extends Record<string, Collection<TContract, ModelName, unknown, CollectionTypeState> | IncludeScalar<unknown>>>(spec: Spec): IncludeCombine<{ [K in keyof Spec]: Spec[K] extends IncludeScalar<infer ScalarResult> ? ScalarResult : Spec[K] extends Collection<TContract, ModelName, infer BranchRow, CollectionTypeState> ? BranchRow[] : never }>;
|
|
719
|
+
/**
|
|
720
|
+
* Resume pagination from a known cursor position. Requires a prior
|
|
721
|
+
* `orderBy(...)` so the cursor has a stable basis; provide a value
|
|
722
|
+
* for every column referenced by the active `orderBy(...)` so each
|
|
723
|
+
* ordered axis has a defined boundary.
|
|
724
|
+
*
|
|
725
|
+
* ```typescript
|
|
726
|
+
* const page1 = await db.orm.Post
|
|
727
|
+
* .orderBy((p) => p.createdAt.desc())
|
|
728
|
+
* .take(20)
|
|
729
|
+
* .all();
|
|
730
|
+
*
|
|
731
|
+
* const last = page1[page1.length - 1]!;
|
|
732
|
+
* const page2 = await db.orm.Post
|
|
733
|
+
* .orderBy((p) => p.createdAt.desc())
|
|
734
|
+
* .cursor({ createdAt: last.createdAt })
|
|
735
|
+
* .take(20)
|
|
736
|
+
* .all();
|
|
737
|
+
* ```
|
|
738
|
+
*/
|
|
534
739
|
cursor(cursorValues: State['hasOrderBy'] extends true ? Partial<Record<keyof DefaultModelRow<TContract, ModelName> & string, unknown>> : never): Collection<TContract, ModelName, Row, State>;
|
|
740
|
+
/**
|
|
741
|
+
* Emit `SELECT DISTINCT` keyed on the given fields. Replaces any
|
|
742
|
+
* previous `distinct(...)` / `distinctOn(...)` selection.
|
|
743
|
+
*
|
|
744
|
+
* ```typescript
|
|
745
|
+
* const groups = await db.orm.User.distinct('country', 'role').all();
|
|
746
|
+
* ```
|
|
747
|
+
*/
|
|
535
748
|
distinct<Fields extends readonly [keyof DefaultModelRow<TContract, ModelName> & string, ...(keyof DefaultModelRow<TContract, ModelName> & string)[]]>(...fields: Fields): Collection<TContract, ModelName, Row, State>;
|
|
749
|
+
/**
|
|
750
|
+
* Emit `SELECT DISTINCT ON (fields)` — keep the first row per
|
|
751
|
+
* distinct key according to the current `orderBy(...)`. Requires a
|
|
752
|
+
* prior `orderBy(...)`; replaces any previous `distinct(...)` /
|
|
753
|
+
* `distinctOn(...)` selection.
|
|
754
|
+
*
|
|
755
|
+
* ```typescript
|
|
756
|
+
* // Latest post per user:
|
|
757
|
+
* const latestPerUser = await db.orm.Post
|
|
758
|
+
* .orderBy([(p) => p.userId.asc(), (p) => p.createdAt.desc()])
|
|
759
|
+
* .distinctOn('userId')
|
|
760
|
+
* .all();
|
|
761
|
+
* ```
|
|
762
|
+
*/
|
|
536
763
|
distinctOn<Fields extends readonly [keyof DefaultModelRow<TContract, ModelName> & string, ...(keyof DefaultModelRow<TContract, ModelName> & string)[]]>(...fields: State['hasOrderBy'] extends true ? Fields : never): Collection<TContract, ModelName, Row, State>;
|
|
764
|
+
/**
|
|
765
|
+
* Apply `LIMIT n`. Replaces any previous limit set on this collection.
|
|
766
|
+
*
|
|
767
|
+
* ```typescript
|
|
768
|
+
* const firstTen = await db.orm.User.orderBy((u) => u.id.asc()).take(10).all();
|
|
769
|
+
* ```
|
|
770
|
+
*/
|
|
537
771
|
take(n: number): Collection<TContract, ModelName, Row, State>;
|
|
772
|
+
/**
|
|
773
|
+
* Apply `OFFSET n`. Replaces any previous offset set on this collection.
|
|
774
|
+
*
|
|
775
|
+
* ```typescript
|
|
776
|
+
* const page2 = await db.orm.User
|
|
777
|
+
* .orderBy((u) => u.id.asc())
|
|
778
|
+
* .skip(10)
|
|
779
|
+
* .take(10)
|
|
780
|
+
* .all();
|
|
781
|
+
* ```
|
|
782
|
+
*/
|
|
538
783
|
skip(n: number): Collection<TContract, ModelName, Row, State>;
|
|
539
784
|
/**
|
|
540
|
-
* Read terminal:
|
|
785
|
+
* Read terminal: execute the query and stream every matching row.
|
|
786
|
+
*
|
|
787
|
+
* The returned `AsyncIterableResult<Row>` is BOTH a thenable that
|
|
788
|
+
* resolves to `Row[]` (so `await` collects all rows into an array)
|
|
789
|
+
* AND an async iterable (so `for await` streams rows as they
|
|
790
|
+
* arrive, without buffering the whole result set in memory). Pick
|
|
791
|
+
* whichever fits the caller. A single result can only be consumed
|
|
792
|
+
* once.
|
|
793
|
+
*
|
|
794
|
+
* Streaming is the default and the expected execution model. The
|
|
795
|
+
* only scenarios that fall back to buffering internally before
|
|
796
|
+
* yielding are drivers that cannot expose a cursor to the
|
|
797
|
+
* underlying database, and — for queries with `include(...)` —
|
|
798
|
+
* targets whose SQL dialect supports neither lateral joins nor
|
|
799
|
+
* correlated subqueries (so child rows cannot be stitched in a
|
|
800
|
+
* single streaming query). These are implementation details below
|
|
801
|
+
* the public API; the iteration shape itself is genuinely
|
|
802
|
+
* streaming whenever the driver and plan allow it.
|
|
803
|
+
*
|
|
804
|
+
* ```typescript
|
|
805
|
+
* // Thenable — collect to an array:
|
|
806
|
+
* const users = await db.orm.User.all();
|
|
807
|
+
* for (const user of users) console.log(user.id);
|
|
808
|
+
*
|
|
809
|
+
* // Async iterable — stream rows as they arrive:
|
|
810
|
+
* for await (const user of db.orm.User.all()) {
|
|
811
|
+
* console.log(user.id);
|
|
812
|
+
* }
|
|
813
|
+
* ```
|
|
541
814
|
*
|
|
542
815
|
* Accepts an optional `configure` callback that receives a
|
|
543
816
|
* `MetaBuilder<'read'>` so the caller can attach typed user
|
|
544
817
|
* annotations to the executed plan. `meta.annotate(...)` enforces
|
|
545
818
|
* applicability at the type level and at runtime; annotations are
|
|
546
819
|
* merged into `plan.meta.annotations` at compile time.
|
|
820
|
+
*
|
|
821
|
+
* ```typescript
|
|
822
|
+
* await db.orm.User.all((meta) => meta.annotate(cacheAnnotation({ ttl: 60 })));
|
|
823
|
+
* ```
|
|
547
824
|
*/
|
|
548
825
|
all(configure?: (meta: MetaBuilder<'read'>) => void): AsyncIterableResult<Row>;
|
|
826
|
+
/**
|
|
827
|
+
* Read terminal: return the first matching row, or `null` if none
|
|
828
|
+
* match. Optionally accepts a filter (callback or shorthand object)
|
|
829
|
+
* followed by a `configure` callback for typed read annotations.
|
|
830
|
+
*
|
|
831
|
+
* To attach annotations without further narrowing, pass `undefined`
|
|
832
|
+
* as the filter (or chain `.where(...)` first):
|
|
833
|
+
*
|
|
834
|
+
* ```typescript
|
|
835
|
+
* // No filter — first row in the collection:
|
|
836
|
+
* const someone = await db.orm.User.first();
|
|
837
|
+
*
|
|
838
|
+
* // Shorthand filter:
|
|
839
|
+
* const alice = await db.orm.User.first({ email: 'alice@example.com' });
|
|
840
|
+
*
|
|
841
|
+
* // Callback filter:
|
|
842
|
+
* const old = await db.orm.User.first((u) => u.age.gt(60));
|
|
843
|
+
*
|
|
844
|
+
* // Annotate without filtering further:
|
|
845
|
+
* await db.orm.User.first(undefined, (meta) =>
|
|
846
|
+
* meta.annotate(cacheAnnotation({ ttl: 60 })),
|
|
847
|
+
* );
|
|
848
|
+
* ```
|
|
849
|
+
*/
|
|
549
850
|
first(): Promise<Row | null>;
|
|
550
851
|
first(filter: undefined, configure: (meta: MetaBuilder<'read'>) => void): Promise<Row | null>;
|
|
551
852
|
first(filter: (model: ModelAccessor<TContract, ModelName>) => WhereArg, configure?: (meta: MetaBuilder<'read'>) => void): Promise<Row | null>;
|
|
552
853
|
first(filter: ShorthandWhereFilter<TContract, ModelName>, configure?: (meta: MetaBuilder<'read'>) => void): Promise<Row | null>;
|
|
553
854
|
/**
|
|
554
855
|
* Read terminal: run an aggregate query (count, sum, avg, min, max)
|
|
555
|
-
* built via the `AggregateBuilder` callback.
|
|
856
|
+
* built via the `AggregateBuilder` callback. Returns one object
|
|
857
|
+
* with the requested aggregate values keyed by the aliases supplied
|
|
858
|
+
* in the spec.
|
|
859
|
+
*
|
|
860
|
+
* ```typescript
|
|
861
|
+
* const stats = await db.orm.Post
|
|
862
|
+
* .where({ published: true })
|
|
863
|
+
* .aggregate((agg) => ({
|
|
864
|
+
* total: agg.count(),
|
|
865
|
+
* averageViews: agg.avg('views'),
|
|
866
|
+
* maxViews: agg.max('views'),
|
|
867
|
+
* }));
|
|
868
|
+
* // { total: 42, averageViews: 17.3, maxViews: 9001 }
|
|
869
|
+
* ```
|
|
556
870
|
*
|
|
557
871
|
* Accepts an optional `configure` callback that receives a
|
|
558
872
|
* `MetaBuilder<'read'>` for attaching typed annotations.
|
|
559
873
|
* Annotations are merged into the compiled plan's `meta.annotations`.
|
|
560
874
|
*/
|
|
561
875
|
aggregate<Spec extends AggregateSpec>(fn: (aggregate: AggregateBuilder<TContract, ModelName>) => Spec, configure?: (meta: MetaBuilder<'read'>) => void): Promise<AggregateResult<Spec>>;
|
|
876
|
+
/**
|
|
877
|
+
* Write terminal: insert one row and return it (with any configured
|
|
878
|
+
* `select(...)` / `include(...)` projections applied to the returned
|
|
879
|
+
* shape).
|
|
880
|
+
*
|
|
881
|
+
* Related rows can be created or linked through relation callbacks
|
|
882
|
+
* on parent/child-owned relations (one-to-one or one-to-many).
|
|
883
|
+
* The callback receives a mutator exposing `create(...)` and
|
|
884
|
+
* `connect(...)`; `disconnect(...)` is only supported in nested
|
|
885
|
+
* `update(...)` mutations. Many-to-many relations are not yet
|
|
886
|
+
* supported as nested-mutation targets.
|
|
887
|
+
*
|
|
888
|
+
* ```typescript
|
|
889
|
+
* // Simple insert:
|
|
890
|
+
* const user = await db.orm.User.create({
|
|
891
|
+
* email: 'alice@example.com',
|
|
892
|
+
* name: 'Alice',
|
|
893
|
+
* });
|
|
894
|
+
*
|
|
895
|
+
* // Nested create on a child-owned to-many relation:
|
|
896
|
+
* const author = await db.orm.User.create({
|
|
897
|
+
* email: 'bob@example.com',
|
|
898
|
+
* posts: (posts) => posts.create([
|
|
899
|
+
* { title: 'Hello' },
|
|
900
|
+
* { title: 'World' },
|
|
901
|
+
* ]),
|
|
902
|
+
* });
|
|
903
|
+
*
|
|
904
|
+
* // Connect a child-owned post to an existing parent author:
|
|
905
|
+
* const reply = await db.orm.Post.create({
|
|
906
|
+
* title: 'Re: Hello',
|
|
907
|
+
* author: (author) => author.connect({ id: 1 }),
|
|
908
|
+
* });
|
|
909
|
+
* ```
|
|
910
|
+
*
|
|
911
|
+
* Accepts an optional `configure` callback that receives a
|
|
912
|
+
* `MetaBuilder<'write'>` for attaching typed annotations.
|
|
913
|
+
* Annotations are merged into the compiled mutation plan's
|
|
914
|
+
* `meta.annotations`.
|
|
915
|
+
*
|
|
916
|
+
* Note: when the input contains nested-mutation callbacks, the
|
|
917
|
+
* operation is executed as a graph of internal queries via
|
|
918
|
+
* `withMutationScope`. In that path, annotations apply to the
|
|
919
|
+
* logical `create()` call but do not currently flow into each
|
|
920
|
+
* constituent SQL statement issued for the related rows.
|
|
921
|
+
*/
|
|
562
922
|
create(data: ResolvedCreateInput<TContract, ModelName, State['variantName']>, configure?: (meta: MetaBuilder<'write'>) => void): Promise<Row>;
|
|
563
923
|
create(data: MutationCreateInputWithRelations<TContract, ModelName>, configure?: (meta: MetaBuilder<'write'>) => void): Promise<Row>;
|
|
924
|
+
/**
|
|
925
|
+
* Write terminal: insert many rows and stream the inserted rows.
|
|
926
|
+
*
|
|
927
|
+
* The returned `AsyncIterableResult<Row>` is BOTH a thenable that
|
|
928
|
+
* resolves to `Row[]` AND an async iterable that streams inserted
|
|
929
|
+
* rows as they arrive. Use whichever shape fits the caller — but
|
|
930
|
+
* only consume it once. Streaming is the default; some
|
|
931
|
+
* driver/plan combinations may still buffer internally before
|
|
932
|
+
* yielding.
|
|
933
|
+
*
|
|
934
|
+
* ```typescript
|
|
935
|
+
* // Thenable — collect all inserted rows into an array:
|
|
936
|
+
* const created = await db.orm.User.createAll([
|
|
937
|
+
* { email: 'a@example.com' },
|
|
938
|
+
* { email: 'b@example.com' },
|
|
939
|
+
* ]);
|
|
940
|
+
*
|
|
941
|
+
* // Async iterable — stream inserted rows as they arrive:
|
|
942
|
+
* for await (const row of db.orm.User.createAll(seedUsers)) {
|
|
943
|
+
* console.log('inserted', row.id);
|
|
944
|
+
* }
|
|
945
|
+
* ```
|
|
946
|
+
*
|
|
947
|
+
* Accepts an optional `configure` callback that receives a
|
|
948
|
+
* `MetaBuilder<'write'>` for attaching typed annotations to the
|
|
949
|
+
* compiled insert plan.
|
|
950
|
+
*/
|
|
564
951
|
createAll(data: readonly ResolvedCreateInput<TContract, ModelName, State['variantName']>[], configure?: (meta: MetaBuilder<'write'>) => void): AsyncIterableResult<Row>;
|
|
952
|
+
/**
|
|
953
|
+
* Write terminal: insert many rows without materializing the
|
|
954
|
+
* inserted rows, returning the number of inserted records.
|
|
955
|
+
*
|
|
956
|
+
* Prefer `createAll(...)` when you need the returned rows; prefer
|
|
957
|
+
* this when you only need to know how many rows were inserted (the
|
|
958
|
+
* compiled plan skips `RETURNING`).
|
|
959
|
+
*
|
|
960
|
+
* ```typescript
|
|
961
|
+
* const inserted = await db.orm.User.createCount([
|
|
962
|
+
* { email: 'a@example.com' },
|
|
963
|
+
* { email: 'b@example.com' },
|
|
964
|
+
* ]);
|
|
965
|
+
* // inserted === 2
|
|
966
|
+
* ```
|
|
967
|
+
*
|
|
968
|
+
* Not supported on MTI variants — use `createAll(...)` instead.
|
|
969
|
+
*/
|
|
565
970
|
createCount(data: readonly ResolvedCreateInput<TContract, ModelName, State['variantName']>[], configure?: (meta: MetaBuilder<'write'>) => void): Promise<number>;
|
|
566
971
|
/**
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
972
|
+
* Write terminal: insert a row, or update the existing row on
|
|
973
|
+
* conflict. Returns the resulting row (the inserted one or the
|
|
974
|
+
* updated/existing one).
|
|
975
|
+
*
|
|
976
|
+
* `conflictOn` selects which unique constraint drives the conflict
|
|
977
|
+
* resolution — omit to use the model's primary key.
|
|
978
|
+
*
|
|
979
|
+
* ```typescript
|
|
980
|
+
* // Insert-or-update on email uniqueness:
|
|
981
|
+
* await db.orm.User.upsert({
|
|
982
|
+
* create: { email: 'alice@example.com', name: 'Alice' },
|
|
983
|
+
* update: { name: 'Alice (updated)' },
|
|
984
|
+
* conflictOn: { email: 'alice@example.com' },
|
|
985
|
+
* });
|
|
986
|
+
*
|
|
987
|
+
* // Conditional create — `update: {}` keeps the existing row
|
|
988
|
+
* // unchanged. `conflictOn` must reference the constraint that
|
|
989
|
+
* // makes the row "already exist"; omit only when the conflict is
|
|
990
|
+
* // on the primary key. On conflict,
|
|
991
|
+
* // `ON CONFLICT DO NOTHING RETURNING ...` may return zero rows,
|
|
992
|
+
* // so a follow-up reload is issued to fetch and return the
|
|
993
|
+
* // existing row.
|
|
994
|
+
* await db.orm.User.upsert({
|
|
995
|
+
* create: { email: 'alice@example.com', name: 'Alice' },
|
|
996
|
+
* update: {},
|
|
997
|
+
* conflictOn: { email: 'alice@example.com' },
|
|
998
|
+
* });
|
|
999
|
+
* ```
|
|
1000
|
+
*
|
|
1001
|
+
* Not supported on MTI variants.
|
|
570
1002
|
*/
|
|
571
1003
|
upsert(input: {
|
|
572
1004
|
create: ResolvedCreateInput<TContract, ModelName, State['variantName']>;
|
|
@@ -575,7 +1007,30 @@ declare class Collection<TContract extends Contract<SqlStorage>, ModelName exten
|
|
|
575
1007
|
}, configure?: (meta: MetaBuilder<'write'>) => void): Promise<Row>;
|
|
576
1008
|
/**
|
|
577
1009
|
* Write terminal: update matching rows and return the first one (or
|
|
578
|
-
* null when no row matched).
|
|
1010
|
+
* `null` when no row matched). Requires a prior `.where(...)` —
|
|
1011
|
+
* calling `update(...)` on an unfiltered collection is a type error.
|
|
1012
|
+
*
|
|
1013
|
+
* Related rows can be created or relinked through relation
|
|
1014
|
+
* callbacks on parent/child-owned relations (one-to-one or
|
|
1015
|
+
* one-to-many). The callback receives a mutator exposing
|
|
1016
|
+
* `create(...)`, `connect(...)`, and `disconnect(...)`. Nested
|
|
1017
|
+
* updates against existing related rows, and many-to-many relations
|
|
1018
|
+
* as nested-mutation targets, are not supported through this API.
|
|
1019
|
+
*
|
|
1020
|
+
* ```typescript
|
|
1021
|
+
* // Update one row by id:
|
|
1022
|
+
* const updated = await db.orm.User
|
|
1023
|
+
* .where({ id: 1 })
|
|
1024
|
+
* .update({ name: 'Alice Renamed' });
|
|
1025
|
+
*
|
|
1026
|
+
* // Update + relink — runs as a graph of internal mutations:
|
|
1027
|
+
* await db.orm.User
|
|
1028
|
+
* .where({ id: 1 })
|
|
1029
|
+
* .update({
|
|
1030
|
+
* name: 'Alice',
|
|
1031
|
+
* posts: (posts) => posts.connect([{ id: 5 }]),
|
|
1032
|
+
* });
|
|
1033
|
+
* ```
|
|
579
1034
|
*
|
|
580
1035
|
* Accepts an optional `configure` callback that receives a
|
|
581
1036
|
* `MetaBuilder<'write'>` for attaching typed annotations.
|
|
@@ -587,17 +1042,97 @@ declare class Collection<TContract extends Contract<SqlStorage>, ModelName exten
|
|
|
587
1042
|
* statement issued for the related rows.
|
|
588
1043
|
*/
|
|
589
1044
|
update(data: State['hasWhere'] extends true ? MutationUpdateInput<TContract, ModelName> : never, configure?: (meta: MetaBuilder<'write'>) => void): Promise<Row | null>;
|
|
1045
|
+
/**
|
|
1046
|
+
* Write terminal: update every matching row and stream the updated
|
|
1047
|
+
* rows. Requires a prior `.where(...)` filter.
|
|
1048
|
+
*
|
|
1049
|
+
* The returned `AsyncIterableResult<Row>` is BOTH a thenable that
|
|
1050
|
+
* resolves to `Row[]` AND an async iterable that streams updated
|
|
1051
|
+
* rows as they arrive. Use whichever fits; a result can only be
|
|
1052
|
+
* consumed once. Streaming is the default; some driver/plan
|
|
1053
|
+
* combinations may still buffer internally before yielding.
|
|
1054
|
+
*
|
|
1055
|
+
* ```typescript
|
|
1056
|
+
* // Thenable — collect updated rows into an array:
|
|
1057
|
+
* const updated = await db.orm.Post
|
|
1058
|
+
* .where({ published: false })
|
|
1059
|
+
* .updateAll({ published: true });
|
|
1060
|
+
*
|
|
1061
|
+
* // Async iterable — stream updated rows as they arrive:
|
|
1062
|
+
* for await (const row of db.orm.Post.where({ draft: true }).updateAll({ draft: false })) {
|
|
1063
|
+
* console.log('published', row.id);
|
|
1064
|
+
* }
|
|
1065
|
+
* ```
|
|
1066
|
+
*
|
|
1067
|
+
* Accepts an optional `configure` callback that receives a
|
|
1068
|
+
* `MetaBuilder<'write'>` for attaching typed annotations.
|
|
1069
|
+
*/
|
|
590
1070
|
updateAll(data: State['hasWhere'] extends true ? Partial<DefaultModelRow<TContract, ModelName>> : never, configure?: (meta: MetaBuilder<'write'>) => void): AsyncIterableResult<Row>;
|
|
1071
|
+
/**
|
|
1072
|
+
* Write terminal: update every matching row without returning them,
|
|
1073
|
+
* resolving to the count of rows that were updated. Requires a prior
|
|
1074
|
+
* `.where(...)` filter.
|
|
1075
|
+
*
|
|
1076
|
+
* Prefer `updateAll(...)` when you need the updated rows; prefer
|
|
1077
|
+
* this when you only need the affected-row count.
|
|
1078
|
+
*
|
|
1079
|
+
* ```typescript
|
|
1080
|
+
* const count = await db.orm.Post
|
|
1081
|
+
* .where({ published: false })
|
|
1082
|
+
* .updateCount({ published: true });
|
|
1083
|
+
* ```
|
|
1084
|
+
*/
|
|
591
1085
|
updateCount(data: State['hasWhere'] extends true ? Partial<DefaultModelRow<TContract, ModelName>> : never, configure?: (meta: MetaBuilder<'write'>) => void): Promise<number>;
|
|
592
1086
|
/**
|
|
593
|
-
* Write terminal: delete matching rows and return the first
|
|
594
|
-
* null when no row matched).
|
|
1087
|
+
* Write terminal: delete matching rows and return the first deleted
|
|
1088
|
+
* row (or `null` when no row matched). Requires a prior `.where(...)`
|
|
1089
|
+
* — calling `delete()` on an unfiltered collection is a type error.
|
|
1090
|
+
*
|
|
1091
|
+
* ```typescript
|
|
1092
|
+
* const deleted = await db.orm.User.where({ id: 1 }).delete();
|
|
1093
|
+
* if (deleted) console.log('deleted', deleted.email);
|
|
1094
|
+
* ```
|
|
595
1095
|
*
|
|
596
1096
|
* Accepts an optional `configure` callback that receives a
|
|
597
1097
|
* `MetaBuilder<'write'>` for attaching typed annotations.
|
|
598
1098
|
*/
|
|
599
1099
|
delete(this: State['hasWhere'] extends true ? Collection<TContract, ModelName, Row, State> : never, configure?: (meta: MetaBuilder<'write'>) => void): Promise<Row | null>;
|
|
1100
|
+
/**
|
|
1101
|
+
* Write terminal: delete every matching row and stream the deleted
|
|
1102
|
+
* rows. Requires a prior `.where(...)` filter.
|
|
1103
|
+
*
|
|
1104
|
+
* The returned `AsyncIterableResult<Row>` is BOTH a thenable that
|
|
1105
|
+
* resolves to `Row[]` AND an async iterable that streams deleted
|
|
1106
|
+
* rows as they arrive. Use whichever fits; a result can only be
|
|
1107
|
+
* consumed once. Streaming is the default; some driver/plan
|
|
1108
|
+
* combinations may still buffer internally before yielding.
|
|
1109
|
+
*
|
|
1110
|
+
* ```typescript
|
|
1111
|
+
* // Thenable — collect the deleted rows into an array:
|
|
1112
|
+
* const deleted = await db.orm.Post.where({ archived: true }).deleteAll();
|
|
1113
|
+
*
|
|
1114
|
+
* // Async iterable — stream deleted rows as they arrive:
|
|
1115
|
+
* for await (const row of db.orm.Post.where({ archived: true }).deleteAll()) {
|
|
1116
|
+
* console.log('removed', row.id);
|
|
1117
|
+
* }
|
|
1118
|
+
* ```
|
|
1119
|
+
*
|
|
1120
|
+
* Accepts an optional `configure` callback that receives a
|
|
1121
|
+
* `MetaBuilder<'write'>` for attaching typed annotations.
|
|
1122
|
+
*/
|
|
600
1123
|
deleteAll(this: State['hasWhere'] extends true ? Collection<TContract, ModelName, Row, State> : never, configure?: (meta: MetaBuilder<'write'>) => void): AsyncIterableResult<Row>;
|
|
1124
|
+
/**
|
|
1125
|
+
* Write terminal: delete every matching row without returning them,
|
|
1126
|
+
* resolving to the count of rows that were deleted. Requires a prior
|
|
1127
|
+
* `.where(...)` filter.
|
|
1128
|
+
*
|
|
1129
|
+
* Prefer `deleteAll(...)` when you need the deleted rows; prefer
|
|
1130
|
+
* this when you only need the affected-row count.
|
|
1131
|
+
*
|
|
1132
|
+
* ```typescript
|
|
1133
|
+
* const removed = await db.orm.Post.where({ archived: true }).deleteCount();
|
|
1134
|
+
* ```
|
|
1135
|
+
*/
|
|
601
1136
|
deleteCount(this: State['hasWhere'] extends true ? Collection<TContract, ModelName, Row, State> : never, configure?: (meta: MetaBuilder<'write'>) => void): Promise<number>;
|
|
602
1137
|
}
|
|
603
1138
|
//#endregion
|