@cleverbrush/knex-schema 3.0.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,75 @@
1
1
  import type { InferType } from '@cleverbrush/schema';
2
- import { ObjectSchemaBuilder } from '@cleverbrush/schema';
2
+ import { EXTRA_TYPE_BRAND, METHOD_LITERAL_BRAND, ObjectSchemaBuilder } from '@cleverbrush/schema';
3
3
  import type { Knex } from 'knex';
4
- import type { ColumnRef, InsertType, JoinManySpec, JoinOneSpec, WithJoinedMany, WithJoinedOne } from './types.js';
4
+ import { POLYMORPHIC_TYPE_BRAND } from './extension.js';
5
+ import type { ColumnRef, CursorPaginationResult, InsertType, JoinManySpec, JoinOneSpec, PaginationResult, SelectProjection, SelectSelector, WithJoinedMany, WithJoinedOne } from './types.js';
6
+ /**
7
+ * Extracts the scope names registered on a schema via `.scope(name, fn)`.
8
+ * Returns `never` when no scopes are defined (making `.scoped()` uncallable).
9
+ * Falls back to `string` for `any`-typed schemas to preserve loose behaviour.
10
+ *
11
+ * @internal
12
+ */
13
+ type ScopesOf<S> = S extends {
14
+ readonly [METHOD_LITERAL_BRAND]?: infer N;
15
+ } ? Extract<N, string> : never;
16
+ /**
17
+ * Extracts the named projection map from a schema type.
18
+ * Returns a `Record<name, readonly keys[]>` type where each key is a
19
+ * registered projection name and the value is the tuple of property keys.
20
+ * Returns `Record<never, never>` (no projections) when the schema has none,
21
+ * making `.projected()` uncallable on undecorated schemas.
22
+ *
23
+ * @internal
24
+ */
25
+ type ProjectionsOf<S> = S extends {
26
+ readonly [EXTRA_TYPE_BRAND]?: infer P;
27
+ } ? P extends Record<string, readonly string[]> ? P : Record<never, never> : Record<never, never>;
28
+ /**
29
+ * Extracts the string-key union for a specific projection name from a schema
30
+ * type. This indirection is needed because TypeScript cannot directly index
31
+ * `ProjectionsOf<S>[K]` with `number` inside a generic function signature.
32
+ *
33
+ * @internal
34
+ */
35
+ type ProjectionKeysOf<S, K extends keyof ProjectionsOf<S> & string> = ProjectionsOf<S>[K] extends readonly (infer T extends string)[] ? T : string;
36
+ /**
37
+ * When a schema carries the `POLYMORPHIC_TYPE_BRAND` phantom type (set by
38
+ * `.withVariants()`), extract the discriminated-union result type from it.
39
+ * Otherwise fall back to `InferType<TLocalSchema>`.
40
+ *
41
+ * @internal
42
+ */
43
+ type QueryResultType<TLocalSchema> = TLocalSchema extends {
44
+ readonly [POLYMORPHIC_TYPE_BRAND]?: infer U;
45
+ } ? NonNullable<U> : InferType<TLocalSchema>;
46
+ /**
47
+ * Intermediate builder returned by {@link SchemaQueryBuilder.onConflict}.
48
+ * Call `.merge()` or `.ignore()` to complete the upsert/insert-ignore operation.
49
+ *
50
+ * @internal
51
+ */
52
+ export declare class OnConflictBuilder<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TResult> {
53
+ #private;
54
+ /** @internal */
55
+ constructor(knex: Knex, localSchema: TLocalSchema, _parent: SchemaQueryBuilder<TLocalSchema, TResult>, conflictColumns: string[]);
56
+ /**
57
+ * Insert and merge (update) conflicting rows.
58
+ *
59
+ * @param data - Row to insert.
60
+ * @param updateData - Optional partial object of columns to update on
61
+ * conflict. If omitted, all inserted columns are updated.
62
+ * @returns The resulting row.
63
+ */
64
+ merge(data: InsertType<TLocalSchema>, updateData?: Partial<InferType<TLocalSchema>>): Promise<TResult>;
65
+ /**
66
+ * Insert and silently ignore conflicts.
67
+ *
68
+ * @param data - Row to insert.
69
+ * @returns The row if inserted, or `undefined` if the conflict was ignored.
70
+ */
71
+ ignore(data: InsertType<TLocalSchema>): Promise<TResult | undefined>;
72
+ }
5
73
  /**
6
74
  * Type-safe, schema-driven query builder for Knex.
7
75
  *
@@ -277,6 +345,36 @@ export declare class SchemaQueryBuilder<TLocalSchema extends ObjectSchemaBuilder
277
345
  * @returns `this` for chaining.
278
346
  */
