@querykitjs/prisma-pg 1.0.0 → 2.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.
- package/README.en.md +171 -11
- package/README.md +171 -11
- package/dist/index.cjs +1 -843
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +160 -57
- package/dist/index.d.ts +160 -57
- package/dist/index.js +1 -836
- package/dist/index.js.map +1 -1
- package/package.json +21 -9
- package/skills/querykit-prisma-pg/SKILL.md +185 -0
package/dist/index.d.cts
CHANGED
|
@@ -1,53 +1,16 @@
|
|
|
1
|
-
import { Types } from '@prisma/client/runtime/library';
|
|
2
1
|
import * as _querykitjs_core from '@querykitjs/core';
|
|
3
|
-
import { SkippedCondition } from '@querykitjs/core';
|
|
2
|
+
import { AllRows, MutationCount, MutationRows, Relations, SkippedCondition, QueryLimits } from '@querykitjs/core';
|
|
4
3
|
export { f } from '@querykitjs/core';
|
|
4
|
+
import { Types } from '@prisma/client/runtime/client';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Prisma's `where` is keyed by **model field name** (camelCase), never by the DB
|
|
11
|
-
* column — but a client may well send `created_at`, which drizzle-pg accepts. So
|
|
12
|
-
* each field's `@map`ped column is recorded as an alias and `resolveField`
|
|
13
|
-
* translates it back, keeping the two Postgres adapters interchangeable.
|
|
14
|
-
*
|
|
15
|
-
* Getting the field list without importing the generated client is the other
|
|
16
|
-
* half of the job: this package must typecheck with no generated client present,
|
|
17
|
-
* so metadata is read off the client **instance** at runtime, through a fallback
|
|
18
|
-
* chain.
|
|
7
|
+
* Prisma type utilities the public types are built from. Not re-exported by
|
|
8
|
+
* `types/index.ts`: they are implementation helpers, not part of the API.
|
|
19
9
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
type: string;
|
|
25
|
-
kind: "scalar" | "enum" | "object" | "unsupported";
|
|
26
|
-
isId: boolean;
|
|
27
|
-
/** `@updatedAt` — Prisma bumps these itself, so the adapter must not. */
|
|
28
|
-
isUpdatedAt: boolean;
|
|
29
|
-
isList: boolean;
|
|
30
|
-
/** The `@map`ped database column, when it differs from the field name. */
|
|
31
|
-
dbName?: string;
|
|
32
|
-
}
|
|
33
|
-
/** Everything the repository needs to know about one model. */
|
|
34
|
-
interface ModelMeta {
|
|
35
|
-
/** Prisma model name (`"User"`) — used as the diagnostics `source`. */
|
|
36
|
-
name: string;
|
|
37
|
-
fields: Map<string, FieldMeta>;
|
|
38
|
-
/** `@map`ped DB column → Prisma field name, so `created_at` also resolves. */
|
|
39
|
-
byDbName: Map<string, string>;
|
|
40
|
-
/** The `@id` field name; undefined for a composite `@@id`. */
|
|
41
|
-
idField: string | undefined;
|
|
42
|
-
/** Fields that uniquely address a row — one `@id`, or every `@@id` field. */
|
|
43
|
-
primaryKey: string[];
|
|
44
|
-
/** Prisma's name for a composite key (`@@id(name:)`), else the joined fields. */
|
|
45
|
-
primaryKeyName: string | undefined;
|
|
46
|
-
hasDeletedAt: boolean;
|
|
47
|
-
/** Present only when the field exists **and** is not `@updatedAt`-managed. */
|
|
48
|
-
stampUpdatedAt: string | undefined;
|
|
49
|
-
hasCreatedAt: boolean;
|
|
50
|
-
}
|
|
10
|
+
|
|
11
|
+
type ArgsOf<TDelegate, TOperation extends Types.Public.Operation> = Types.Public.Args<TDelegate, TOperation>;
|
|
12
|
+
/** One row with the given Prisma args applied (`select` / `include`). */
|
|
13
|
+
type RowWith<TDelegate, TArgs> = Types.Public.Result<TDelegate, TArgs, "findFirstOrThrow">;
|
|
51
14
|
|
|
52
15
|
/**
|
|
53
16
|
* QueryKit Prisma adapter — public types. The DSL/filter/meta types come from
|
|
@@ -60,8 +23,9 @@ interface ModelMeta {
|
|
|
60
23
|
* names, same semantics, one shared source in core.
|
|
61
24
|
*
|
|
62
25
|
* ⚠️ This file must never import from `@prisma/client` itself — only from
|
|
63
|
-
* `@prisma/client/runtime/
|
|
64
|
-
* generated
|
|
26
|
+
* `@prisma/client/runtime/client`, which exists whether or not a client has been
|
|
27
|
+
* generated (Prisma 6.19 and 7 both ship it; 7 has no `runtime/library`). That
|
|
28
|
+
* is what lets the package typecheck and build in CI with no
|
|
65
29
|
* `prisma generate` step, while still inferring exact row types in a consumer's
|
|
66
30
|
* project. `Types.Public.*` are Prisma's own public type utilities; the generated
|
|
67
31
|
* client re-exports the very same ones as `Prisma.Result` / `Prisma.Args`.
|
|
@@ -84,9 +48,6 @@ type ModelKey<TClient> = {
|
|
|
84
48
|
}[keyof TClient & string];
|
|
85
49
|
/** The delegate behind a model key. */
|
|
86
50
|
type DelegateOf<TClient, TKey extends ModelKey<TClient>> = TClient[TKey];
|
|
87
|
-
type ArgsOf<TDelegate, TOperation extends Types.Public.Operation> = Types.Public.Args<TDelegate, TOperation>;
|
|
88
|
-
/** One row with the given Prisma args applied (`select` / `include`). */
|
|
89
|
-
type RowWith<TDelegate, TArgs> = Types.Public.Result<TDelegate, TArgs, "findFirstOrThrow">;
|
|
90
51
|
/** Full row shape of a model (what reads return with no `columns`/`with`). */
|
|
91
52
|
type Row<TDelegate> = RowWith<TDelegate, Record<string, never>>;
|
|
92
53
|
/** Insertable shape — the model's `create` data. */
|
|
@@ -160,10 +121,13 @@ type UpsertOptions<TDelegate = AnyDelegate> = _querykitjs_core.UpsertOptions<Fie
|
|
|
160
121
|
type AggregateSpec<TDelegate = AnyDelegate> = _querykitjs_core.AggregateSpec<FieldKey<TDelegate>, Filter<TDelegate>>;
|
|
161
122
|
/** One aggregated result row (group fields + aggregate values). */
|
|
162
123
|
type AggregateRow = Record<string, unknown>;
|
|
124
|
+
|
|
163
125
|
/** Offset (classic page-based) pagination. */
|
|
164
126
|
interface OffsetParams<TDelegate = AnyDelegate> extends QueryParams<TDelegate> {
|
|
165
127
|
page?: number;
|
|
166
128
|
perPage?: number;
|
|
129
|
+
/** `false` — no count query: `perPage + 1` rows are read, `total_items` / `total_pages` are `null` (task 013). Default `true`. */
|
|
130
|
+
withTotal?: boolean;
|
|
167
131
|
}
|
|
168
132
|
type OffsetMeta = _querykitjs_core.OffsetMeta;
|
|
169
133
|
interface OffsetResult<T> {
|
|
@@ -197,6 +161,7 @@ interface CursorResult<T> {
|
|
|
197
161
|
data: T[];
|
|
198
162
|
meta: CursorMeta;
|
|
199
163
|
}
|
|
164
|
+
|
|
200
165
|
type TrueKeys<T> = {
|
|
201
166
|
[K in keyof T]: T[K] extends true ? K : never;
|
|
202
167
|
}[keyof T];
|
|
@@ -273,12 +238,32 @@ interface Repository<TDelegate = AnyDelegate> {
|
|
|
273
238
|
upsertMany(values: Insert<TDelegate>[], options: UpsertOptions<TDelegate>): Promise<Row<TDelegate>[]>;
|
|
274
239
|
/** Update one row by id; returns the updated row (or `undefined`). */
|
|
275
240
|
updateById(id: Id, patch: Partial<Insert<TDelegate>>, idKey?: FieldKey<TDelegate>): Promise<Row<TDelegate> | undefined>;
|
|
276
|
-
/**
|
|
277
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Update every row matching the filter in one atomic `updateMany` → `{ count }` (task 013).
|
|
243
|
+
* No filter only with `{ all: true }` (the scope still applies); an empty or fully skipped
|
|
244
|
+
* filter is `QueryKitError` `empty-filter`. The filter passes the request policy like a read.
|
|
245
|
+
*/
|
|
246
|
+
updateWhere(filter: Filter<TDelegate> | AllRows, patch: Partial<Insert<TDelegate>>, options?: {
|
|
247
|
+
returning?: false;
|
|
248
|
+
}): Promise<MutationCount>;
|
|
249
|
+
/** With `returning: { limit }`: `{ count, rows }` from one atomic `updateManyAndReturn`, at most `limit` rows. */
|
|
250
|
+
updateWhere(filter: Filter<TDelegate> | AllRows, patch: Partial<Insert<TDelegate>>, options: {
|
|
251
|
+
returning: {
|
|
252
|
+
limit: number;
|
|
253
|
+
};
|
|
254
|
+
}): Promise<MutationRows<Row<TDelegate>>>;
|
|
278
255
|
/** Hard-delete one row by id; returns the deleted row (or `undefined`). */
|
|
279
256
|
deleteById(id: Id, idKey?: FieldKey<TDelegate>): Promise<Row<TDelegate> | undefined>;
|
|
280
|
-
/** Hard-delete every row matching the filter
|
|
281
|
-
deleteWhere(filter: Filter<TDelegate>
|
|
257
|
+
/** Hard-delete every row matching the filter in one `deleteMany` → `{ count }` (same rules as `updateWhere`). */
|
|
258
|
+
deleteWhere(filter: Filter<TDelegate> | AllRows, options?: {
|
|
259
|
+
returning?: false;
|
|
260
|
+
}): Promise<MutationCount>;
|
|
261
|
+
/** With `returning: { limit }`: `{ count, rows }` — the rows are read just before the delete (not atomic). */
|
|
262
|
+
deleteWhere(filter: Filter<TDelegate> | AllRows, options: {
|
|
263
|
+
returning: {
|
|
264
|
+
limit: number;
|
|
265
|
+
};
|
|
266
|
+
}): Promise<MutationRows<Row<TDelegate>>>;
|
|
282
267
|
/** Soft-delete (set `deletedAt`); requires a `deletedAt` field. */
|
|
283
268
|
softDelete(id: Id, idKey?: FieldKey<TDelegate>): Promise<Row<TDelegate> | undefined>;
|
|
284
269
|
/** Restore a soft-deleted row (`deletedAt = null`). */
|
|
@@ -293,6 +278,69 @@ interface Repository<TDelegate = AnyDelegate> {
|
|
|
293
278
|
}
|
|
294
279
|
/** Extends a base repository with custom, model-specific methods. */
|
|
295
280
|
type RepositoryExtender<TDelegate, TExt extends Record<string, unknown>> = (base: Repository<TDelegate>) => TExt;
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Model metadata — the Prisma counterpart of drizzle's `columns.ts` and
|
|
284
|
+
* mongoose's `fields.ts`.
|
|
285
|
+
*
|
|
286
|
+
* Prisma's `where` is keyed by **model field name** (camelCase), never by the DB
|
|
287
|
+
* column — but a client may well send `created_at`, which drizzle-pg accepts. So
|
|
288
|
+
* each field's `@map`ped column is recorded as an alias and `resolveField`
|
|
289
|
+
* translates it back, keeping the two Postgres adapters interchangeable.
|
|
290
|
+
*
|
|
291
|
+
* Getting the field list without importing the generated client is the other
|
|
292
|
+
* half of the job: this package must typecheck with no generated client present,
|
|
293
|
+
* so metadata is read off the client **instance** at runtime, through a fallback
|
|
294
|
+
* chain.
|
|
295
|
+
*/
|
|
296
|
+
/** One model field, normalized across every metadata source. */
|
|
297
|
+
interface FieldMeta {
|
|
298
|
+
name: string;
|
|
299
|
+
/** Prisma type name: `"Int"`, `"String"`, `"DateTime"`, an enum or model name, … */
|
|
300
|
+
type: string;
|
|
301
|
+
kind: "scalar" | "enum" | "object" | "unsupported";
|
|
302
|
+
isId: boolean;
|
|
303
|
+
/** `@updatedAt` — Prisma bumps these itself, so the adapter must not. */
|
|
304
|
+
isUpdatedAt: boolean;
|
|
305
|
+
isList: boolean;
|
|
306
|
+
/** The `@map`ped database column, when it differs from the field name. */
|
|
307
|
+
dbName?: string;
|
|
308
|
+
/** `false` for an optional (nullable) field — Prisma accepts `nulls` in `orderBy` only there (task 021 B11). */
|
|
309
|
+
isRequired?: boolean;
|
|
310
|
+
/** The database type (`"Uuid"` for `@db.Uuid`) — from the runtime model when it has one, or the `fields` override (task 021 B8). */
|
|
311
|
+
nativeType?: string;
|
|
312
|
+
/** An enum field's values (from the runtime data model), for the task 021 B8 cast. */
|
|
313
|
+
enumValues?: readonly string[];
|
|
314
|
+
}
|
|
315
|
+
/** Everything the repository needs to know about one model. */
|
|
316
|
+
interface ModelMeta {
|
|
317
|
+
/** Prisma model name (`"User"`) — used as the diagnostics `source`. */
|
|
318
|
+
name: string;
|
|
319
|
+
fields: Map<string, FieldMeta>;
|
|
320
|
+
/** `@map`ped DB column → Prisma field name, so `created_at` also resolves. */
|
|
321
|
+
byDbName: Map<string, string>;
|
|
322
|
+
/** The `@id` field name; undefined for a composite `@@id`. */
|
|
323
|
+
idField: string | undefined;
|
|
324
|
+
/** Fields that uniquely address a row — one `@id`, or every `@@id` field. */
|
|
325
|
+
primaryKey: string[];
|
|
326
|
+
/** Prisma's name for a composite key (`@@id(name:)`), else the joined fields. */
|
|
327
|
+
primaryKeyName: string | undefined;
|
|
328
|
+
hasDeletedAt: boolean;
|
|
329
|
+
/** Present only when the field exists **and** is not `@updatedAt`-managed. */
|
|
330
|
+
stampUpdatedAt: string | undefined;
|
|
331
|
+
hasCreatedAt: boolean;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Read a model's metadata off a live Prisma client, trying, in order:
|
|
335
|
+
* `_runtimeDataModel` → `delegate.fields` → the caller-supplied `override`.
|
|
336
|
+
*
|
|
337
|
+
* Throws when none of them work — the same reasoning as drizzle's "table not in
|
|
338
|
+
* schema" error: a repository built on unknown metadata would silently skip
|
|
339
|
+
* *every* filter key and return the whole table.
|
|
340
|
+
*/
|
|
341
|
+
/** A `fields` override entry: a full field, or a patch of a discovered one by `name` (e.g. `{ name: "age", isRequired: false }`). */
|
|
342
|
+
type FieldOverride = Pick<FieldMeta, "name"> & Partial<FieldMeta>;
|
|
343
|
+
|
|
296
344
|
/** {@link createRegistry} options — pagination defaults and bounds. */
|
|
297
345
|
interface RegistryOptions {
|
|
298
346
|
/** `findList` default page size (core `DEFAULT_PER_PAGE` = 20). */
|
|
@@ -321,6 +369,27 @@ interface RegistryOptions {
|
|
|
321
369
|
* path: watch with the hook first, flip `strict: true` once the log is clean.
|
|
322
370
|
*/
|
|
323
371
|
onSkippedCondition?: (info: _querykitjs_core.SkippedCondition) => void;
|
|
372
|
+
/**
|
|
373
|
+
* Server-side request limits (core `DEFAULT_QUERY_LIMITS`: depth 5, conditions 30,
|
|
374
|
+
* array 200, string 256, offset 10 000, sort 3) — enforced even when validation was
|
|
375
|
+
* bypassed. Past one ⇒ `QueryKitError` (`reason: "limit-exceeded"`). A repository's
|
|
376
|
+
* own `limits` win.
|
|
377
|
+
*/
|
|
378
|
+
limits?: Partial<_querykitjs_core.QueryLimits>;
|
|
379
|
+
/**
|
|
380
|
+
* Signs cursor tokens (HMAC-SHA256, task 012). With it a token that was not
|
|
381
|
+
* issued by this server — or was changed — is `invalid-value`. Without it tokens
|
|
382
|
+
* are unsigned but still checked (scalar values, v2 shape).
|
|
383
|
+
*/
|
|
384
|
+
cursorSecret?: string;
|
|
385
|
+
/**
|
|
386
|
+
* The createdAt / deletedAt field names (task 014; default `createdAt`, `deletedAt`): the default
|
|
387
|
+
* sort and the default `sortable` use `createdAt`, soft delete uses `deletedAt`.
|
|
388
|
+
*/
|
|
389
|
+
timestamps?: {
|
|
390
|
+
createdAt?: string;
|
|
391
|
+
deletedAt?: string;
|
|
392
|
+
};
|
|
324
393
|
}
|
|
325
394
|
/**
|
|
326
395
|
* Options for `registry.repository(model, options)`.
|
|
@@ -336,6 +405,12 @@ interface RegistryOptions {
|
|
|
336
405
|
* yourself, before handing a write result to a client.
|
|
337
406
|
*/
|
|
338
407
|
interface RepositoryOptions<TDelegate = AnyDelegate> {
|
|
408
|
+
/**
|
|
409
|
+
* Relations a client may open with `with` (task 014, R21): relation → `{ columns, filterable?, nested? }`.
|
|
410
|
+
* `columns` is required (a list or `"*"`); an unlisted relation, column, `where` field or nested
|
|
411
|
+
* `include` is `QueryKitError` `forbidden-key`, `site: "with"`. Without it `with` opens nothing.
|
|
412
|
+
*/
|
|
413
|
+
relations?: Relations;
|
|
339
414
|
/** Constant equality filter added to every read/write (RBAC / multi-tenancy). */
|
|
340
415
|
scope?: Scope<TDelegate>;
|
|
341
416
|
/**
|
|
@@ -355,7 +430,24 @@ interface RepositoryOptions<TDelegate = AnyDelegate> {
|
|
|
355
430
|
* the Prisma client itself (it tries `_runtimeDataModel`, then the public
|
|
356
431
|
* `delegate.fields`) — e.g. behind an unusual client wrapper.
|
|
357
432
|
*/
|
|
358
|
-
fields?: readonly
|
|
433
|
+
fields?: readonly FieldOverride[];
|
|
434
|
+
/**
|
|
435
|
+
* Fields a client may filter by, and the operators for each (`"*"` — all). A
|
|
436
|
+
* relation field is `"relation.field"` (`"posts.title": ["="]`). A field not
|
|
437
|
+
* listed ⇒ `reason: "forbidden-key"`, an operator not listed ⇒ `"forbidden-operator"`
|
|
438
|
+
* — a `QueryKitError` whatever `strict` says, before Prisma is called.
|
|
439
|
+
* **When not given** — `allowedColumns` (else the `forcedColumns` keys, else only
|
|
440
|
+
* the `@id` field) with `"="` and `"in"` only. `aggregate` fields come from this list too.
|
|
441
|
+
*/
|
|
442
|
+
filterable?: _querykitjs_core.Filterable<FieldKey<TDelegate> | `${string}.${string}`>;
|
|
443
|
+
/**
|
|
444
|
+
* Fields a client may sort (and use as `cursorKey`) by. When not given — the
|
|
445
|
+
* `@id` field and `createdAt` (when the model has it). Anything else ⇒
|
|
446
|
+
* `reason: "forbidden-key"`.
|
|
447
|
+
*/
|
|
448
|
+
sortable?: readonly FieldKey<TDelegate>[];
|
|
449
|
+
/** Request limits for this repository — over the registry's `limits`. */
|
|
450
|
+
limits?: Partial<_querykitjs_core.QueryLimits>;
|
|
359
451
|
}
|
|
360
452
|
/** DB registry: created once, yields model repositories. */
|
|
361
453
|
interface Registry<TClient extends AnyClient = AnyClient> {
|
|
@@ -447,10 +539,20 @@ interface RepoRuntime {
|
|
|
447
539
|
strict: boolean;
|
|
448
540
|
/** Called for every dropped condition (also when `strict` is off). */
|
|
449
541
|
onSkippedCondition?: (info: SkippedCondition) => void;
|
|
542
|
+
/** Registry-level request limits; a repository's own `limits` win. */
|
|
543
|
+
limits?: Partial<QueryLimits>;
|
|
544
|
+
/** Signs cursor tokens (task 012). */
|
|
545
|
+
cursorSecret?: string;
|
|
546
|
+
/** createdAt / deletedAt field names (task 014); default `createdAt`, `deletedAt`. */
|
|
547
|
+
timestamps?: {
|
|
548
|
+
createdAt?: string;
|
|
549
|
+
deletedAt?: string;
|
|
550
|
+
};
|
|
450
551
|
}
|
|
552
|
+
|
|
451
553
|
/**
|
|
452
554
|
* Build a model-scoped repository. `runtime` (client + ambient transaction
|
|
453
|
-
* context) comes from the registry, so this
|
|
555
|
+
* context) comes from the registry, so this module never touches the app's
|
|
454
556
|
* database handle directly.
|
|
455
557
|
*/
|
|
456
558
|
declare function buildRepository<TDelegate>(runtime: RepoRuntime, modelKey: string, config?: RepositoryOptions<TDelegate>): Repository<TDelegate>;
|
|
@@ -491,4 +593,5 @@ declare function createFilters<TDelegate>(): {
|
|
|
491
593
|
not: (node: _querykitjs_core.FilterNode<FieldKey<TDelegate>, RawWhere<TDelegate>>) => _querykitjs_core.NotGroup<FieldKey<TDelegate>, RawWhere<TDelegate>>;
|
|
492
594
|
};
|
|
493
595
|
|
|
494
|
-
export {
|
|
596
|
+
export { buildRepository, createFilters, createRegistry };
|
|
597
|
+
export type { AggregateRow, AggregateSpec, AndGroup, AnyClient, AnyDelegate, ByIdParams, ColumnSelection, CursorMeta, CursorParams, CursorResult, DelegateOf, FieldCondition, FieldKey, FieldMeta, Filter, FilterNode, FilterOperator, FilterScalar, FilterValue, Id, IncludeInput, InfiniteMeta, InfiniteParams, InfiniteResult, Insert, LooseFieldKey, ModelKey, ModelMeta, NotGroup, OffsetMeta, OffsetParams, OffsetResult, OrGroup, QueryParams, RawWhere, Registry, RegistryOptions, RepoRuntime, Repository, RepositoryExtender, RepositoryOptions, ResultFor, Row, Scope, SelectInput, Sort, SortDirection, SortItem, UpsertOptions, WithRelations };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,53 +1,16 @@
|
|
|
1
|
-
import { Types } from '@prisma/client/runtime/library';
|
|
2
1
|
import * as _querykitjs_core from '@querykitjs/core';
|
|
3
|
-
import { SkippedCondition } from '@querykitjs/core';
|
|
2
|
+
import { AllRows, MutationCount, MutationRows, Relations, SkippedCondition, QueryLimits } from '@querykitjs/core';
|
|
4
3
|
export { f } from '@querykitjs/core';
|
|
4
|
+
import { Types } from '@prisma/client/runtime/client';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Prisma's `where` is keyed by **model field name** (camelCase), never by the DB
|
|
11
|
-
* column — but a client may well send `created_at`, which drizzle-pg accepts. So
|
|
12
|
-
* each field's `@map`ped column is recorded as an alias and `resolveField`
|
|
13
|
-
* translates it back, keeping the two Postgres adapters interchangeable.
|
|
14
|
-
*
|
|
15
|
-
* Getting the field list without importing the generated client is the other
|
|
16
|
-
* half of the job: this package must typecheck with no generated client present,
|
|
17
|
-
* so metadata is read off the client **instance** at runtime, through a fallback
|
|
18
|
-
* chain.
|
|
7
|
+
* Prisma type utilities the public types are built from. Not re-exported by
|
|
8
|
+
* `types/index.ts`: they are implementation helpers, not part of the API.
|
|
19
9
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
type: string;
|
|
25
|
-
kind: "scalar" | "enum" | "object" | "unsupported";
|
|
26
|
-
isId: boolean;
|
|
27
|
-
/** `@updatedAt` — Prisma bumps these itself, so the adapter must not. */
|
|
28
|
-
isUpdatedAt: boolean;
|
|
29
|
-
isList: boolean;
|
|
30
|
-
/** The `@map`ped database column, when it differs from the field name. */
|
|
31
|
-
dbName?: string;
|
|
32
|
-
}
|
|
33
|
-
/** Everything the repository needs to know about one model. */
|
|
34
|
-
interface ModelMeta {
|
|
35
|
-
/** Prisma model name (`"User"`) — used as the diagnostics `source`. */
|
|
36
|
-
name: string;
|
|
37
|
-
fields: Map<string, FieldMeta>;
|
|
38
|
-
/** `@map`ped DB column → Prisma field name, so `created_at` also resolves. */
|
|
39
|
-
byDbName: Map<string, string>;
|
|
40
|
-
/** The `@id` field name; undefined for a composite `@@id`. */
|
|
41
|
-
idField: string | undefined;
|
|
42
|
-
/** Fields that uniquely address a row — one `@id`, or every `@@id` field. */
|
|
43
|
-
primaryKey: string[];
|
|
44
|
-
/** Prisma's name for a composite key (`@@id(name:)`), else the joined fields. */
|
|
45
|
-
primaryKeyName: string | undefined;
|
|
46
|
-
hasDeletedAt: boolean;
|
|
47
|
-
/** Present only when the field exists **and** is not `@updatedAt`-managed. */
|
|
48
|
-
stampUpdatedAt: string | undefined;
|
|
49
|
-
hasCreatedAt: boolean;
|
|
50
|
-
}
|
|
10
|
+
|
|
11
|
+
type ArgsOf<TDelegate, TOperation extends Types.Public.Operation> = Types.Public.Args<TDelegate, TOperation>;
|
|
12
|
+
/** One row with the given Prisma args applied (`select` / `include`). */
|
|
13
|
+
type RowWith<TDelegate, TArgs> = Types.Public.Result<TDelegate, TArgs, "findFirstOrThrow">;
|
|
51
14
|
|
|
52
15
|
/**
|
|
53
16
|
* QueryKit Prisma adapter — public types. The DSL/filter/meta types come from
|
|
@@ -60,8 +23,9 @@ interface ModelMeta {
|
|
|
60
23
|
* names, same semantics, one shared source in core.
|
|
61
24
|
*
|
|
62
25
|
* ⚠️ This file must never import from `@prisma/client` itself — only from
|
|
63
|
-
* `@prisma/client/runtime/
|
|
64
|
-
* generated
|
|
26
|
+
* `@prisma/client/runtime/client`, which exists whether or not a client has been
|
|
27
|
+
* generated (Prisma 6.19 and 7 both ship it; 7 has no `runtime/library`). That
|
|
28
|
+
* is what lets the package typecheck and build in CI with no
|
|
65
29
|
* `prisma generate` step, while still inferring exact row types in a consumer's
|
|
66
30
|
* project. `Types.Public.*` are Prisma's own public type utilities; the generated
|
|
67
31
|
* client re-exports the very same ones as `Prisma.Result` / `Prisma.Args`.
|
|
@@ -84,9 +48,6 @@ type ModelKey<TClient> = {
|
|
|
84
48
|
}[keyof TClient & string];
|
|
85
49
|
/** The delegate behind a model key. */
|
|
86
50
|
type DelegateOf<TClient, TKey extends ModelKey<TClient>> = TClient[TKey];
|
|
87
|
-
type ArgsOf<TDelegate, TOperation extends Types.Public.Operation> = Types.Public.Args<TDelegate, TOperation>;
|
|
88
|
-
/** One row with the given Prisma args applied (`select` / `include`). */
|
|
89
|
-
type RowWith<TDelegate, TArgs> = Types.Public.Result<TDelegate, TArgs, "findFirstOrThrow">;
|
|
90
51
|
/** Full row shape of a model (what reads return with no `columns`/`with`). */
|
|
91
52
|
type Row<TDelegate> = RowWith<TDelegate, Record<string, never>>;
|
|
92
53
|
/** Insertable shape — the model's `create` data. */
|
|
@@ -160,10 +121,13 @@ type UpsertOptions<TDelegate = AnyDelegate> = _querykitjs_core.UpsertOptions<Fie
|
|
|
160
121
|
type AggregateSpec<TDelegate = AnyDelegate> = _querykitjs_core.AggregateSpec<FieldKey<TDelegate>, Filter<TDelegate>>;
|
|
161
122
|
/** One aggregated result row (group fields + aggregate values). */
|
|
162
123
|
type AggregateRow = Record<string, unknown>;
|
|
124
|
+
|
|
163
125
|
/** Offset (classic page-based) pagination. */
|
|
164
126
|
interface OffsetParams<TDelegate = AnyDelegate> extends QueryParams<TDelegate> {
|
|
165
127
|
page?: number;
|
|
166
128
|
perPage?: number;
|
|
129
|
+
/** `false` — no count query: `perPage + 1` rows are read, `total_items` / `total_pages` are `null` (task 013). Default `true`. */
|
|
130
|
+
withTotal?: boolean;
|
|
167
131
|
}
|
|
168
132
|
type OffsetMeta = _querykitjs_core.OffsetMeta;
|
|
169
133
|
interface OffsetResult<T> {
|
|
@@ -197,6 +161,7 @@ interface CursorResult<T> {
|
|
|
197
161
|
data: T[];
|
|
198
162
|
meta: CursorMeta;
|
|
199
163
|
}
|
|
164
|
+
|
|
200
165
|
type TrueKeys<T> = {
|
|
201
166
|
[K in keyof T]: T[K] extends true ? K : never;
|
|
202
167
|
}[keyof T];
|
|
@@ -273,12 +238,32 @@ interface Repository<TDelegate = AnyDelegate> {
|
|
|
273
238
|
upsertMany(values: Insert<TDelegate>[], options: UpsertOptions<TDelegate>): Promise<Row<TDelegate>[]>;
|
|
274
239
|
/** Update one row by id; returns the updated row (or `undefined`). */
|
|
275
240
|
updateById(id: Id, patch: Partial<Insert<TDelegate>>, idKey?: FieldKey<TDelegate>): Promise<Row<TDelegate> | undefined>;
|
|
276
|
-
/**
|
|
277
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Update every row matching the filter in one atomic `updateMany` → `{ count }` (task 013).
|
|
243
|
+
* No filter only with `{ all: true }` (the scope still applies); an empty or fully skipped
|
|
244
|
+
* filter is `QueryKitError` `empty-filter`. The filter passes the request policy like a read.
|
|
245
|
+
*/
|
|
246
|
+
updateWhere(filter: Filter<TDelegate> | AllRows, patch: Partial<Insert<TDelegate>>, options?: {
|
|
247
|
+
returning?: false;
|
|
248
|
+
}): Promise<MutationCount>;
|
|
249
|
+
/** With `returning: { limit }`: `{ count, rows }` from one atomic `updateManyAndReturn`, at most `limit` rows. */
|
|
250
|
+
updateWhere(filter: Filter<TDelegate> | AllRows, patch: Partial<Insert<TDelegate>>, options: {
|
|
251
|
+
returning: {
|
|
252
|
+
limit: number;
|
|
253
|
+
};
|
|
254
|
+
}): Promise<MutationRows<Row<TDelegate>>>;
|
|
278
255
|
/** Hard-delete one row by id; returns the deleted row (or `undefined`). */
|
|
279
256
|
deleteById(id: Id, idKey?: FieldKey<TDelegate>): Promise<Row<TDelegate> | undefined>;
|
|
280
|
-
/** Hard-delete every row matching the filter
|
|
281
|
-
deleteWhere(filter: Filter<TDelegate>
|
|
257
|
+
/** Hard-delete every row matching the filter in one `deleteMany` → `{ count }` (same rules as `updateWhere`). */
|
|
258
|
+
deleteWhere(filter: Filter<TDelegate> | AllRows, options?: {
|
|
259
|
+
returning?: false;
|
|
260
|
+
}): Promise<MutationCount>;
|
|
261
|
+
/** With `returning: { limit }`: `{ count, rows }` — the rows are read just before the delete (not atomic). */
|
|
262
|
+
deleteWhere(filter: Filter<TDelegate> | AllRows, options: {
|
|
263
|
+
returning: {
|
|
264
|
+
limit: number;
|
|
265
|
+
};
|
|
266
|
+
}): Promise<MutationRows<Row<TDelegate>>>;
|
|
282
267
|
/** Soft-delete (set `deletedAt`); requires a `deletedAt` field. */
|
|
283
268
|
softDelete(id: Id, idKey?: FieldKey<TDelegate>): Promise<Row<TDelegate> | undefined>;
|
|
284
269
|
/** Restore a soft-deleted row (`deletedAt = null`). */
|
|
@@ -293,6 +278,69 @@ interface Repository<TDelegate = AnyDelegate> {
|
|
|
293
278
|
}
|
|
294
279
|
/** Extends a base repository with custom, model-specific methods. */
|
|
295
280
|
type RepositoryExtender<TDelegate, TExt extends Record<string, unknown>> = (base: Repository<TDelegate>) => TExt;
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Model metadata — the Prisma counterpart of drizzle's `columns.ts` and
|
|
284
|
+
* mongoose's `fields.ts`.
|
|
285
|
+
*
|
|
286
|
+
* Prisma's `where` is keyed by **model field name** (camelCase), never by the DB
|
|
287
|
+
* column — but a client may well send `created_at`, which drizzle-pg accepts. So
|
|
288
|
+
* each field's `@map`ped column is recorded as an alias and `resolveField`
|
|
289
|
+
* translates it back, keeping the two Postgres adapters interchangeable.
|
|
290
|
+
*
|
|
291
|
+
* Getting the field list without importing the generated client is the other
|
|
292
|
+
* half of the job: this package must typecheck with no generated client present,
|
|
293
|
+
* so metadata is read off the client **instance** at runtime, through a fallback
|
|
294
|
+
* chain.
|
|
295
|
+
*/
|
|
296
|
+
/** One model field, normalized across every metadata source. */
|
|
297
|
+
interface FieldMeta {
|
|
298
|
+
name: string;
|
|
299
|
+
/** Prisma type name: `"Int"`, `"String"`, `"DateTime"`, an enum or model name, … */
|
|
300
|
+
type: string;
|
|
301
|
+
kind: "scalar" | "enum" | "object" | "unsupported";
|
|
302
|
+
isId: boolean;
|
|
303
|
+
/** `@updatedAt` — Prisma bumps these itself, so the adapter must not. */
|
|
304
|
+
isUpdatedAt: boolean;
|
|
305
|
+
isList: boolean;
|
|
306
|
+
/** The `@map`ped database column, when it differs from the field name. */
|
|
307
|
+
dbName?: string;
|
|
308
|
+
/** `false` for an optional (nullable) field — Prisma accepts `nulls` in `orderBy` only there (task 021 B11). */
|
|
309
|
+
isRequired?: boolean;
|
|
310
|
+
/** The database type (`"Uuid"` for `@db.Uuid`) — from the runtime model when it has one, or the `fields` override (task 021 B8). */
|
|
311
|
+
nativeType?: string;
|
|
312
|
+
/** An enum field's values (from the runtime data model), for the task 021 B8 cast. */
|
|
313
|
+
enumValues?: readonly string[];
|
|
314
|
+
}
|
|
315
|
+
/** Everything the repository needs to know about one model. */
|
|
316
|
+
interface ModelMeta {
|
|
317
|
+
/** Prisma model name (`"User"`) — used as the diagnostics `source`. */
|
|
318
|
+
name: string;
|
|
319
|
+
fields: Map<string, FieldMeta>;
|
|
320
|
+
/** `@map`ped DB column → Prisma field name, so `created_at` also resolves. */
|
|
321
|
+
byDbName: Map<string, string>;
|
|
322
|
+
/** The `@id` field name; undefined for a composite `@@id`. */
|
|
323
|
+
idField: string | undefined;
|
|
324
|
+
/** Fields that uniquely address a row — one `@id`, or every `@@id` field. */
|
|
325
|
+
primaryKey: string[];
|
|
326
|
+
/** Prisma's name for a composite key (`@@id(name:)`), else the joined fields. */
|
|
327
|
+
primaryKeyName: string | undefined;
|
|
328
|
+
hasDeletedAt: boolean;
|
|
329
|
+
/** Present only when the field exists **and** is not `@updatedAt`-managed. */
|
|
330
|
+
stampUpdatedAt: string | undefined;
|
|
331
|
+
hasCreatedAt: boolean;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Read a model's metadata off a live Prisma client, trying, in order:
|
|
335
|
+
* `_runtimeDataModel` → `delegate.fields` → the caller-supplied `override`.
|
|
336
|
+
*
|
|
337
|
+
* Throws when none of them work — the same reasoning as drizzle's "table not in
|
|
338
|
+
* schema" error: a repository built on unknown metadata would silently skip
|
|
339
|
+
* *every* filter key and return the whole table.
|
|
340
|
+
*/
|
|
341
|
+
/** A `fields` override entry: a full field, or a patch of a discovered one by `name` (e.g. `{ name: "age", isRequired: false }`). */
|
|
342
|
+
type FieldOverride = Pick<FieldMeta, "name"> & Partial<FieldMeta>;
|
|
343
|
+
|
|
296
344
|
/** {@link createRegistry} options — pagination defaults and bounds. */
|
|
297
345
|
interface RegistryOptions {
|
|
298
346
|
/** `findList` default page size (core `DEFAULT_PER_PAGE` = 20). */
|
|
@@ -321,6 +369,27 @@ interface RegistryOptions {
|
|
|
321
369
|
* path: watch with the hook first, flip `strict: true` once the log is clean.
|
|
322
370
|
*/
|
|
323
371
|
onSkippedCondition?: (info: _querykitjs_core.SkippedCondition) => void;
|
|
372
|
+
/**
|
|
373
|
+
* Server-side request limits (core `DEFAULT_QUERY_LIMITS`: depth 5, conditions 30,
|
|
374
|
+
* array 200, string 256, offset 10 000, sort 3) — enforced even when validation was
|
|
375
|
+
* bypassed. Past one ⇒ `QueryKitError` (`reason: "limit-exceeded"`). A repository's
|
|
376
|
+
* own `limits` win.
|
|
377
|
+
*/
|
|
378
|
+
limits?: Partial<_querykitjs_core.QueryLimits>;
|
|
379
|
+
/**
|
|
380
|
+
* Signs cursor tokens (HMAC-SHA256, task 012). With it a token that was not
|
|
381
|
+
* issued by this server — or was changed — is `invalid-value`. Without it tokens
|
|
382
|
+
* are unsigned but still checked (scalar values, v2 shape).
|
|
383
|
+
*/
|
|
384
|
+
cursorSecret?: string;
|
|
385
|
+
/**
|
|
386
|
+
* The createdAt / deletedAt field names (task 014; default `createdAt`, `deletedAt`): the default
|
|
387
|
+
* sort and the default `sortable` use `createdAt`, soft delete uses `deletedAt`.
|
|
388
|
+
*/
|
|
389
|
+
timestamps?: {
|
|
390
|
+
createdAt?: string;
|
|
391
|
+
deletedAt?: string;
|
|
392
|
+
};
|
|
324
393
|
}
|
|
325
394
|
/**
|
|
326
395
|
* Options for `registry.repository(model, options)`.
|
|
@@ -336,6 +405,12 @@ interface RegistryOptions {
|
|
|
336
405
|
* yourself, before handing a write result to a client.
|
|
337
406
|
*/
|
|
338
407
|
interface RepositoryOptions<TDelegate = AnyDelegate> {
|
|
408
|
+
/**
|
|
409
|
+
* Relations a client may open with `with` (task 014, R21): relation → `{ columns, filterable?, nested? }`.
|
|
410
|
+
* `columns` is required (a list or `"*"`); an unlisted relation, column, `where` field or nested
|
|
411
|
+
* `include` is `QueryKitError` `forbidden-key`, `site: "with"`. Without it `with` opens nothing.
|
|
412
|
+
*/
|
|
413
|
+
relations?: Relations;
|
|
339
414
|
/** Constant equality filter added to every read/write (RBAC / multi-tenancy). */
|
|
340
415
|
scope?: Scope<TDelegate>;
|
|
341
416
|
/**
|
|
@@ -355,7 +430,24 @@ interface RepositoryOptions<TDelegate = AnyDelegate> {
|
|
|
355
430
|
* the Prisma client itself (it tries `_runtimeDataModel`, then the public
|
|
356
431
|
* `delegate.fields`) — e.g. behind an unusual client wrapper.
|
|
357
432
|
*/
|
|
358
|
-
fields?: readonly
|
|
433
|
+
fields?: readonly FieldOverride[];
|
|
434
|
+
/**
|
|
435
|
+
* Fields a client may filter by, and the operators for each (`"*"` — all). A
|
|
436
|
+
* relation field is `"relation.field"` (`"posts.title": ["="]`). A field not
|
|
437
|
+
* listed ⇒ `reason: "forbidden-key"`, an operator not listed ⇒ `"forbidden-operator"`
|
|
438
|
+
* — a `QueryKitError` whatever `strict` says, before Prisma is called.
|
|
439
|
+
* **When not given** — `allowedColumns` (else the `forcedColumns` keys, else only
|
|
440
|
+
* the `@id` field) with `"="` and `"in"` only. `aggregate` fields come from this list too.
|
|
441
|
+
*/
|
|
442
|
+
filterable?: _querykitjs_core.Filterable<FieldKey<TDelegate> | `${string}.${string}`>;
|
|
443
|
+
/**
|
|
444
|
+
* Fields a client may sort (and use as `cursorKey`) by. When not given — the
|
|
445
|
+
* `@id` field and `createdAt` (when the model has it). Anything else ⇒
|
|
446
|
+
* `reason: "forbidden-key"`.
|
|
447
|
+
*/
|
|
448
|
+
sortable?: readonly FieldKey<TDelegate>[];
|
|
449
|
+
/** Request limits for this repository — over the registry's `limits`. */
|
|
450
|
+
limits?: Partial<_querykitjs_core.QueryLimits>;
|
|
359
451
|
}
|
|
360
452
|
/** DB registry: created once, yields model repositories. */
|
|
361
453
|
interface Registry<TClient extends AnyClient = AnyClient> {
|
|
@@ -447,10 +539,20 @@ interface RepoRuntime {
|
|
|
447
539
|
strict: boolean;
|
|
448
540
|
/** Called for every dropped condition (also when `strict` is off). */
|
|
449
541
|
onSkippedCondition?: (info: SkippedCondition) => void;
|
|
542
|
+
/** Registry-level request limits; a repository's own `limits` win. */
|
|
543
|
+
limits?: Partial<QueryLimits>;
|
|
544
|
+
/** Signs cursor tokens (task 012). */
|
|
545
|
+
cursorSecret?: string;
|
|
546
|
+
/** createdAt / deletedAt field names (task 014); default `createdAt`, `deletedAt`. */
|
|
547
|
+
timestamps?: {
|
|
548
|
+
createdAt?: string;
|
|
549
|
+
deletedAt?: string;
|
|
550
|
+
};
|
|
450
551
|
}
|
|
552
|
+
|
|
451
553
|
/**
|
|
452
554
|
* Build a model-scoped repository. `runtime` (client + ambient transaction
|
|
453
|
-
* context) comes from the registry, so this
|
|
555
|
+
* context) comes from the registry, so this module never touches the app's
|
|
454
556
|
* database handle directly.
|
|
455
557
|
*/
|
|
456
558
|
declare function buildRepository<TDelegate>(runtime: RepoRuntime, modelKey: string, config?: RepositoryOptions<TDelegate>): Repository<TDelegate>;
|
|
@@ -491,4 +593,5 @@ declare function createFilters<TDelegate>(): {
|
|
|
491
593
|
not: (node: _querykitjs_core.FilterNode<FieldKey<TDelegate>, RawWhere<TDelegate>>) => _querykitjs_core.NotGroup<FieldKey<TDelegate>, RawWhere<TDelegate>>;
|
|
492
594
|
};
|
|
493
595
|
|
|
494
|
-
export {
|
|
596
|
+
export { buildRepository, createFilters, createRegistry };
|
|
597
|
+
export type { AggregateRow, AggregateSpec, AndGroup, AnyClient, AnyDelegate, ByIdParams, ColumnSelection, CursorMeta, CursorParams, CursorResult, DelegateOf, FieldCondition, FieldKey, FieldMeta, Filter, FilterNode, FilterOperator, FilterScalar, FilterValue, Id, IncludeInput, InfiniteMeta, InfiniteParams, InfiniteResult, Insert, LooseFieldKey, ModelKey, ModelMeta, NotGroup, OffsetMeta, OffsetParams, OffsetResult, OrGroup, QueryParams, RawWhere, Registry, RegistryOptions, RepoRuntime, Repository, RepositoryExtender, RepositoryOptions, ResultFor, Row, Scope, SelectInput, Sort, SortDirection, SortItem, UpsertOptions, WithRelations };
|