@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.
package/dist/types.d.ts CHANGED
@@ -89,4 +89,273 @@ export type ValidatedSpec = ({
89
89
  type: 'many';
90
90
  } & ValidatedJoinManySpec);
91
91
  export type InsertType<T extends ObjectSchemaBuilder<any, any, any, any, any, any, any>> = InferType<ReturnType<T['makeAllPropsOptional']>>;
92
+ import type { COMPOSITE_PRIMARY_KEY_BRAND, PRIMARY_KEY_BRAND } from './extension.js';
93
+ /**
94
+ * Detect whether a property schema is branded as a primary key (i.e. its
95
+ * schema was created with `.primaryKey()`).
96
+ *
97
+ * @internal
98
+ */
99
+ type IsPkBranded<TPropSchema> = TPropSchema extends {
100
+ readonly [PRIMARY_KEY_BRAND]?: true;
101
+ } ? true : false;
102
+ /**
103
+ * Extract the primary-key column descriptor for a schema.
104
+ *
105
+ * Returns:
106
+ * - the literal property-key string for a single-column primary key
107
+ * (e.g. `'id'`),
108
+ * - a tuple of property-key strings for a composite primary key
109
+ * (e.g. `['userId', 'roleId']`),
110
+ * - or `never` if no primary key is declared.
111
+ *
112
+ * Composite primary keys are detected via the `COMPOSITE_PRIMARY_KEY_BRAND`
113
+ * placed on the object schema by `.hasPrimaryKey([...] as const)`. Use
114
+ * `as const` on the column tuple to preserve ordering at the type level.
115
+ *
116
+ * @public
117
+ */
118
+ export type PrimaryKeyOf<S extends ObjectSchemaBuilder<any, any, any, any, any, any, any>> = S extends {
119
+ readonly [COMPOSITE_PRIMARY_KEY_BRAND]?: infer TCols;
120
+ } ? TCols extends readonly string[] ? TCols : never : {
121
+ [K in keyof SchemaPropsForPk<S> & string]: IsPkBranded<SchemaPropsForPk<S>[K]> extends true ? K : never;
122
+ }[keyof SchemaPropsForPk<S> & string];
123
+ /**
124
+ * Extract the schema's property record for primary-key inference. Mirrors
125
+ * `SchemaProps` from `entity.ts` but lives here to avoid a circular import.
126
+ *
127
+ * @internal
128
+ */
129
+ type SchemaPropsForPk<T> = T extends ObjectSchemaBuilder<infer P, any, any, any, any, any, any> ? P : never;
130
+ /**
131
+ * The runtime value type of a schema's primary key.
132
+ *
133
+ * - For a single-column PK, the inferred type of that property
134
+ * (e.g. `number`).
135
+ * - For a composite PK, a tuple of inferred property types in declared
136
+ * order (e.g. `[number, number]`).
137
+ * - `never` if no primary key is declared.
138
+ *
139
+ * @public
140
+ */
141
+ export type PrimaryKeyValueOf<S extends ObjectSchemaBuilder<any, any, any, any, any, any, any>> = PrimaryKeyOf<S> extends readonly (infer _Item extends string)[] ? PrimaryKeyOf<S> extends readonly string[] ? PkTupleValue<S, PrimaryKeyOf<S>> : never : PrimaryKeyOf<S> extends string ? InferType<S>[PrimaryKeyOf<S> & keyof InferType<S>] : never;
142
+ /**
143
+ * Map a tuple of PK property-key names to their inferred value types.
144
+ *
145
+ * @internal
146
+ */
147
+ type PkTupleValue<S extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TKeys extends readonly string[]> = {
148
+ [I in keyof TKeys]: TKeys[I] extends keyof InferType<S> ? InferType<S>[TKeys[I]] : unknown;
149
+ };
150
+ /**
151
+ * Extract the property schema captured inside a `PropertyDescriptor`.
152
+ *
153
+ * @internal
154
+ */
155
+ type DescriptorPropertySchema<T> = T extends PropertyDescriptor<any, infer S, any, any> ? S : never;
156
+ /**
157
+ * Result row type produced by a {@link SelectProjection} selector.
158
+ *
159
+ * Each entry's value is the {@link InferType} of the property schema the
160
+ * descriptor points at, so `.select(t => ({ id: t.id, n: t.title }))`
161
+ * yields `{ id: number; n: string }`.
162
+ *
163
+ * @public
164
+ */
165
+ export type SelectProjection<R extends Record<string, unknown>> = {
166
+ [K in keyof R]: InferType<DescriptorPropertySchema<R[K]>>;
167
+ };
168
+ /**
169
+ * Callback shape accepted by the projection overload of `select`. The
170
+ * callback receives the schema's property-descriptor tree and returns an
171
+ * `{ alias: descriptor }` record.
172
+ *
173
+ * @public
174
+ */
175
+ export type SelectSelector<T extends ObjectSchemaBuilder<any, any, any, any, any, any, any>> = (tree: PropertyDescriptorTree<SchemaBase<T>, SchemaBase<T>>) => Record<string, PropertyDescriptor<any, any, any>>;
176
+ /** Result of offset-based pagination via {@link SchemaQueryBuilder.paginate}. */
177
+ export interface PaginationResult<T> {
178
+ /** The rows for the current page. */
179
+ data: T[];
180
+ /** Total number of matching rows across all pages. */
181
+ total: number;
182
+ /** Current page number (1-based). */
183
+ page: number;
184
+ /** Number of rows per page. */
185
+ pageSize: number;
186
+ /** Total number of pages. */
187
+ totalPages: number;
188
+ /** Whether a next page exists. */
189
+ hasNextPage: boolean;
190
+ /** Whether a previous page exists. */
191
+ hasPreviousPage: boolean;
192
+ }
193
+ /** Result of cursor-based pagination via {@link SchemaQueryBuilder.paginateAfter}. */
194
+ export interface CursorPaginationResult<T> {
195
+ /** The rows for the current page. */
196
+ data: T[];
197
+ /** Cursor value for the next page, or `null` if no more rows. */
198
+ nextCursor: string | null;
199
+ /** Whether more rows exist after this page. */
200
+ hasMore: boolean;
201
+ }
202
+ /** Storage strategy for a polymorphic variant. */
203
+ export type VariantStorageType = 'cti' | 'sti';
204
+ /** @internal Resolved form of a variant relation stored on {@link ResolvedVariantSpec}. */
205
+ export interface ResolvedVariantRelationSpec {
206
+ name: string;
207
+ type: 'hasMany' | 'hasOne' | 'belongsTo' | 'belongsToMany';
208
+ schema: any;
209
+ /** Resolved FK *column* name on the variant or foreign table. */
210
+ foreignKey?: string;
211
+ through?: {
212
+ table: string;
213
+ localKey: string;
214
+ foreignKey: string;
215
+ };
216
+ }
217
+ /** @internal Resolved, normalised variant spec stored in schema extensions. */
218
+ export interface ResolvedVariantSpec {
219
+ storage: VariantStorageType;
220
+ schema: ObjectSchemaBuilder<any, any, any, any, any, any, any>;
221
+ /** CTI: FK column name on the variant table. */
222
+ foreignKey?: string;
223
+ /** CTI: variant table name (from `schema.hasTableName()`). */
224
+ tableName?: string;
225
+ allowOrphan: boolean;
226
+ enforceCheck: boolean;
227
+ /** Variant-scoped relations (resolved), populated by `.withVariants()`. */
228
+ relations: ResolvedVariantRelationSpec[];
229
+ }
230
+ /** @internal Full variant config stored in the schema extension `'variants'`. */
231
+ export interface ResolvedVariantConfig {
232
+ /** Property key on the base schema that is the discriminator. */
233
+ discriminatorKey: string;
234
+ /** SQL column name corresponding to `discriminatorKey`. Filled by query builder. */
235
+ discriminatorColumn: string;
236
+ /** Map from discriminator value → resolved variant spec. */
237
+ variants: Record<string, ResolvedVariantSpec>;
238
+ }
239
+ /** @internal Pending filter registered via `.whereVariant()`. */
240
+ export interface VariantWhereFilter {
241
+ /** The discriminator value this filter applies to (e.g. `'image'`). */
242
+ key: string;
243
+ /** SQL column expression on the variant alias (e.g. `__v_image.width`). */
244
+ qualifiedColumn: string;
245
+ /** SQL comparison operator (validated). */
246
+ op: string;
247
+ value: any;
248
+ }
249
+ /** @internal Relation metadata stored via `.hasMany()`, `.belongsTo()`, etc. */
250
+ export interface RelationSpec {
251
+ type: 'hasMany' | 'hasOne' | 'belongsTo' | 'belongsToMany';
252
+ name: string;
253
+ schema: any;
254
+ foreignKey?: any;
255
+ through?: {
256
+ table: string;
257
+ localKey: string;
258
+ foreignKey: string;
259
+ };
260
+ }
261
+ /** Column information read from the database. */
262
+ export interface DatabaseColumnInfo {
263
+ name: string;
264
+ type: string;
265
+ nullable: boolean;
266
+ defaultValue: string | null;
267
+ maxLength: number | null;
268
+ numericPrecision: number | null;
269
+ }
270
+ /** Index information read from the database. */
271
+ export interface DatabaseIndexInfo {
272
+ name: string;
273
+ columns: string[];
274
+ unique: boolean;
275
+ definition: string;
276
+ }
277
+ /** Foreign key information read from the database. */
278
+ export interface DatabaseForeignKeyInfo {
279
+ constraintName: string;
280
+ columnName: string;
281
+ foreignTable: string;
282
+ foreignColumn: string;
283
+ deleteRule: string;
284
+ updateRule: string;
285
+ }
286
+ /** Check constraint information read from the database. */
287
+ export interface DatabaseCheckInfo {
288
+ name: string;
289
+ definition: string;
290
+ }
291
+ /** Full database table state from introspection. */
292
+ export interface DatabaseTableState {
293
+ columns: Record<string, DatabaseColumnInfo>;
294
+ indexes: DatabaseIndexInfo[];
295
+ foreignKeys: DatabaseForeignKeyInfo[];
296
+ checks: DatabaseCheckInfo[];
297
+ }
298
+ /**
299
+ * Serialized snapshot of all entity schemas at a given point in time.
300
+ *
301
+ * Stored in `<migrations.directory>/snapshot.json` and committed to version
302
+ * control. `migrate generate` diffs the current code against this snapshot
303
+ * (instead of a live database) to produce migration files, so no DB
304
+ * connection is required.
305
+ *
306
+ * Each entry in `tables` mirrors the shape that `introspectDatabase` would
307
+ * return — allowing `diffSchema` to be reused unchanged.
308
+ *
309
+ * @public
310
+ */
311
+ export interface SchemaSnapshot {
312
+ version: 1;
313
+ /** Map of table name → database state derived from entity schemas. */
314
+ tables: Record<string, DatabaseTableState>;
315
+ }
316
+ /** A column to add in a migration. */
317
+ export interface AddColumnDiff {
318
+ name: string;
319
+ type: string;
320
+ nullable: boolean;
321
+ defaultValue?: any;
322
+ references?: {
323
+ table: string;
324
+ column: string;
325
+ };
326
+ onDelete?: string;
327
+ onUpdate?: string;
328
+ }
329
+ /** Changes to apply to an existing column. */
330
+ export interface AlterColumnDiff {
331
+ name: string;
332
+ changes: Record<string, {
333
+ from: any;
334
+ to: any;
335
+ }>;
336
+ }
337
+ /** An index to add in a migration. */
338
+ export interface AddIndexDiff {
339
+ columns: string[];
340
+ name?: string;
341
+ unique?: boolean;
342
+ }
343
+ /** A foreign key to add in a migration. */
344
+ export interface AddForeignKeyDiff {
345
+ column: string;
346
+ foreignTable: string;
347
+ foreignColumn: string;
348
+ onDelete?: string;
349
+ onUpdate?: string;
350
+ }
351
+ /** Schema diff result between the code-first model and the live database. */
352
+ export interface MigrationDiff {
353
+ addColumns: AddColumnDiff[];
354
+ dropColumns: string[];
355
+ alterColumns: AlterColumnDiff[];
356
+ addIndexes: AddIndexDiff[];
357
+ dropIndexes: string[];
358
+ addForeignKeys: AddForeignKeyDiff[];
359
+ dropForeignKeys: string[];
360
+ }
92
361
  export {};
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "email": "andrew_zol@cleverbrush.com"
6
6
  },
7
7
  "dependencies": {
8
- "@cleverbrush/schema": "^3.1.0"
8
+ "@cleverbrush/schema": "^4.1.0"
9
9
  },
10
10
  "peerDependencies": {
11
11
  "knex": ">=3.1.0"
@@ -32,6 +32,10 @@
32
32
  ".": {
33
33
  "types": "./dist/index.d.ts",
34
34
  "import": "./dist/index.js"
35
+ },
36
+ "./extension": {
37
+ "types": "./dist/extension.d.ts",
38
+ "import": "./dist/extension.js"
35
39
  }
36
40
  },
37
41
  "sideEffects": false,
@@ -48,5 +52,5 @@
48
52
  },
49
53
  "type": "module",
50
54
  "types": "./dist/index.d.ts",
51
- "version": "3.1.0"
55
+ "version": "4.1.0"
52
56
  }