279
347
  whereExists(callback: Knex.QueryCallback | Knex.QueryBuilder): this;
348
+ /**
349
+ * Add a `WHERE NOT EXISTS (subquery)` clause.
350
+ * @param callback - A Knex query callback or sub-query builder.
351
+ * @returns `this` for chaining.
352
+ */
353
+ whereNotExists(callback: Knex.QueryCallback | Knex.QueryBuilder): this;
354
+ /**
355
+ * Add a PostgreSQL JSON path filter using `@?` / `@@` operators or
356
+ * a path-based equality test via `jsonb_path_query_first`.
357
+ *
358
+ * Only supported on `pg` clients — throws at runtime on others.
359
+ *
360
+ * @param column - Column reference for the `jsonb` column.
361
+ * @param path - Dot-separated property path (e.g. `'a.b.c'`) or a
362
+ * JSONPath expression string (e.g. `'$.a.b ? (@ == 1)'`).
363
+ * @param operator - Comparison operator (`=`, `!=`, `<`, `<=`, `>`, `>=`,
364
+ * `@?`, `@@`). Use `@?` / `@@` for JSONPath existence / predicate tests.
365
+ * @param value - The right-hand side value. Ignored for `@?` and `@@`.
366
+ * @returns `this` for chaining.
367
+ *
368
+ * @example
369
+ * ```ts
370
+ * // Filter rows where data->>'status' = 'active'
371
+ * query(db, Schema).whereJsonPath(t => t.data, 'status', '=', 'active');
372
+ *
373
+ * // JSONPath existence
374
+ * query(db, Schema).whereJsonPath(t => t.data, '$.tags[*] ? (@ == "sale")', '@?');
375
+ * ```
376
+ */
377
+ whereJsonPath(column: ColumnRef<TLocalSchema>, path: string, operator?: string, value?: any): this;
280
378
  /**
281
379
  * Order the results by a column.
282
380
  * @param column - Column reference or raw expression.
@@ -335,6 +433,22 @@ export declare class SchemaQueryBuilder<TLocalSchema extends ObjectSchemaBuilder
335
433
  * @returns `this` for chaining.
336
434
  */
337
435
  select(...columns: (ColumnRef<TLocalSchema> | Knex.Raw)[]): this;
436
+ /**
437
+ * DTO projection: select multiple aliased columns at once via a
438
+ * descriptor record. Returns a query whose result rows match the
439
+ * shape of the selector's return value (each value typed as the
440
+ * inferred schema-property type).
441
+ *
442
+ * @example
443
+ * ```ts
444
+ * const dtos = await query(db, UserSchema)
445
+ * .where(t => t.id, '>', 0)
446
+ * .select(t => ({ id: t.id, n: t.name }))
447
+ * .execute();
448
+ * // dtos: { id: number; n: string }[]
449
+ * ```
450
+ */
451
+ select<TSel extends SelectSelector<TLocalSchema>>(selector: TSel): SchemaQueryBuilder<TLocalSchema, SelectProjection<ReturnType<TSel>>>;
338
452
  /**
339
453
  * Add `DISTINCT` to the select clause. Duplicate rows are eliminated.
340
454
  * @param columns - One or more column references or raw expressions.
@@ -398,6 +512,53 @@ export declare class SchemaQueryBuilder<TLocalSchema extends ObjectSchemaBuilder
398
512
  * @returns The full inserted rows in insertion order.
399
513
  */
400
514
  insertMany(data: InsertType<TLocalSchema>[]): Promise<TResult[]>;
