@cleverbrush/knex-schema 3.1.0 → 4.1.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.
@@ -0,0 +1,160 @@
1
+ import type { ObjectSchemaBuilder } from '@cleverbrush/schema';
2
+ import type { Knex } from 'knex';
3
+ import type { Entity } from './entity.js';
4
+ import type { DatabaseTableState, MigrationDiff, SchemaSnapshot } from './types.js';
5
+ /**
6
+ * Introspect a PostgreSQL table and return its current state.
7
+ *
8
+ * Queries `information_schema.columns`, `pg_indexes`, `pg_constraint`, and
9
+ * referential constraint metadata to build a complete picture of the table's
10
+ * columns, indexes, foreign keys, and check constraints.
11
+ *
12
+ * @param knex - A configured Knex instance connected to a PostgreSQL database.
13
+ * @param tableName - The table name to introspect.
14
+ * @returns The current database state for the table.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const dbState = await introspectDatabase(knex, 'users');
19
+ * console.log(dbState.columns); // { id: { type: 'integer', ... }, ... }
20
+ * ```
21
+ */
22
+ export declare function introspectDatabase(knex: Knex, tableName: string): Promise<DatabaseTableState>;
23
+ /**
24
+ * Derive a {@link DatabaseTableState} from a code-first `ObjectSchemaBuilder`
25
+ * without connecting to the database.
26
+ *
27
+ * The result mirrors what {@link introspectDatabase} would return after the
28
+ * schema has been fully applied, so it can be fed directly into
29
+ * {@link diffSchema} as the `dbState` argument. This is the foundation of
30
+ * snapshot-based migration generation.
31
+ *
32
+ * @param schema - An `ObjectSchemaBuilder` with DDL extensions.
33
+ * @returns A {@link DatabaseTableState} representing the schema's ideal DB shape.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const state = entitySchemaToTableState(UserSchema);
38
+ * // state.columns, state.foreignKeys, state.indexes …
39
+ * ```
40
+ */
41
+ export declare function entitySchemaToTableState(schema: ObjectSchemaBuilder<any, any, any, any, any, any, any>): DatabaseTableState;
42
+ /**
43
+ * Compare a code-first schema model against a live database table state and
44
+ * produce a diff describing the changes needed to bring the database in sync.
45
+ *
46
+ * @param schema - The code-first `ObjectSchemaBuilder`.
47
+ * @param dbState - The current database state from {@link introspectDatabase}.
48
+ * @returns A {@link MigrationDiff} describing columns, indexes, and foreign
49
+ * keys to add, drop, or alter.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const dbState = await introspectDatabase(knex, 'users');
54
+ * const diff = diffSchema(UserSchema, dbState);
55
+ * if (diff.addColumns.length > 0) {
56
+ * const migration = generateMigration(diff, 'users');
57
+ * console.log(migration.up);
58
+ * }
59
+ * ```
60
+ */
61
+ export declare function diffSchema(schema: ObjectSchemaBuilder<any, any, any, any, any, any, any>, dbState: DatabaseTableState): MigrationDiff;
62
+ /**
63
+ * Generate migration `up` and `down` code strings from a {@link MigrationDiff}.
64
+ *
65
+ * The generated code is valid TypeScript that uses Knex's schema builder API.
66
+ * Write it to a migration file and run via Knex's migration system.
67
+ *
68
+ * @param diff - The schema diff from {@link diffSchema}.
69
+ * @param tableName - The table name to alter.
70
+ * @returns An object with `up` and `down` migration code strings.
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * const diff = diffSchema(UserSchema, dbState);
75
+ * const migration = generateMigration(diff, 'users');
76
+ * fs.writeFileSync('migration.ts', migration.full);
77
+ * ```
78
+ */
79
+ export declare function generateMigration(diff: MigrationDiff, tableName: string): {
80
+ up: string;
81
+ down: string;
82
+ full: string;
83
+ };
84
+ /**
85
+ * Check whether a table exists in the connected PostgreSQL database.
86
+ *
87
+ * @param knex - A configured Knex instance (or transaction).
88
+ * @param tableName - The table name to check.
89
+ * @returns `true` when the table exists.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * const exists = await tableExistsInDb(knex, 'users');
94
+ * if (!exists) await generateCreateTable(UserSchema)(knex);
95
+ * ```
96
+ */
97
+ export declare function tableExistsInDb(knex: Knex, tableName: string): Promise<boolean>;
98
+ /**
99
+ * Return `true` when a {@link MigrationDiff} has no operations — i.e. the
100
+ * database table is already in sync with the schema.
101
+ */
102
+ export declare function isDiffEmpty(diff: MigrationDiff): boolean;
103
+ /**
104
+ * Execute a {@link MigrationDiff} directly against a live database without
105
+ * writing a migration file. Intended for `db push` (dev-only schema sync).
106
+ *
107
+ * Foreign-key constraint drops are executed as raw `ALTER TABLE … DROP
108
+ * CONSTRAINT` statements before the main `alterTable` call.
109
+ *
110
+ * @param knex - A configured Knex instance or transaction.
111
+ * @param diff - The diff from {@link diffSchema}.
112
+ * @param tableName - The table to alter.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * const dbState = await introspectDatabase(knex, 'users');
117
+ * const diff = diffSchema(UserSchema, dbState);
118
+ * if (!isDiffEmpty(diff)) await applyDiff(knex, diff, 'users');
119
+ * ```
120
+ */
121
+ export declare function applyDiff(knex: Knex, diff: MigrationDiff, tableName: string): Promise<void>;
122
+ /**
123
+ * Generate a single combined migration (up + down) for a set of entities by
124
+ * diffing the current code-first schemas against a **serialized snapshot**
125
+ * stored in the repository — no live database connection required.
126
+ *
127
+ * For each entity's table the function:
128
+ * - **New tables** (in entities but not in `prevSnapshot`): emits `CREATE TABLE`.
129
+ * - **Existing tables** (in both): diffs entity schema against the snapshot
130
+ * state via {@link diffSchema} and emits `ALTER TABLE` when changes exist.
131
+ * - **Dropped tables** (in `prevSnapshot` but not in entities): emits
132
+ * `DROP TABLE` with a best-effort `CREATE TABLE` in the `down` direction.
133
+ * - Orders tables topologically by FK dependencies so parent tables are
134
+ * created before child tables in `up` (and dropped after in `down`).
135
+ *
136
+ * @param entities - The entities from your {@link EntityMap}.
137
+ * @param prevSnapshot - The last committed {@link SchemaSnapshot} (empty on first run).
138
+ * @returns `{ up, down, full, isEmpty, nextSnapshot }` where `nextSnapshot`
139
+ * should be written to disk after the migration file is created.
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * const prev = loadSnapshot('./migrations/snapshot.json');
144
+ * const result = generateMigrationsForContext(
145
+ * Object.values({ todos: TodoEntity, users: UserEntity }),
146
+ * prev
147
+ * );
148
+ * if (!result.isEmpty) {
149
+ * fs.writeFileSync('migrations/20260423000000_init.ts', result.full);
150
+ * writeSnapshot('./migrations/snapshot.json', result.nextSnapshot);
151
+ * }
152
+ * ```
153
+ */
154
+ export declare function generateMigrationsForContext(entities: Entity<any, any>[], prevSnapshot: SchemaSnapshot): {
155
+ up: string;
156
+ down: string;
157
+ full: string;
158
+ isEmpty: boolean;
159
+ nextSnapshot: SchemaSnapshot;
160
+ };
@@ -0,0 +1,6 @@
1
+ import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js';
2
+ export declare function deleteImpl(builder: SchemaQueryBuilder<any, any>): Promise<number>;
3
+ export declare function withDeletedImpl(builder: SchemaQueryBuilder<any, any>): any;
4
+ export declare function onlyDeletedImpl(builder: SchemaQueryBuilder<any, any>): any;
5
+ export declare function hardDeleteImpl(builder: SchemaQueryBuilder<any, any>): Promise<number>;
6
+ export declare function restoreImpl(builder: SchemaQueryBuilder<any, any>): Promise<any[]>;
@@ -0,0 +1,57 @@
1
+ import type { InferType } from '@cleverbrush/schema';
2
+ import { EXTRA_TYPE_BRAND, METHOD_LITERAL_BRAND, ObjectSchemaBuilder } from '@cleverbrush/schema';
3
+ import type { Knex } from 'knex';
4
+ import { POLYMORPHIC_TYPE_BRAND } from '../extension.js';
5
+ import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js';
6
+ import type { ResolvedVariantConfig, ValidatedSpec } from '../types.js';
7
+ export type ScopesOf<S> = S extends {
8
+ readonly [METHOD_LITERAL_BRAND]?: infer N;
9
+ } ? Extract<N, string> : never;
10
+ export type ProjectionsOf<S> = S extends {
11
+ readonly [EXTRA_TYPE_BRAND]?: infer P;
12
+ } ? P extends Record<string, readonly string[]> ? P : Record<never, never> : Record<never, never>;
13
+ export type ProjectionKeysOf<S, K extends keyof ProjectionsOf<S> & string> = ProjectionsOf<S>[K] extends readonly (infer T extends string)[] ? T : string;
14
+ export type QueryResultType<TLocalSchema> = TLocalSchema extends {
15
+ readonly [POLYMORPHIC_TYPE_BRAND]?: infer U;
16
+ } ? NonNullable<U> : InferType<TLocalSchema>;
17
+ export declare function resolveColumn(builder: SchemaQueryBuilder<any, any>, ref: any, label?: string): string | Knex.Raw;
18
+ export declare function invalidateCache(builder: SchemaQueryBuilder<any, any>): void;
19
+ export declare function getSoftDelete(builder: SchemaQueryBuilder<any, any>): {
20
+ column: string;
21
+ } | null;
22
+ export declare function getDefaultScope(builder: SchemaQueryBuilder<any, any>): Function | null;
23
+ export declare function getTimestamps(builder: SchemaQueryBuilder<any, any>): {
24
+ createdAt: string;
25
+ updatedAt: string;
26
+ } | null;
27
+ declare const ALLOWED_OPS: Set<string>;
28
+ export { ALLOWED_OPS };
29
+ export declare function getVariantConfig(builder: SchemaQueryBuilder<any, any>): ResolvedVariantConfig | null;
30
+ export declare function applyVariantJoins(builder: SchemaQueryBuilder<any, any>, base: Knex.QueryBuilder, variantConfig: ResolvedVariantConfig): Knex.QueryBuilder;
31
+ export declare function registerSchemaQueryBuilder(ctor: new (...args: any[]) => any): void;
32
+ export declare function getSchemaQueryBuilderCtor(): new (...args: any[]) => any;
33
+ export declare function buildVariantRelationSelect(builder: SchemaQueryBuilder<any, any>, foreignSchema: ObjectSchemaBuilder<any, any, any, any, any, any, any>, relAlias: string, foreignTableName: string, customize?: (q: SchemaQueryBuilder<any, any>) => void): Knex.Raw[];
34
+ export declare function mapPolymorphicRow(builder: SchemaQueryBuilder<any, any>, row: Record<string, any>, variantConfig: ResolvedVariantConfig): Record<string, any>;
35
+ export declare function resolveSchema(_builder: SchemaQueryBuilder<any, any>, schema: any): ObjectSchemaBuilder<any, any, any, any, any, any, any>;
36
+ export declare function findPrimaryKeyColumn(_builder: SchemaQueryBuilder<any, any>, schema: ObjectSchemaBuilder<any, any, any, any, any, any, any>): string;
37
+ export declare function resolvePkColumns(builder: SchemaQueryBuilder<any, any>): {
38
+ propertyKeys: readonly string[];
39
+ columnNames: readonly string[];
40
+ };
41
+ export declare function getEffectiveBaseQuery(builder: SchemaQueryBuilder<any, any>): Knex.QueryBuilder;
42
+ export declare function buildJoinOne(builder: SchemaQueryBuilder<any, any>, resultQuery: Knex.QueryBuilder, spec: ValidatedSpec & {
43
+ type: 'one';
44
+ }, relationAlias: string): void;
45
+ export declare function buildJoinMany(builder: SchemaQueryBuilder<any, any>, resultQuery: Knex.QueryBuilder, spec: ValidatedSpec & {
46
+ type: 'many';
47
+ }, relationAlias: string, i: number): void;
48
+ export declare function buildQuery(builder: SchemaQueryBuilder<any, any>): Knex.QueryBuilder;
49
+ export declare function getQuery(builder: SchemaQueryBuilder<any, any>): Knex.QueryBuilder;
50
+ export declare function mapRow(builder: SchemaQueryBuilder<any, any>, row: Record<string, any>): Record<string, any>;
51
+ export declare function cleanAndMapRow(builder: SchemaQueryBuilder<any, any>, row: Record<string, any>): Record<string, any>;
52
+ export declare function mapObjectToColumns(builder: SchemaQueryBuilder<any, any>, obj: Record<string, any>): Record<string, any>;
53
+ export declare function mapRecordToColumns(builder: SchemaQueryBuilder<any, any>, record: Record<string, any>): Record<string, any>;
54
+ export declare function resolveColumnArg(builder: SchemaQueryBuilder<any, any>, col: any): string | Knex.Raw;
55
+ export declare function isColumnAccessor(builder: SchemaQueryBuilder<any, any>, fn: Function): boolean;
56
+ export declare function assertNotProjection(builder: SchemaQueryBuilder<any, any>, method: string): void;
57
+ export declare function assertNotExplicitSelect(builder: SchemaQueryBuilder<any, any>, method: string): void;
@@ -0,0 +1,26 @@
1
+ import type { InferType } from '@cleverbrush/schema';
2
+ import type { Knex } from 'knex';
3
+ import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js';
4
+ import type { ColumnRef, InsertType } from '../types.js';
5
+ export declare class OnConflictBuilder<TLocalSchema extends import('@cleverbrush/schema').ObjectSchemaBuilder<any, any, any, any, any, any, any>, TResult> {
6
+ #private;
7
+ constructor(knex: Knex, localSchema: TLocalSchema, _parent: SchemaQueryBuilder<TLocalSchema, TResult>, conflictColumns: string[]);
8
+ merge(data: InsertType<TLocalSchema>, updateData?: Partial<InferType<TLocalSchema>>): Promise<TResult>;
9
+ ignore(data: InsertType<TLocalSchema>): Promise<TResult | undefined>;
10
+ }
11
+ export declare function insertImpl(builder: SchemaQueryBuilder<any, any>, data: InsertType<any>): Promise<any>;
12
+ export declare function insertManyImpl(builder: SchemaQueryBuilder<any, any>, data: InsertType<any>[]): Promise<any[]>;
13
+ export declare function onConflictImpl(builder: SchemaQueryBuilder<any, any>, ...conflictColumns: ColumnRef<any>[]): OnConflictBuilder<any, any>;
14
+ export declare function upsertImpl(builder: SchemaQueryBuilder<any, any>, data: InsertType<any>, opts: {
15
+ conflictColumns: ColumnRef<any>[];
16
+ updateColumns?: ColumnRef<any>[];
17
+ }): Promise<any>;
18
+ export declare function bulkInsertImpl(builder: SchemaQueryBuilder<any, any>, rows: InsertType<any>[], opts?: {
19
+ chunkSize?: number;
20
+ onConflict?: 'ignore' | 'merge';
21
+ conflictColumns?: ColumnRef<any>[];
22
+ }): Promise<any[]>;
23
+ export declare function bulkUpsertImpl(builder: SchemaQueryBuilder<any, any>, rows: InsertType<any>[], opts: {
24
+ conflictColumns: ColumnRef<any>[];
25
+ chunkSize?: number;
26
+ }): Promise<any[]>;
@@ -0,0 +1,6 @@
1
+ import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js';
2
+ import type { JoinManySpec, JoinOneSpec } from '../types.js';
3
+ export declare function joinOneImpl(builder: SchemaQueryBuilder<any, any>, spec: JoinOneSpec<any, any, any, any>): any;
4
+ export declare function joinManyImpl(builder: SchemaQueryBuilder<any, any>, spec: JoinManySpec<any, any, any>): any;
5
+ export declare function includeImpl(builder: SchemaQueryBuilder<any, any>, relationName: string, customize?: (q: SchemaQueryBuilder<any, any>) => void): any;
6
+ export declare function includeVariantImpl(builder: SchemaQueryBuilder<any, any>, variantKey: string, relationName: string, customize?: (q: SchemaQueryBuilder<any, any>) => void): any;
@@ -0,0 +1,15 @@
1
+ import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js';
2
+ import type { ColumnRef, CursorPaginationResult, PaginationResult } from '../types.js';
3
+ export declare function limitImpl(builder: SchemaQueryBuilder<any, any>, n: number): any;
4
+ export declare function offsetImpl(builder: SchemaQueryBuilder<any, any>, n: number): any;
5
+ export declare function paginateImpl(builder: SchemaQueryBuilder<any, any>, opts: {
6
+ page: number;
7
+ pageSize: number;
8
+ }): Promise<PaginationResult<any>>;
9
+ export declare function paginateAfterImpl(builder: SchemaQueryBuilder<any, any>, opts: {
10
+ cursor?: any;
11
+ limit: number;
12
+ column?: ColumnRef<any>;
13
+ direction?: 'asc' | 'desc';
14
+ }): Promise<CursorPaginationResult<any>>;
15
+ export declare function executeImpl(builder: SchemaQueryBuilder<any, any>): Promise<any[]>;
@@ -0,0 +1,15 @@
1
+ import type { Knex } from 'knex';
2
+ import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js';
3
+ import type { ColumnRef } from '../types.js';
4
+ export declare function selectImpl(builder: SchemaQueryBuilder<any, any>, ...args: unknown[]): any;
5
+ export declare function distinctImpl(builder: SchemaQueryBuilder<any, any>, ...columns: (ColumnRef<any> | Knex.Raw)[]): any;
6
+ export declare function countImpl(builder: SchemaQueryBuilder<any, any>, column?: ColumnRef<any> | Knex.Raw): any;
7
+ export declare function countDistinctImpl(builder: SchemaQueryBuilder<any, any>, column?: ColumnRef<any> | Knex.Raw): any;
8
+ export declare function minImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any> | Knex.Raw): any;
9
+ export declare function maxImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any> | Knex.Raw): any;
10
+ export declare function sumImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any> | Knex.Raw): any;
11
+ export declare function avgImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any> | Knex.Raw): any;
12
+ export declare function selectRawImpl(builder: SchemaQueryBuilder<any, any>, sql: string, bindings?: any[]): any;
13
+ export declare function projectedImpl(builder: SchemaQueryBuilder<any, any>, name: string): any;
14
+ export declare function scopedImpl(builder: SchemaQueryBuilder<any, any>, name: string): any;
15
+ export declare function unscopedImpl(builder: SchemaQueryBuilder<any, any>): any;
@@ -0,0 +1,39 @@
1
+ import type { ObjectSchemaBuilder } from '@cleverbrush/schema';
2
+ import type { Knex } from 'knex';
3
+ import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js';
4
+ import type { ResolvedVariantConfig, ValidatedSpec, VariantWhereFilter } from '../types.js';
5
+ export interface QueryBuilderState {
6
+ knex: Knex;
7
+ baseQuery: Knex.QueryBuilder;
8
+ localSchema: ObjectSchemaBuilder<any, any, any, any, any, any, any>;
9
+ specs: ValidatedSpec[];
10
+ tableName: string;
11
+ /** SQL column names explicitly passed to `.select()`. null = SELECT *. */
12
+ explicitSelects: string[] | null;
13
+ /** Column-selection mode: null, 'select', 'aggregate', or 'projection'. */
14
+ selectionMode: 'select' | 'aggregate' | 'projection' | null;
15
+ /** Name of the projection currently applied, for error messages. */
16
+ appliedProjection: string | null;
17
+ /** When true, soft-delete filter is NOT applied. */
18
+ includeDeleted: boolean;
19
+ /** When true, only soft-deleted rows are returned. */
20
+ onlyDeleted: boolean;
21
+ /** When true, default scope is not applied. */
22
+ skipDefaultScope: boolean;
23
+ /** Resolved variant config, lazily populated. undefined = not yet read; null = not polymorphic. */
24
+ variantConfig: ResolvedVariantConfig | null | undefined;
25
+ /** When set, only these discriminator values are returned. null = all variants. */
26
+ enabledVariants: Set<string> | null;
27
+ /** Pending per-variant WHERE filters registered via .whereVariant(). */
28
+ variantWhereFilters: VariantWhereFilter[];
29
+ /** Variant-relation eager-load requests registered via .includeVariant(). */
30
+ variantRelationIncludes: Array<{
31
+ variantKey: string;
32
+ relationName: string;
33
+ customize?: (q: SchemaQueryBuilder<any, any>) => void;
34
+ }>;
35
+ /** Memoized result of buildQuery(). null = needs rebuild. */
36
+ cachedBuiltQuery: Knex.QueryBuilder | null;
37
+ }
38
+ export declare function getState(builder: SchemaQueryBuilder<any, any>): QueryBuilderState;
39
+ export declare function setState(builder: SchemaQueryBuilder<any, any>, state: QueryBuilderState): void;
@@ -0,0 +1,7 @@
1
+ import type { InferType } from '@cleverbrush/schema';
2
+ import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js';
3
+ export declare function updateImpl(builder: SchemaQueryBuilder<any, any>, data: Partial<InferType<any>>): Promise<any[]>;
4
+ export declare function bulkUpdateImpl(builder: SchemaQueryBuilder<any, any>, updates: ReadonlyArray<{
5
+ where: Partial<InferType<any>>;
6
+ set: Partial<InferType<any>>;
7
+ }>): Promise<number>;
@@ -0,0 +1,29 @@
1
+ import type { Knex } from 'knex';
2
+ import type { SchemaQueryBuilder } from '../SchemaQueryBuilder.js';
3
+ import type { ColumnRef } from '../types.js';
4
+ export declare function whereImpl(builder: SchemaQueryBuilder<any, any>, columnOrRaw: any, ...args: any[]): any;
5
+ export declare function andWhereImpl(builder: SchemaQueryBuilder<any, any>, columnOrRaw: any, ...args: any[]): any;
6
+ export declare function orWhereImpl(builder: SchemaQueryBuilder<any, any>, columnOrRaw: any, ...args: any[]): any;
7
+ export declare function whereNotImpl(builder: SchemaQueryBuilder<any, any>, columnOrRaw: any, ...args: any[]): any;
8
+ export declare function whereInImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>, values: readonly any[] | Knex.QueryBuilder): any;
9
+ export declare function whereNotInImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>, values: readonly any[] | Knex.QueryBuilder): any;
10
+ export declare function orWhereInImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>, values: readonly any[] | Knex.QueryBuilder): any;
11
+ export declare function orWhereNotInImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>, values: readonly any[] | Knex.QueryBuilder): any;
12
+ export declare function whereNullImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>): any;
13
+ export declare function whereNotNullImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>): any;
14
+ export declare function orWhereNullImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>): any;
15
+ export declare function orWhereNotNullImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>): any;
16
+ export declare function whereBetweenImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>, range: readonly [any, any]): any;
17
+ export declare function whereNotBetweenImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>, range: readonly [any, any]): any;
18
+ export declare function whereLikeImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>, value: string): any;
19
+ export declare function whereILikeImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>, value: string): any;
20
+ export declare function whereRawImpl(builder: SchemaQueryBuilder<any, any>, sql: string, ...bindings: any[]): any;
21
+ export declare function whereExistsImpl(builder: SchemaQueryBuilder<any, any>, callback: Knex.QueryCallback | Knex.QueryBuilder): any;
22
+ export declare function whereNotExistsImpl(builder: SchemaQueryBuilder<any, any>, callback: Knex.QueryCallback | Knex.QueryBuilder): any;
23
+ export declare function whereJsonPathImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any>, path: string, operator?: string, value?: any): any;
24
+ export declare function orderByImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any> | Knex.Raw, direction?: 'asc' | 'desc'): any;
25
+ export declare function orderByRawImpl(builder: SchemaQueryBuilder<any, any>, sql: string, ...bindings: any[]): any;
26
+ export declare function groupByImpl(builder: SchemaQueryBuilder<any, any>, ...columns: (ColumnRef<any> | Knex.Raw)[]): any;
27
+ export declare function groupByRawImpl(builder: SchemaQueryBuilder<any, any>, sql: string, ...bindings: any[]): any;
28
+ export declare function havingImpl(builder: SchemaQueryBuilder<any, any>, column: ColumnRef<any> | Knex.Raw, operator: string, value: any): any;
29
+ export declare function havingRawImpl(builder: SchemaQueryBuilder<any, any>, sql: string, ...bindings: any[]): any;
package/dist/raw.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ import type { InferType, ObjectSchemaBuilder } from '@cleverbrush/schema';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Execute a raw SQL query or Knex query builder and map the result rows
5
+ * through the schema's column→property name mapping.
6
+ *
7
+ * This is the escape hatch for complex queries that can't be expressed with
8
+ * the typed `SchemaQueryBuilder` API. The schema is used only for result
9
+ * mapping — column names in the result are converted back to property names.
10
+ * Extra columns (not in the schema) are passed through unchanged.
11
+ *
12
+ * @param knex - A configured Knex instance.
13
+ * @param schema - The `ObjectSchemaBuilder` for result mapping.
14
+ * @param queryOrSql - A raw SQL string or a `Knex.QueryBuilder`.
15
+ * @param bindings - Optional bindings for parameterised SQL queries.
16
+ * @returns Mapped result rows.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * // Raw SQL with schema result mapping
21
+ * const results = await rawQuery(knex, PostSchema, `
22
+ * SELECT p.*, COUNT(c.id) AS comment_count
23
+ * FROM posts p
24
+ * LEFT JOIN comments c ON c.post_id = p.id
25
+ * GROUP BY p.id
26
+ * ORDER BY comment_count DESC
27
+ * LIMIT ?
28
+ * `, [10]);
29
+ *
30
+ * // Knex query builder as the source
31
+ * const subQuery = knex('posts').select('author_id', knex.raw('COUNT(*) as post_count')).groupBy('author_id');
32
+ * const results = await rawQuery(knex, UserSchema, subQuery);
33
+ * ```
34
+ */
35
+ export declare function rawQuery<TSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>>(knex: Knex, schema: TSchema, queryOrSql: string | Knex.QueryBuilder, bindings?: any[]): Promise<(InferType<TSchema> & Record<string, any>)[]>;
@@ -0,0 +1,39 @@
1
+ import type { Entity } from './entity.js';
2
+ import type { SchemaSnapshot } from './types.js';
3
+ /**
4
+ * Build a {@link SchemaSnapshot} from a set of entities without a live DB.
5
+ *
6
+ * Handles polymorphic (CTI) entities by including each variant table.
7
+ * Deduplicates tables so STI variants sharing a base table are only included
8
+ * once.
9
+ *
10
+ * @param entities - The entities from your `EntityMap`.
11
+ * @returns A snapshot reflecting the current code-first schema state.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * const snapshot = entitiesToSnapshot(Object.values(entityMap));
16
+ * writeSnapshot('./migrations/snapshot.json', snapshot);
17
+ * ```
18
+ */
19
+ export declare function entitiesToSnapshot(entities: Entity<any, any>[]): SchemaSnapshot;
20
+ /**
21
+ * Load a {@link SchemaSnapshot} from disk.
22
+ *
23
+ * Returns an empty snapshot (no tables) when the file does not exist — this
24
+ * is the "first run" case, which causes `migrate generate` to emit a single
25
+ * migration containing `CREATE TABLE` for every entity.
26
+ *
27
+ * @param snapshotPath - Absolute or cwd-relative path to `snapshot.json`.
28
+ * @returns The parsed snapshot, or `{ version: 1, tables: {} }` if missing or
29
+ * unreadable.
30
+ */
31
+ export declare function loadSnapshot(snapshotPath: string): SchemaSnapshot;
32
+ /**
33
+ * Write a {@link SchemaSnapshot} to disk atomically (temp-file + rename) with
34
+ * deterministic key ordering so diffs in version control are minimal.
35
+ *
36
+ * @param snapshotPath - Absolute or cwd-relative path to write `snapshot.json`.
37
+ * @param snapshot - The snapshot to serialize.
38
+ */
39
+ export declare function writeSnapshot(snapshotPath: string, snapshot: SchemaSnapshot): void;