515
+ /**
516
+ * Insert a row (or rows) with an `ON CONFLICT` clause.
517
+ *
518
+ * Returns a chainable object with `.merge()` and `.ignore()` methods.
519
+ *
520
+ * - `.merge(updateData?)` — updates the conflicting row with the provided
521
+ * fields (or all insert fields if omitted).
522
+ * - `.ignore()` — skips the insert when a conflict occurs (INSERT IGNORE).
523
+ *
524
+ * @param conflictColumns - Column references that define the conflict target.
525
+ * @returns A chainable conflict builder.
526
+ *
527
+ * @example
528
+ * ```ts
529
+ * // Upsert: insert or update on conflict
530
+ * await query(db, UserSchema)
531
+ * .onConflict(t => t.email)
532
+ * .merge({ name: 'Bob' });
533
+ *
534
+ * // Insert and ignore on conflict
535
+ * await query(db, UserSchema)
536
+ * .onConflict(t => t.email)
537
+ * .ignore();
538
+ * ```
539
+ */
540
+ onConflict(...conflictColumns: ColumnRef<TLocalSchema>[]): OnConflictBuilder<TLocalSchema, TResult>;
541
+ /**
542
+ * Insert or update a row based on a conflict target (upsert shorthand).
543
+ *
544
+ * Equivalent to calling `.onConflict(conflictColumns).merge(updateData)`.
545
+ *
546
+ * @param data - The row data to insert.
547
+ * @param opts - `{ conflictColumns, updateColumns? }`.
548
+ * @returns The resulting row (inserted or updated).
549
+ *
550
+ * @example
551
+ * ```ts
552
+ * const user = await query(db, UserSchema).upsert(
553
+ * { email: 'alice@example.com', name: 'Alice' },
554
+ * { conflictColumns: [t => t.email], updateColumns: [t => t.name] }
555
+ * );
556
+ * ```
557
+ */
558
+ upsert(data: InsertType<TLocalSchema>, opts: {
559
+ conflictColumns: ColumnRef<TLocalSchema>[];
560
+ updateColumns?: ColumnRef<TLocalSchema>[];
561
+ }): Promise<TResult>;
401
562
  /**
402
563
  * Update all rows that match the current `WHERE` clause and return the
403
564
  * updated records.
@@ -418,7 +579,12 @@ export declare class SchemaQueryBuilder<TLocalSchema extends ObjectSchemaBuilder
418
579
  update(data: Partial<InferType<TLocalSchema>>): Promise<TResult[]>;
419
580
  /**
420
581
  * Delete all rows that match the current `WHERE` clause.
421
- * @returns The number of rows deleted.
582
+ *
583
+ * If the schema has soft-delete enabled via `.softDelete()`, this performs
584
+ * an `UPDATE SET deleted_at = NOW()` instead of a real `DELETE`.
585
+ * Use {@link hardDelete} for permanent deletion.
586
+ *
587
+ * @returns The number of rows deleted (or soft-deleted).
422
588
  *
423
589
  * @example
424
590
  * ```ts
@@ -426,6 +592,53 @@ export declare class SchemaQueryBuilder<TLocalSchema extends ObjectSchemaBuilder
426
592
  * ```
427
593
  */
428
594
  delete(): Promise<number>;
595
+ /**
596
+ * Bulk-insert many rows in chunks. The default chunk size of `500` keeps
597
+ * comfortably below Postgres' parameter-count limit of 65535. The chunk
598
+ * size also auto-shrinks when the number of bindings per row would
599
+ * exceed that ceiling.
600
+ *
601
+ * When `opts.onConflict` is supplied each chunk is wrapped in an
602
+ * `INSERT ... ON CONFLICT` clause:
603
+ *
604
+ * - `'ignore'` — `ON CONFLICT (...) DO NOTHING`
605
+ * - `'merge'` — `ON CONFLICT (...) DO UPDATE SET ...` (uses `conflictColumns` as
606
+ * the conflict target and updates every inserted column).
607
+ *
608
+ * `beforeInsert` / `afterInsert` hooks fire per row, identically to
609
+ * {@link insertMany}.
610
+ *
611
+ * @returns The inserted rows (excluding rows skipped by `'ignore'`).
612
+ */
613
+ bulkInsert(rows: InsertType<TLocalSchema>[], opts?: {
614
+ chunkSize?: number;
615
+ onConflict?: 'ignore' | 'merge';
616
+ conflictColumns?: ColumnRef<TLocalSchema>[];
617
+ }): Promise<TResult[]>;
618
+ /**
619
+ * Bulk-upsert many rows in chunks. Equivalent to
620
+ * `.bulkInsert(rows, { onConflict: 'merge', conflictColumns })`.
621
+ */
622
+ bulkUpsert(rows: InsertType<TLocalSchema>[], opts: {
623
+ conflictColumns: ColumnRef<TLocalSchema>[];
624
+ chunkSize?: number;
625
+ }): Promise<TResult[]>;
626
+ /**
627
+ * Bulk-update many rows in a single SQL statement using a CASE
628
+ * expression keyed on the entity's primary key.
629
+ *
630
+ * Each entry's `where` clause must fully match the entity's primary key
631
+ * columns (single or composite). Updates that touch different columns
632
+ * are coalesced into one statement; rows whose PK appears in `updates`
633
+ * but whose `set` does not contain a given column retain their existing
634
+ * value.
635
+ *
636
+ * @returns The number of rows affected.
637
+ */
638
+ bulkUpdate(updates: ReadonlyArray<{
639
+ where: Partial<InferType<TLocalSchema>>;
640
+ set: Partial<InferType<TLocalSchema>>;
641
+ }>): Promise<number>;
429
642
  /**
430
643
  * Escape hatch: apply any Knex method to the underlying base query.
431
644
  *
@@ -472,6 +685,228 @@ export declare class SchemaQueryBuilder<TLocalSchema extends ObjectSchemaBuilder
472
685
  * ```
473
686
  */
474
687
  transacting(trx: Knex.Transaction): SchemaQueryBuilder<TLocalSchema, TResult>;
688
+ /**
689
+ * Eager-load a named relation defined via `.hasMany()`, `.belongsTo()`,
690
+ * `.hasOne()`, or `.belongsToMany()` on the schema.
691
+ *
692
+ * @param relationName - The relation name passed to the schema's relation method.
693
+ * @param customize - Optional callback to customise the foreign query
694
+ * (e.g. add ordering, limits).
695
+ * @returns `this` for chaining.
696
+ *
697
+ * @example
698
+ * ```ts
699
+ * const posts = await query(db, PostWithRelations)
700
+ * .include('author')
701
+ * .include('tags');
702
+ * ```
703
+ */
704
+ include(relationName: string, customize?: (q: SchemaQueryBuilder<any, any>) => void): this;
705
+ /**
706
+ * Eager-load a named relation declared inside a `withVariants` variant spec.
707
+ *
708
+ * The relation is loaded via a LEFT JOIN on the variant's alias table and
709
+ * only populated on rows whose discriminator matches `variantKey`.
710
+ *
711
+ * @param variantKey - The variant key (e.g. `'assigned'`).
712
+ * @param relationName - The relation name declared in `variants[key].relations`.
713
+ * @param customize - Optional callback to restrict which columns are
714
+ * selected from the foreign table (scope / projection).
715
+ *
716
+ * @example
717
+ * ```ts
718
+ * await query(db, TodoActivity)
719
+ * .includeVariant('assigned', 'assignee', q => q.projected('summary'));
720
+ * ```
721
+ */
722
+ includeVariant(variantKey: string, relationName: string, customize?: (q: SchemaQueryBuilder<any, any>) => void): this;
723
+ /**
724
+ * Apply a named scope defined on the schema via `.scope(name, fn)`.
725
+ *
726
+ * The `name` parameter is constrained to the literal scope names registered
727
+ * on the schema, so IDEs show only valid completions and typos are caught
728
+ * at compile time.
729
+ *
730
+ * @param name - The scope name.
731
+ * @returns `this` for chaining.
732
+ *
733
+ * @example
734
+ * ```ts
735
+ * await query(db, Post).scoped('published').scoped('recent');
736
+ * ```
737
+ */
738
+ /**
739
+ * Apply a **named projection** defined on the schema via
740
+ * `.projection(name, columns)`.
741
+ *
742
+ * Calling `.projected()` on the query builder does two things:
743
+ * 1. Restricts the SQL `SELECT` clause to the columns registered under
744
+ * `name` (SQL column names are resolved via `.hasColumnName()`).
745
+ * 2. Narrows the TypeScript result row type to `Pick<Row, Keys>` so
746
+ * accessing columns outside the projection is a compile-time error.
747
+ *
748
+ * The `name` parameter is constrained to the literal projection names
749
+ * registered on the schema — TypeScript will report an error for any
750
+ * unregistered name.
751
+ *
752
+ * Calling `.projected()` after `.select()`, any aggregate method
753
+ * (`.count()`, `.min()`, etc.), or a second `.projected()` call throws
754
+ * at runtime with a clear error message.
755
+ *
756
+ * @param name - The projection name.
757
+ * @returns A new builder whose result type is `Pick<Row, ProjectionKeys>`.
758
+ *
759
+ * @example
760
+ * ```ts
761
+ * const PostSchema = object({ id: number(), title: string(), body: string() })
762
+ * .hasTableName('posts')
763
+ * .projection('summary', 'id', 'title');
764
+ *
765
+ * const rows = await query(db, PostSchema)
766
+ * .scoped('published')
767
+ * .projected('summary');
768
+ * // rows: Array<Pick<Post, 'id' | 'title'>>
769
+ * // rows[0].body // ← TS error: not in projection
770
+ * ```
771
+ *
772
+ * @see {@link ddlExtension} `.projection()` for schema-side definition.
773
+ */
774
+ projected<K extends keyof ProjectionsOf<TLocalSchema> & string>(name: K): SchemaQueryBuilder<TLocalSchema, Pick<TResult, ProjectionKeysOf<TLocalSchema, K> & keyof TResult>>;
775
+ scoped<K extends ScopesOf<TLocalSchema>>(name: K): this;
776
+ /**
777
+ * Bypass the default scope (and soft-delete scope) for this query.
778
+ *
779
+ * @returns `this` for chaining.
780
+ *
781
+ * @example
782
+ * ```ts
783
+ * await query(db, Post).unscoped().where(t => t.id, 1);
784
+ * ```
785
+ */
786
+ unscoped(): this;
787
+ /**
788
+ * Add a WHERE condition that applies **only to rows matching a specific
789
+ * variant** of a polymorphic schema. Rows for other variants pass through
790
+ * unaffected (the condition is ORed away for non-matching discriminator values).
791
+ *
792
+ * The column name is resolved against the **variant's** schema properties.
793
+ *
794
+ * Only valid on a polymorphic schema (created via `.withVariants()`).
795
+ *
796
+ * @param key - The discriminator value identifying the variant (e.g. `'image'`).
797
+ * @param column - Property key on the variant's schema (e.g. `'width'`).
798
+ * @param operator - SQL comparison operator (`'='`, `'>'`, `'<'`, `'like'`, etc.).
799
+ * @param value - The value to compare against.
800
+ * @returns `this` for chaining.
801
+ *
802
+ * @example
803
+ * ```ts
804
+ * // Return all documents and only images wider than 1024 px
805
+ * const files = await query(db, FileSchema)
806
+ * .whereVariant('image', 'width', '>', 1024);
807
+ * ```
808
+ */
809
+ whereVariant(key: string, column: string, operator: string, value: any): this;
810
+ /**
811
+ * Restrict the query to only return rows for the specified variant keys.
812
+ *
813
+ * Adds `WHERE <discriminator> IN (...)` to the query and skips the LEFT
814
+ * JOINs for excluded variants. This is more efficient than filtering after
815
+ * loading all variants.
816
+ *
817
+ * Only valid on a polymorphic schema (created via `.withVariants()`).
818
+ *
819
+ * @param keys - Discriminator values to include (e.g. `['image', 'document']`).
820
+ * @returns `this` for chaining.
821
+ *
822
+ * @example
823
+ * ```ts
824
+ * const images = await query(db, FileSchema).selectVariants(['image']);
825
+ * // images: Array<{ id; name; type: 'image'; width; height; format }>
826
+ * ```
827
+ */
828
+ selectVariants(keys: string[]): this;
829
+ /**
830
+ * Include soft-deleted rows in the results.
831
+ *
832
+ * By default, schemas with `.softDelete()` automatically filter out
833
+ * rows where `deleted_at IS NOT NULL`. Call `.withDeleted()` to
834
+ * include them.
835
+ *
836
+ * @returns `this` for chaining.
837
+ */
838
+ withDeleted(): this;
839
+ /**
840
+ * Return only soft-deleted rows (`WHERE deleted_at IS NOT NULL`).
841
+ *
842
+ * @returns `this` for chaining.
843
+ */
844
+ onlyDeleted(): this;
845
+ /**
846
+ * Permanently delete rows matching the current WHERE clause, bypassing
847
+ * the soft-delete mechanism.
848
+ *
849
+ * @returns The number of rows deleted.
850
+ */
851
+ hardDelete(): Promise<number>;
852
+ /**
853
+ * Restore soft-deleted rows by setting `deleted_at = NULL`.
854
+ *
855
+ * @returns The restored rows.
856
+ */
857
+ restore(): Promise<TResult[]>;
858
+ /**
859
+ * Execute an offset-based paginated query.
860
+ *
861
+ * Runs a count query and a data query in parallel. Returns the page data
862
+ * along with pagination metadata.
863
+ *
864
+ * @param opts - `{ page, pageSize }` — 1-based page number and page size.
865
+ * @returns A {@link PaginationResult} with data, total count, and page info.
866
+ *
867
+ * @example
868
+ * ```ts
869
+ * const page = await query(db, Post)
870
+ * .where(t => t.status, 'published')
871
+ * .paginate({ page: 2, pageSize: 20 });
872
+ * // page.data, page.total, page.totalPages, page.hasNextPage, ...
873
+ * ```
874
+ */
875
+ paginate(opts: {
876
+ page: number;
877
+ pageSize: number;
878
+ }): Promise<PaginationResult<TResult>>;
879
+ /**
880
+ * Execute a cursor-based (keyset) paginated query.
881
+ *
882
+ * More efficient than offset pagination for large datasets. Fetches one
883
+ * extra row to determine whether more data exists.
884
+ *
885
+ * @param opts - `{ cursor, limit, column?, direction? }`.
886
+ * @returns A {@link CursorPaginationResult} with data, next cursor, and
887
+ * `hasMore` flag.
888
+ *
889
+ * @example
890
+ * ```ts
891
+ * const page = await query(db, Post)
892
+ * .orderBy(t => t.createdAt, 'desc')
893
+ * .paginateAfter({ cursor: lastCreatedAt, limit: 20 });
894
+ * ```
895
+ */
896
+ paginateAfter(opts: {
897
+ cursor?: any;
898
+ limit: number;
899
+ column?: ColumnRef<TLocalSchema>;
900
+ direction?: 'asc' | 'desc';
901
+ }): Promise<CursorPaginationResult<TResult>>;
902
+ /**
903
+ * Add a raw SQL expression to the SELECT clause.
904
+ *
905
+ * @param sql - Raw SQL (e.g. `'*, ts_rank(vector, query) AS rank'`).
906
+ * @param bindings - Optional parameter bindings.
907
+ * @returns `this` for chaining.
908
+ */
909
+ selectRaw(sql: string, bindings?: any[]): this;
475
910
  /**
476
911
  * Return the raw SQL string that would be executed, for debugging.
477
912
  * Does not execute the query against the database.
@@ -511,6 +946,20 @@ export declare class SchemaQueryBuilder<TLocalSchema extends ObjectSchemaBuilder
511
946
  * ```
512
947
  */
513
948
  first(): Promise<TResult | undefined>;
949
+ /**
950
+ * Execute the query and return an array of values for a single column.
951
+ *
952
+ * @param column - Column reference (property accessor or string key) for
953
+ * the column whose values should be returned.
954
+ * @returns A promise resolving to an array of values for that column.
955
+ *
956
+ * @example
957
+ * ```ts
958
+ * const names = await query(db, UserSchema).pluck(t => t.name);
959
+ * // names: string[]
960
+ * ```
961
+ */
962
+ pluck<K extends keyof TResult & string>(column: ColumnRef<TLocalSchema>): Promise<TResult[K][]>;
514
963
  /**
515
964
  * Thenable implementation — allows the builder to be awaited directly
516
965
  * without calling {@link execute} explicitly.
@@ -546,7 +995,7 @@ export declare class SchemaQueryBuilder<TLocalSchema extends ObjectSchemaBuilder
546
995
  * const users = await query(db, UserSchema).where(t => t.name, 'like', 'A%');
547
996
  * ```
548
997
  */
549
- export declare function query<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(knex: Knex, schema: TLocalSchema): SchemaQueryBuilder<TLocalSchema, InferType<TLocalSchema>>;
998
+ export declare function query<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(knex: Knex, schema: TLocalSchema): SchemaQueryBuilder<TLocalSchema, QueryResultType<TLocalSchema>>;
550
999
  /**
551
1000
  * Create a typed {@link SchemaQueryBuilder} from an existing Knex query builder.
552
1001
  *
@@ -565,11 +1014,11 @@ export declare function query<TLocalSchema extends ObjectSchemaBuilder<any, any,
565
1014
  * const activeUsers = await query(db, UserSchema, base).where(t => t.age, '>', 18);
566
1015
  * ```
567
1016
  */
568
- export declare function query<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(knex: Knex, schema: TLocalSchema, baseQuery: Knex.QueryBuilder): SchemaQueryBuilder<TLocalSchema, InferType<TLocalSchema>>;
1017
+ export declare function query<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(knex: Knex, schema: TLocalSchema, baseQuery: Knex.QueryBuilder): SchemaQueryBuilder<TLocalSchema, QueryResultType<TLocalSchema>>;
569
1018
  /** Bound query function returned by {@link createQuery}. */
570
1019
  export interface BoundQuery {
571
- <TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(schema: TLocalSchema): SchemaQueryBuilder<TLocalSchema, InferType<TLocalSchema>>;
572
- <TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(schema: TLocalSchema, baseQuery: Knex.QueryBuilder): SchemaQueryBuilder<TLocalSchema, InferType<TLocalSchema>>;
1020
+ <TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(schema: TLocalSchema): SchemaQueryBuilder<TLocalSchema, QueryResultType<TLocalSchema>>;
1021
+ <TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(schema: TLocalSchema, baseQuery: Knex.QueryBuilder): SchemaQueryBuilder<TLocalSchema, QueryResultType<TLocalSchema>>;
573
1022
  /**
574
1023
  * Return a version of this bound factory whose queries all run within the
575
1024
  * given Knex transaction. Equivalent to calling `.transacting(trx)` on
@@ -638,3 +1087,4 @@ export interface BoundQuery {
638
1087
  * ```
639
1088
  */
640
1089
  export declare function createQuery(knexInstance: Knex): BoundQuery;
1090
+ export {};
@@ -0,0 +1,2 @@
1
+ import{arrayExtensions as p,defineExtension as d,NumberSchemaBuilder as x,numberExtensions as S,ObjectSchemaBuilder as g,StringSchemaBuilder as b,SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR as E,stringExtensions as B,withExtensions as f}from"@cleverbrush/schema";import{EXTRA_TYPE_BRAND as Q,METHOD_LITERAL_BRAND as W}from"@cleverbrush/schema";var D=Symbol.for("@cleverbrush/knex-schema:primaryKey"),P=Symbol.for("@cleverbrush/knex-schema:compositePrimaryKey"),v=Symbol.for("@cleverbrush/knex-schema:polymorphicType");function r(n){return this.withExtension("columnName",n)}function T(n){return this.withExtension("tableName",n)}var w=d({string:{hasColumnName(n){return r.call(this,n)}},number:{hasColumnName(n){return r.call(this,n)}},boolean:{hasColumnName(n){return r.call(this,n)}},date:{hasColumnName(n){return r.call(this,n)}},any:{hasColumnName(n){return r.call(this,n)}},func:{hasColumnName(n){return r.call(this,n)}},array:{hasColumnName(n){return r.call(this,n)}},union:{hasColumnName(n){return r.call(this,n)}},generic:{hasColumnName(n){return r.call(this,n)}},object:{hasTableName(n){return T.call(this,n)}}}),R=d({number:{references(n,e="id"){return this.withExtension("references",{table:n,column:e})},onDelete(n){return this.withExtension("onDelete",n)},onUpdate(n){return this.withExtension("onUpdate",n)},defaultTo(n){return this.withExtension("defaultTo",n)},index(n){return this.withExtension("index",n??!0)},unique(n){return this.withExtension("unique",n??!0)},columnType(n){return this.withExtension("columnType",n)},bigint(){return this.withExtension("columnType","bigint")},smallint(){return this.withExtension("columnType","smallint")},decimal(n,e){return this.withExtension("columnType",`decimal(${n},${e})`)},defaultToRaw(n){return this.withExtension("defaultTo",{raw:n})},rowVersion(n){return this.withExtension("rowVersion",{strategy:n?.strategy??"increment"})}},string:{columnType(n){return this.withExtension("columnType",n)},text(){return this.withExtension("columnType","text")},asUuid(){return this.withExtension("columnType","uuid")},citext(){return this.withExtension("columnType","citext")},jsonb(){return this.withExtension("columnType","jsonb")},tsvector(){return this.withExtension("columnType","tsvector")},references(n,e="id"){return this.withExtension("references",{table:n,column:e})},onDelete(n){return this.withExtension("onDelete",n)},onUpdate(n){return this.withExtension("onUpdate",n)},unique(n){return this.withExtension("unique",n??!0)},index(n){return this.withExtension("index",n??!0)},defaultTo(n){return this.withExtension("defaultTo",n)},check(n){return this.withExtension("check",n)},defaultToRaw(n){return this.withExtension("defaultTo",{raw:n})},rowVersion(){return this.withExtension("rowVersion",{strategy:"manual"})}},boolean:{defaultTo(n){return this.withExtension("defaultTo",n)},columnType(n){return this.withExtension("columnType",n)},index(n){return this.withExtension("index",n??!0)},unique(n){return this.withExtension("unique",n??!0)}},date:{defaultTo(n){return this.withExtension("defaultTo",n)},columnType(n){return this.withExtension("columnType",n)},index(n){return this.withExtension("index",n??!0)},defaultToRaw(n){return this.withExtension("defaultTo",{raw:n})},timestamptz(){return this.withExtension("columnType","timestamptz")},dateOnly(){return this.withExtension("columnType","date")},rowVersion(){return this.withExtension("rowVersion",{strategy:"timestamp"})}},object:{columnType(n){return this.withExtension("columnType",n)},jsonb(){return this.withExtension("columnType","jsonb")},json(){return this.withExtension("columnType","json")},hasIndex(n,e){let a=this.getExtension("indexes")??[];return this.withExtension("indexes",[...a,{columns:n,...e}])},hasUnique(n,e){let a=this.getExtension("uniques")??[];return this.withExtension("uniques",[...a,{columns:n,name:e}])},hasCheck(n){let e=this.getExtension("checks")??[];return this.withExtension("checks",[...e,n])},hasRawColumn(n,e){let a=this.getExtension("rawColumns")??[];return this.withExtension("rawColumns",[...a,{name:n,definition:e}])},hasRawIndex(n){let e=this.getExtension("rawIndexes")??[];return this.withExtension("rawIndexes",[...e,n])},hasMany(n,e){let a=this.getExtension("relations")??[];return this.withExtension("relations",[...a,{type:"hasMany",name:n,...e}])},hasOne(n,e){let a=this.getExtension("relations")??[];return this.withExtension("relations",[...a,{type:"hasOne",name:n,...e}])},belongsTo(n,e){let a=this.getExtension("relations")??[];return this.withExtension("relations",[...a,{type:"belongsTo",name:n,...e}])},belongsToMany(n,e){let a=this.getExtension("relations")??[];return this.withExtension("relations",[...a,{type:"belongsToMany",name:n,...e}])},hasTimestamps(n){return this.withExtension("timestamps",{createdAt:n?.createdAt??"created_at",updatedAt:n?.updatedAt??"updated_at"})},softDelete(n){return this.withExtension("softDelete",{column:n?.column??"deleted_at"})},scope(n,e){let a=this.getExtension("scopes")??{};return this.withExtension("scopes",{...a,[n]:e})},projection(n,...e){let a=g.getPropertiesFor(this),y=e.map(h=>{if(typeof h=="string")return h;let t=h(a)[E];if(!t)throw new Error(`projection('${n}'): each accessor must return a valid PropertyDescriptor. Use \`t => t.propName\`.`);if(typeof t.propertyName!="string")throw new Error(`projection('${n}'): could not resolve property name from descriptor. Ensure the accessor returns a top-level property descriptor.`);return t.propertyName}),o=this.getExtension("projections")??{};if(Object.hasOwn(o,n))throw new Error(`projection('${n}'): a projection with this name is already registered on this schema. Each projection name must be unique.`);return this.withExtension("projections",{...o,[n]:{keys:y}})},defaultScope(n){return this.withExtension("defaultScope",n)},beforeInsert(n){let e=this.getExtension("beforeInsert")??[];return this.withExtension("beforeInsert",[...e,n])},afterInsert(n){let e=this.getExtension("afterInsert")??[];return this.withExtension("afterInsert",[...e,n])},beforeUpdate(n){let e=this.getExtension("beforeUpdate")??[];return this.withExtension("beforeUpdate",[...e,n])},beforeDelete(n){let e=this.getExtension("beforeDelete")??[];return this.withExtension("beforeDelete",[...e,n])}}});function I(n,e,a){let y={},o=[];for(let[i,t]of Object.entries(a)){let c=t.schema,m=c.introspect().properties??{};if(e in m){let l=m[e].introspect().equalsTo;if(l===void 0)throw new Error(`withVariants: variant "${i}" declares discriminator property "${e}" but it has no literal value \u2014 use string('${i}') instead of string()`);if(l!==i)throw new Error(`withVariants: variant "${i}" declares discriminator "${e}" = string('${l}') but the map key is '${i}' \u2014 they must match`)}let u;if(t.storage==="cti"){if(u=c.getExtension("tableName"),!u)throw new Error(`withVariants: CTI variant "${i}" schema must have .hasTableName() configured`);if(!t.foreignKeyColumn)throw new Error(`withVariants: CTI variant "${i}" must specify foreignKey (the FK property accessor on the variant schema)`)}y[i]={storage:t.storage,schema:c,foreignKey:t.foreignKeyColumn,tableName:u,allowOrphan:t.allowOrphan??!1,enforceCheck:t.enforceCheck??!1,relations:t.relations??[]},o.push(c)}let h={discriminatorKey:e,variants:y};return n.withExtension("variants",h).withExtension("polymorphicVariants",o)}var s=f(B,S,p,w,R),_=s.string,K=s.number,V=s.boolean,F=s.date,q=s.object,k=s.array,M=s.union,Y=s.func,U=s.any;(()=>{let n=x.prototype;typeof n.primaryKey!="function"&&(n.primaryKey=function(y){return this.withExtension("primaryKey",{autoIncrement:y?.autoIncrement??!0})});let e=b.prototype;typeof e.primaryKey!="function"&&(e.primaryKey=function(){return this.withExtension("primaryKey",{autoIncrement:!1})});let a=g.prototype;typeof a.hasPrimaryKey!="function"&&(a.hasPrimaryKey=function(y){return this.withExtension("compositePrimaryKey",y)})})();function $(n,e){let a=n.getExtension("columnName");return typeof a=="string"?a:e}function L(n){let e=n.getExtension("tableName");if(typeof e!="string")throw new Error('Schema does not have a table name. Use .hasTableName("table_name") to set one.');return e}function H(n){return n.getExtension("projections")??{}}function X(n){let e=n.getExtension("variants");return e??null}function z(n){return n.getExtension("polymorphicVariants")??[]}export{D as a,P as b,v as c,w as d,R as e,I as f,_ as g,K as h,V as i,F as j,q as k,k as l,M as m,Y as n,U as o,$ as p,L as q,H as r,X as s,z as t,Q as u,W as v};
2
+ //# sourceMappingURL=chunk-V4TH6K42.js.map