@zudojs/database 0.0.1 → 1.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.
Files changed (134) hide show
  1. package/README.md +223 -17
  2. package/dist/cache/cache.memory.d.ts +167 -0
  3. package/dist/cache/cache.memory.js +186 -40
  4. package/dist/cache/index.d.ts +2 -2
  5. package/dist/cache/index.js +2 -2
  6. package/dist/database/database.core.d.ts +91 -0
  7. package/dist/database/database.core.js +150 -0
  8. package/dist/databaseClient/databaseClient.core.d.ts +165 -14
  9. package/dist/databaseClient/databaseClient.core.js +304 -70
  10. package/dist/databaseClient/databaseClient.errors.d.ts +112 -0
  11. package/dist/databaseClient/databaseClient.errors.js +425 -0
  12. package/dist/databaseClient/index.d.ts +2 -1
  13. package/dist/databaseClient/index.js +2 -1
  14. package/dist/databaseConnection/databaseConnection.manager.d.ts +163 -0
  15. package/dist/databaseConnection/databaseConnection.manager.js +138 -76
  16. package/dist/databaseConnection/index.d.ts +1 -1
  17. package/dist/databaseType/databaseType.type.d.ts +224 -0
  18. package/dist/databaseType/databaseType.type.js +10 -0
  19. package/dist/health/health.check.d.ts +74 -0
  20. package/dist/health/health.check.js +78 -47
  21. package/dist/health/index.d.ts +1 -1
  22. package/dist/health/index.js +1 -1
  23. package/dist/index.d.ts +14 -14
  24. package/dist/index.js +11 -11
  25. package/dist/locks/index.d.ts +2 -2
  26. package/dist/locks/index.js +2 -2
  27. package/dist/locks/locks.core.d.ts +128 -0
  28. package/dist/locks/locks.core.js +144 -85
  29. package/dist/migration/index.d.ts +3 -1
  30. package/dist/migration/index.js +2 -0
  31. package/dist/migration/migration.dialect.d.ts +65 -0
  32. package/dist/migration/migration.dialect.js +63 -0
  33. package/dist/migration/migration.helpers.d.ts +65 -0
  34. package/dist/migration/migration.helpers.js +141 -0
  35. package/dist/migration/migration.runner.d.ts +75 -0
  36. package/dist/migration/migration.runner.js +195 -107
  37. package/dist/migration/migration.types.d.ts +85 -0
  38. package/dist/migration/migration.types.js +2 -0
  39. package/dist/pagination/index.d.ts +2 -1
  40. package/dist/pagination/index.js +2 -1
  41. package/dist/pagination/pagination.core.d.ts +163 -0
  42. package/dist/pagination/pagination.core.js +279 -0
  43. package/dist/pagination/pagination.keyset.d.ts +55 -0
  44. package/dist/pagination/pagination.keyset.js +108 -0
  45. package/dist/queryBuilder/index.d.ts +4 -3
  46. package/dist/queryBuilder/index.js +3 -2
  47. package/dist/queryBuilder/queryBuilder.core.d.ts +178 -0
  48. package/dist/queryBuilder/queryBuilder.core.js +420 -0
  49. package/dist/queryBuilder/queryBuilder.factory.d.ts +6 -0
  50. package/dist/queryBuilder/queryBuilder.factory.js +8 -0
  51. package/dist/queryBuilder/queryBuilder.filter.d.ts +170 -0
  52. package/dist/queryBuilder/queryBuilder.filter.js +497 -0
  53. package/dist/queryBuilder/queryBuilder.prisma.d.ts +60 -0
  54. package/dist/queryBuilder/queryBuilder.prisma.js +233 -0
  55. package/dist/queryBuilder/queryBuilder.type.d.ts +48 -0
  56. package/dist/queryBuilder/queryBuilder.type.js +2 -0
  57. package/dist/relations/index.d.ts +1 -1
  58. package/dist/relations/index.js +1 -1
  59. package/dist/relations/relations.definition.d.ts +184 -0
  60. package/dist/relations/relations.definition.js +362 -0
  61. package/dist/repository/index.d.ts +2 -1
  62. package/dist/repository/index.js +1 -0
  63. package/dist/repository/repository.base.d.ts +270 -0
  64. package/dist/repository/repository.base.js +350 -84
  65. package/dist/repository/repository.errors.d.ts +60 -0
  66. package/dist/repository/repository.errors.js +235 -0
  67. package/dist/seed/index.d.ts +2 -2
  68. package/dist/seed/index.js +1 -1
  69. package/dist/seed/seed.runner.d.ts +160 -0
  70. package/dist/seed/seed.runner.js +194 -225
  71. package/dist/transaction/index.d.ts +1 -1
  72. package/dist/transaction/index.js +1 -1
  73. package/dist/transaction/transaction.core.d.ts +117 -0
  74. package/dist/transaction/transaction.core.js +83 -56
  75. package/dist/unitOfWork/unitOfWork.core.d.ts +44 -0
  76. package/dist/unitOfWork/unitOfWork.core.js +9 -20
  77. package/package.json +35 -19
  78. package/dist/cache/cache.memory.d.ts.map +0 -1
  79. package/dist/cache/cache.memory.js.map +0 -1
  80. package/dist/cache/index.d.ts.map +0 -1
  81. package/dist/cache/index.js.map +0 -1
  82. package/dist/database/database.core.d.ts.map +0 -1
  83. package/dist/database/index.d.ts.map +0 -1
  84. package/dist/database/index.js.map +0 -1
  85. package/dist/databaseClient/databaseClient.core.d.ts.map +0 -1
  86. package/dist/databaseClient/databaseClient.core.js.map +0 -1
  87. package/dist/databaseClient/databaseClient.logger.d.ts.map +0 -1
  88. package/dist/databaseClient/databaseClient.logger.js.map +0 -1
  89. package/dist/databaseClient/index.d.ts.map +0 -1
  90. package/dist/databaseClient/index.js.map +0 -1
  91. package/dist/databaseConnection/databaseConnection.manager.d.ts.map +0 -1
  92. package/dist/databaseConnection/databaseConnection.manager.js.map +0 -1
  93. package/dist/databaseConnection/index.d.ts.map +0 -1
  94. package/dist/databaseConnection/index.js.map +0 -1
  95. package/dist/databaseType/index.d.ts.map +0 -1
  96. package/dist/databaseType/index.js.map +0 -1
  97. package/dist/health/health.check.d.ts.map +0 -1
  98. package/dist/health/health.check.js.map +0 -1
  99. package/dist/health/index.d.ts.map +0 -1
  100. package/dist/health/index.js.map +0 -1
  101. package/dist/index.d.ts.map +0 -1
  102. package/dist/index.js.map +0 -1
  103. package/dist/locks/index.d.ts.map +0 -1
  104. package/dist/locks/index.js.map +0 -1
  105. package/dist/locks/locks.core.d.ts.map +0 -1
  106. package/dist/locks/locks.core.js.map +0 -1
  107. package/dist/migration/index.d.ts.map +0 -1
  108. package/dist/migration/index.js.map +0 -1
  109. package/dist/migration/migration.helpers.d.ts.map +0 -1
  110. package/dist/migration/migration.runner.d.ts.map +0 -1
  111. package/dist/migration/migration.runner.js.map +0 -1
  112. package/dist/migration/migration.types.d.ts.map +0 -1
  113. package/dist/pagination/index.d.ts.map +0 -1
  114. package/dist/pagination/index.js.map +0 -1
  115. package/dist/queryBuilder/index.d.ts.map +0 -1
  116. package/dist/queryBuilder/index.js.map +0 -1
  117. package/dist/relations/index.d.ts.map +0 -1
  118. package/dist/relations/index.js.map +0 -1
  119. package/dist/repository/index.d.ts.map +0 -1
  120. package/dist/repository/index.js.map +0 -1
  121. package/dist/repository/repository.base.d.ts.map +0 -1
  122. package/dist/repository/repository.base.js.map +0 -1
  123. package/dist/seed/index.d.ts.map +0 -1
  124. package/dist/seed/index.js.map +0 -1
  125. package/dist/seed/seed.runner.d.ts.map +0 -1
  126. package/dist/seed/seed.runner.js.map +0 -1
  127. package/dist/transaction/index.d.ts.map +0 -1
  128. package/dist/transaction/index.js.map +0 -1
  129. package/dist/transaction/transaction.core.d.ts.map +0 -1
  130. package/dist/transaction/transaction.core.js.map +0 -1
  131. package/dist/unitOfWork/index.d.ts.map +0 -1
  132. package/dist/unitOfWork/index.js.map +0 -1
  133. package/dist/unitOfWork/unitOfWork.core.d.ts.map +0 -1
  134. package/dist/unitOfWork/unitOfWork.core.js.map +0 -1
@@ -0,0 +1,362 @@
1
+ /**
2
+ * Default maximum include depth.
3
+ */
4
+ export const DEFAULT_INCLUDE_DEPTH = 5;
5
+ /**
6
+ * Creates a one-to-one relation definition.
7
+ */
8
+ export function oneToOne(definition) {
9
+ const relation = Object.freeze({
10
+ ...definition,
11
+ type: "one-to-one",
12
+ });
13
+ validateRelation(relation);
14
+ return relation;
15
+ }
16
+ /**
17
+ * Creates a one-to-many relation definition.
18
+ */
19
+ export function oneToMany(definition) {
20
+ const relation = Object.freeze({
21
+ ...definition,
22
+ type: "one-to-many",
23
+ });
24
+ validateRelation(relation);
25
+ return relation;
26
+ }
27
+ /**
28
+ * Creates a many-to-one relation definition.
29
+ */
30
+ export function manyToOne(definition) {
31
+ const relation = Object.freeze({
32
+ ...definition,
33
+ type: "many-to-one",
34
+ });
35
+ validateRelation(relation);
36
+ return relation;
37
+ }
38
+ /**
39
+ * Creates a many-to-many relation definition.
40
+ */
41
+ export function manyToMany(definition) {
42
+ const relation = Object.freeze({
43
+ ...definition,
44
+ type: "many-to-many",
45
+ });
46
+ validateRelation(relation);
47
+ return relation;
48
+ }
49
+ /**
50
+ * Creates a relation include definition.
51
+ */
52
+ export function includeRelation(relation, options = {}) {
53
+ validateRelationName(relation);
54
+ if (options.select !== undefined) {
55
+ for (const field of options.select) {
56
+ validateFieldName(field);
57
+ }
58
+ }
59
+ if (options.include !== undefined) {
60
+ for (const nested of options.include) {
61
+ validateInclude(nested);
62
+ }
63
+ }
64
+ return Object.freeze({
65
+ relation,
66
+ select: options.select
67
+ ? Object.freeze([...new Set(options.select)])
68
+ : undefined,
69
+ include: options.include ? Object.freeze([...options.include]) : undefined,
70
+ });
71
+ }
72
+ /**
73
+ * Validates a relation include (recursively).
74
+ */
75
+ export function validateInclude(include) {
76
+ if (!include || typeof include !== "object") {
77
+ throw new TypeError("A relation include is required.");
78
+ }
79
+ validateRelationName(include.relation);
80
+ for (const field of include.select ?? []) {
81
+ validateFieldName(field);
82
+ }
83
+ for (const nested of include.include ?? []) {
84
+ validateInclude(nested);
85
+ }
86
+ }
87
+ /**
88
+ * Translates relation includes into a Prisma `include` object.
89
+ *
90
+ * When a registry is supplied every relation is validated against the
91
+ * parent model (descending through child models for nested includes) and
92
+ * cyclic includes are rejected. Depth is bounded in all cases.
93
+ */
94
+ export function toPrismaInclude(includes, options = {}) {
95
+ const maxDepth = options.depth ?? DEFAULT_INCLUDE_DEPTH;
96
+ if (!Number.isInteger(maxDepth) || maxDepth < 1) {
97
+ throw new TypeError("Include depth must be a positive integer.");
98
+ }
99
+ if (options.registry && options.parent === undefined) {
100
+ throw new TypeError("toPrismaInclude requires `parent` when a registry is supplied.");
101
+ }
102
+ return buildInclude(includes, options, options.parent, 1, maxDepth, []);
103
+ }
104
+ function buildInclude(includes, options, parent, depth, maxDepth, path) {
105
+ if (depth > maxDepth) {
106
+ throw new RangeError(`Relation include depth exceeds the maximum of ${maxDepth}.`);
107
+ }
108
+ const result = {};
109
+ for (const include of includes) {
110
+ validateInclude(include);
111
+ if (include.relation in result) {
112
+ throw new TypeError(`Relation "${include.relation}" is included more than once.`);
113
+ }
114
+ let definition;
115
+ if (options.registry) {
116
+ definition = options.registry.get(include.relation, parent);
117
+ if (!definition) {
118
+ throw new TypeError(`Relation "${include.relation}" is not registered for the parent model.`);
119
+ }
120
+ if (path.includes(definition)) {
121
+ throw new TypeError(`Relation include "${include.relation}" is cyclic.`);
122
+ }
123
+ }
124
+ const entry = {};
125
+ if (include.select && include.select.length > 0) {
126
+ const select = {};
127
+ for (const field of include.select) {
128
+ select[field] = true;
129
+ }
130
+ entry["select"] = select;
131
+ }
132
+ if (include.include && include.include.length > 0) {
133
+ const nested = buildInclude(include.include, options, definition ? definition.child : undefined, depth + 1, maxDepth, definition ? [...path, definition] : path);
134
+ if (entry["select"]) {
135
+ entry["select"] = { ...entry["select"], ...nested };
136
+ }
137
+ else {
138
+ entry["include"] = nested;
139
+ }
140
+ }
141
+ if (options.includeDeleted === false &&
142
+ definition &&
143
+ isCollectionRelation(definition)) {
144
+ const field = options.softDeleteField ?? "deletedAt";
145
+ validateFieldName(field);
146
+ entry["where"] = { [field]: null };
147
+ }
148
+ result[include.relation] = Object.keys(entry).length === 0 ? true : entry;
149
+ }
150
+ return result;
151
+ }
152
+ /**
153
+ * Creates a nested relation include.
154
+ */
155
+ export function includeRelations(...includes) {
156
+ return Object.freeze([...includes]);
157
+ }
158
+ /**
159
+ * Relation registry used by database infrastructure.
160
+ *
161
+ * Relations are keyed by parent model and name, so two models may each
162
+ * define a relation with the same name.
163
+ */
164
+ export class RelationRegistry {
165
+ relations = new Map();
166
+ /**
167
+ * Registers a relation.
168
+ */
169
+ register(relation) {
170
+ validateRelation(relation);
171
+ const byName = this.relations.get(relation.parent);
172
+ if (byName?.has(relation.name)) {
173
+ throw new Error(`Relation "${relation.name}" is already registered for this parent.`);
174
+ }
175
+ const frozen = Object.freeze({
176
+ ...relation,
177
+ });
178
+ if (byName) {
179
+ byName.set(relation.name, frozen);
180
+ }
181
+ else {
182
+ this.relations.set(relation.parent, new Map([[relation.name, frozen]]));
183
+ }
184
+ return this;
185
+ }
186
+ /**
187
+ * Registers multiple relations.
188
+ */
189
+ registerMany(relations) {
190
+ for (const relation of relations) {
191
+ this.register(relation);
192
+ }
193
+ return this;
194
+ }
195
+ /**
196
+ * Gets a relation by name.
197
+ *
198
+ * Without `parent` the name must be unique across all parents; an
199
+ * ambiguous lookup throws.
200
+ */
201
+ get(name, parent) {
202
+ if (parent !== undefined) {
203
+ return this.relations.get(parent)?.get(name);
204
+ }
205
+ const matches = this.findByName(name);
206
+ if (matches.length > 1) {
207
+ throw new Error(`Relation "${name}" is registered for multiple parents; specify the parent.`);
208
+ }
209
+ return matches[0];
210
+ }
211
+ /**
212
+ * Checks whether a relation exists.
213
+ */
214
+ has(name, parent) {
215
+ if (parent !== undefined) {
216
+ return this.relations.get(parent)?.has(name) ?? false;
217
+ }
218
+ return this.findByName(name).length > 0;
219
+ }
220
+ /**
221
+ * Removes a relation. Without `parent`, every relation with that name is
222
+ * removed.
223
+ */
224
+ remove(name, parent) {
225
+ if (parent !== undefined) {
226
+ const byName = this.relations.get(parent);
227
+ const removed = byName?.delete(name) ?? false;
228
+ if (byName && byName.size === 0) {
229
+ this.relations.delete(parent);
230
+ }
231
+ return removed;
232
+ }
233
+ let removed = false;
234
+ for (const [key, byName] of this.relations) {
235
+ if (byName.delete(name)) {
236
+ removed = true;
237
+ }
238
+ if (byName.size === 0) {
239
+ this.relations.delete(key);
240
+ }
241
+ }
242
+ return removed;
243
+ }
244
+ /**
245
+ * Returns all registered relations.
246
+ */
247
+ all() {
248
+ return Object.freeze([...this.relations.values()].flatMap((byName) => [...byName.values()]));
249
+ }
250
+ /**
251
+ * Returns relations for a specific parent entity.
252
+ */
253
+ forParent(parent) {
254
+ return Object.freeze([...(this.relations.get(parent)?.values() ?? [])]);
255
+ }
256
+ /**
257
+ * Returns relations for a specific child entity.
258
+ */
259
+ forChild(child) {
260
+ return Object.freeze(this.all().filter((relation) => relation.child === child));
261
+ }
262
+ /**
263
+ * Clears all registered relations.
264
+ */
265
+ clear() {
266
+ this.relations.clear();
267
+ }
268
+ /**
269
+ * Returns the number of registered relations.
270
+ */
271
+ get size() {
272
+ let size = 0;
273
+ for (const byName of this.relations.values()) {
274
+ size += byName.size;
275
+ }
276
+ return size;
277
+ }
278
+ findByName(name) {
279
+ const matches = [];
280
+ for (const byName of this.relations.values()) {
281
+ const relation = byName.get(name);
282
+ if (relation) {
283
+ matches.push(relation);
284
+ }
285
+ }
286
+ return matches;
287
+ }
288
+ }
289
+ /**
290
+ * Creates a relation registry.
291
+ */
292
+ export function createRelationRegistry(relations = []) {
293
+ const registry = new RelationRegistry();
294
+ registry.registerMany(relations);
295
+ return registry;
296
+ }
297
+ /**
298
+ * Validates a relation definition.
299
+ */
300
+ export function validateRelation(relation) {
301
+ if (!relation || typeof relation !== "object") {
302
+ throw new TypeError("A relation definition is required.");
303
+ }
304
+ validateRelationName(relation.name);
305
+ if (relation.parent === undefined || relation.parent === null) {
306
+ throw new TypeError(`Relation "${relation.name}" requires a parent entity.`);
307
+ }
308
+ if (relation.child === undefined || relation.child === null) {
309
+ throw new TypeError(`Relation "${relation.name}" requires a child entity.`);
310
+ }
311
+ if (!isRelationType(relation.type)) {
312
+ throw new TypeError(`Relation "${relation.name}" has an invalid relation type.`);
313
+ }
314
+ if (typeof relation.foreignKey !== "string" ||
315
+ relation.foreignKey.trim().length === 0) {
316
+ throw new TypeError(`Relation "${relation.name}" requires a foreign key.`);
317
+ }
318
+ if (typeof relation.referencedKey !== "string" ||
319
+ relation.referencedKey.trim().length === 0) {
320
+ throw new TypeError(`Relation "${relation.name}" requires a referenced key.`);
321
+ }
322
+ }
323
+ /**
324
+ * Checks whether a value is a supported relation type.
325
+ */
326
+ export function isRelationType(value) {
327
+ return (value === "one-to-one" ||
328
+ value === "one-to-many" ||
329
+ value === "many-to-one" ||
330
+ value === "many-to-many");
331
+ }
332
+ /**
333
+ * Returns whether the relation represents a collection.
334
+ */
335
+ export function isCollectionRelation(relation) {
336
+ return relation.type === "one-to-many" || relation.type === "many-to-many";
337
+ }
338
+ /**
339
+ * Returns whether the relation represents a single entity.
340
+ */
341
+ export function isSingleRelation(relation) {
342
+ return relation.type === "one-to-one" || relation.type === "many-to-one";
343
+ }
344
+ /**
345
+ * Validates a relation name.
346
+ */
347
+ function validateRelationName(name) {
348
+ if (typeof name !== "string" || name.trim().length === 0) {
349
+ throw new TypeError("A relation name is required.");
350
+ }
351
+ validateFieldName(name);
352
+ }
353
+ const FIELD_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
354
+ /**
355
+ * Validates a relation or select field name.
356
+ */
357
+ function validateFieldName(field) {
358
+ if (typeof field !== "string" || !FIELD_PATTERN.test(field)) {
359
+ throw new TypeError(`Invalid relation field name "${String(field)}".`);
360
+ }
361
+ }
362
+ //# sourceMappingURL=relations.definition.js.map
@@ -3,5 +3,6 @@
3
3
  *
4
4
  * Generic repository pattern with Prisma delegate support.
5
5
  */
6
- export { BaseRepository, type RepositoryDelegate, type BaseRepositoryOptions, } from "./repository.base.js";
6
+ export { BaseRepository, type RepositoryDelegate, type BaseRepositoryOptions, type SoftDeleteOptions, type CursorQueryOptions, type TransactionClientLike, } from "./repository.base.js";
7
+ export { mapRepositoryError, isPrismaErrorLike, toDatabaseOperation, toErrorMetadata, createAbortError, createTimeoutError, type RepositoryOperation, type RepositoryErrorContext, type PrismaErrorLike, } from "./repository.errors.js";
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,5 @@
4
4
  * Generic repository pattern with Prisma delegate support.
5
5
  */
6
6
  export { BaseRepository, } from "./repository.base.js";
7
+ export { mapRepositoryError, isPrismaErrorLike, toDatabaseOperation, toErrorMetadata, createAbortError, createTimeoutError, } from "./repository.errors.js";
7
8
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,270 @@
1
+ import type { DatabaseOperationOptions, PaginatedResult, QueryOptions, Repository, SoftDeletableRepository, SortInput } from "../databaseType/databaseType.type.js";
2
+ import { type CursorPaginatedResult } from "../pagination/pagination.core.js";
3
+ import type { QueryBuilder } from "../queryBuilder/queryBuilder.core.js";
4
+ import type { QueryBuilderState } from "../queryBuilder/queryBuilder.type.js";
5
+ import type { RelationLoadOptions, RelationRegistry } from "../relations/relations.definition.js";
6
+ import { type RepositoryOperation } from "./repository.errors.js";
7
+ /**
8
+ * Generic Prisma-style delegate contract.
9
+ *
10
+ * This keeps the repository base class independent from generated
11
+ * Prisma model types while still supporting standard CRUD operations.
12
+ */
13
+ export interface RepositoryDelegate<TEntity, TId = string, TCreateInput = Partial<TEntity>, TUpdateInput = Partial<TEntity>, TWhereInput = unknown> {
14
+ findUnique(args: {
15
+ where: unknown;
16
+ }): Promise<TEntity | null>;
17
+ findFirst(args: {
18
+ where?: TWhereInput;
19
+ orderBy?: unknown;
20
+ select?: unknown;
21
+ }): Promise<TEntity | null>;
22
+ findMany(args?: {
23
+ where?: TWhereInput;
24
+ skip?: number;
25
+ take?: number;
26
+ orderBy?: unknown;
27
+ select?: unknown;
28
+ include?: unknown;
29
+ }): Promise<readonly TEntity[]>;
30
+ create(args: {
31
+ data: TCreateInput;
32
+ }): Promise<TEntity>;
33
+ update(args: {
34
+ where: unknown;
35
+ data: TUpdateInput;
36
+ }): Promise<TEntity>;
37
+ delete(args: {
38
+ where: unknown;
39
+ }): Promise<TEntity>;
40
+ count(args?: {
41
+ where?: TWhereInput;
42
+ }): Promise<number>;
43
+ upsert?(args: {
44
+ where: unknown;
45
+ create: TCreateInput;
46
+ update: TUpdateInput;
47
+ }): Promise<TEntity>;
48
+ createMany?(args: {
49
+ data: readonly TCreateInput[];
50
+ }): Promise<{
51
+ count: number;
52
+ }>;
53
+ deleteMany?(args: {
54
+ where?: TWhereInput;
55
+ }): Promise<{
56
+ count: number;
57
+ }>;
58
+ }
59
+ /**
60
+ * Soft-delete configuration.
61
+ */
62
+ export interface SoftDeleteOptions {
63
+ /**
64
+ * Nullable timestamp column marking deleted rows (default `deletedAt`).
65
+ */
66
+ readonly field?: string;
67
+ }
68
+ /**
69
+ * Options for constructing a repository.
70
+ */
71
+ export interface BaseRepositoryOptions {
72
+ readonly modelName?: string;
73
+ /**
74
+ * Primary key field used by `findById`, `update`, `delete` and friends
75
+ * (default `id`).
76
+ */
77
+ readonly idField?: string;
78
+ /**
79
+ * Enables soft deletion. Every read, count, exists, update and paginate
80
+ * path then excludes rows whose soft-delete field is set.
81
+ */
82
+ readonly softDelete?: boolean | SoftDeleteOptions;
83
+ /**
84
+ * Secret used to sign keyset cursors produced by `paginateCursor`.
85
+ */
86
+ readonly cursorSecret?: string;
87
+ /**
88
+ * Property on a transaction client that yields this model's delegate
89
+ * (default: `modelName` with a lower-cased first letter). Used by
90
+ * `withTransaction`.
91
+ */
92
+ readonly delegateKey?: string;
93
+ /**
94
+ * Relation registry used to validate `include` definitions passed to
95
+ * `findByQuery`.
96
+ */
97
+ readonly relations?: RelationRegistry;
98
+ /**
99
+ * Model identifier registered in `relations` for this repository's
100
+ * entity (default `modelName`).
101
+ */
102
+ readonly relationParent?: unknown;
103
+ }
104
+ /**
105
+ * Options for cursor pagination.
106
+ */
107
+ export interface CursorQueryOptions<TField extends string = string> extends DatabaseOperationOptions {
108
+ readonly cursor?: string | null;
109
+ readonly limit?: number;
110
+ /**
111
+ * Sort order. The id field is appended as a tiebreaker when absent.
112
+ */
113
+ readonly sort?: readonly SortInput<TField>[];
114
+ }
115
+ /**
116
+ * A Prisma transaction client (or any object exposing model delegates).
117
+ */
118
+ export type TransactionClientLike = Readonly<Record<string, unknown>>;
119
+ /**
120
+ * Generic base repository implementation.
121
+ *
122
+ * Concrete repositories should extend this class and provide the
123
+ * appropriate Prisma delegate plus any domain-specific behavior.
124
+ */
125
+ export declare abstract class BaseRepository<TEntity, TId = string, TCreateInput = Partial<TEntity>, TUpdateInput = Partial<TEntity>, TWhereInput = Record<string, unknown>> implements Repository<TEntity, TId, TCreateInput, TUpdateInput, TWhereInput>, SoftDeletableRepository<TEntity, TId, TCreateInput, TUpdateInput, TWhereInput> {
126
+ protected readonly delegate: RepositoryDelegate<TEntity, TId, TCreateInput, TUpdateInput, TWhereInput>;
127
+ protected readonly modelName: string;
128
+ protected readonly idField: string;
129
+ protected readonly softDeleteField?: string;
130
+ protected readonly cursorSecret?: string;
131
+ protected readonly delegateKey: string;
132
+ protected readonly relations?: RelationRegistry;
133
+ protected readonly relationParent: unknown;
134
+ /**
135
+ * When true, soft-deleted rows are visible to reads (see `withDeleted`).
136
+ */
137
+ protected readonly includeDeleted: boolean;
138
+ constructor(delegate: RepositoryDelegate<TEntity, TId, TCreateInput, TUpdateInput, TWhereInput>, options?: BaseRepositoryOptions);
139
+ /**
140
+ * Returns a copy of this repository bound to a transaction client's
141
+ * delegate, so operations run inside the transaction.
142
+ */
143
+ withTransaction(transaction: TransactionClientLike): this;
144
+ /**
145
+ * Returns a copy of this repository bound to a different delegate.
146
+ */
147
+ withDelegate(delegate: RepositoryDelegate<TEntity, TId, TCreateInput, TUpdateInput, TWhereInput>): this;
148
+ /**
149
+ * Returns a copy of this repository whose reads include soft-deleted
150
+ * rows.
151
+ */
152
+ withDeleted(): this;
153
+ /**
154
+ * Finds an entity by its primary identifier.
155
+ */
156
+ findById(id: TId, options?: DatabaseOperationOptions): Promise<TEntity | null>;
157
+ /**
158
+ * Finds the first entity matching a filter.
159
+ */
160
+ findOne(filter: TWhereInput, options?: DatabaseOperationOptions): Promise<TEntity | null>;
161
+ /**
162
+ * Finds all entities matching a filter.
163
+ */
164
+ findMany(filter?: TWhereInput, options?: DatabaseOperationOptions): Promise<readonly TEntity[]>;
165
+ /**
166
+ * Finds entities using pagination and sorting.
167
+ */
168
+ findPaginated<TField extends string = string>(filter?: TWhereInput, options?: QueryOptions<TField>): Promise<PaginatedResult<TEntity>>;
169
+ /**
170
+ * Alias of {@link findPaginated}.
171
+ */
172
+ paginate<TField extends string = string>(filter?: TWhereInput, options?: QueryOptions<TField>): Promise<PaginatedResult<TEntity>>;
173
+ /**
174
+ * Finds entities using keyset (cursor) pagination.
175
+ *
176
+ * Rows are ordered by `options.sort` (the id field is appended as a
177
+ * tiebreaker), `limit + 1` rows are fetched and the extra row decides
178
+ * `hasNextPage`. Cursors are validated against the sort fields and, when
179
+ * `cursorSecret` is configured, signed.
180
+ */
181
+ paginateCursor<TField extends string = string>(filter?: TWhereInput, options?: CursorQueryOptions<TField>): Promise<CursorPaginatedResult<TEntity>>;
182
+ /**
183
+ * Finds entities from a query builder (or its built state), applying the
184
+ * filter, sort, select, include and pagination it carries.
185
+ *
186
+ * `options.includeDeleted` and `options.depth` control how relation
187
+ * includes are resolved (see `toPrismaInclude`); by default soft-deleted
188
+ * rows of collection relations are filtered whenever this repository
189
+ * filters its own rows.
190
+ */
191
+ findByQuery<TField extends string = string>(query: QueryBuilder<TField> | QueryBuilderState<TField>, options?: RelationLoadOptions): Promise<readonly TEntity[]>;
192
+ /**
193
+ * Creates a new entity.
194
+ */
195
+ create(input: TCreateInput, options?: DatabaseOperationOptions): Promise<TEntity>;
196
+ /**
197
+ * Creates many entities and returns the number created.
198
+ */
199
+ createMany(inputs: readonly TCreateInput[], options?: DatabaseOperationOptions): Promise<number>;
200
+ /**
201
+ * Updates an entity by its identifier.
202
+ */
203
+ update(id: TId, input: TUpdateInput, options?: DatabaseOperationOptions): Promise<TEntity>;
204
+ /**
205
+ * Deletes an entity by its identifier (hard delete).
206
+ */
207
+ delete(id: TId, options?: DatabaseOperationOptions): Promise<void>;
208
+ /**
209
+ * Deletes every entity matching a filter (hard delete, including
210
+ * soft-deleted rows) and returns the number removed.
211
+ */
212
+ deleteMany(filter: TWhereInput, options?: DatabaseOperationOptions): Promise<number>;
213
+ /**
214
+ * Marks an entity as deleted by setting its soft-delete field.
215
+ */
216
+ softDelete(id: TId, options?: DatabaseOperationOptions): Promise<TEntity>;
217
+ /**
218
+ * Restores a soft-deleted entity.
219
+ */
220
+ restore(id: TId, options?: DatabaseOperationOptions): Promise<TEntity>;
221
+ /**
222
+ * Finds soft-deleted entities matching a filter.
223
+ */
224
+ findDeleted(filter?: TWhereInput, options?: DatabaseOperationOptions): Promise<readonly TEntity[]>;
225
+ /**
226
+ * Checks whether an entity exists.
227
+ */
228
+ exists(filter: TWhereInput, options?: DatabaseOperationOptions): Promise<boolean>;
229
+ /**
230
+ * Counts entities matching a filter.
231
+ */
232
+ count(filter?: TWhereInput, options?: DatabaseOperationOptions): Promise<number>;
233
+ /**
234
+ * Updates an entity if it exists, otherwise creates it.
235
+ */
236
+ upsert(where: TWhereInput, create: TCreateInput, update: TUpdateInput, options?: DatabaseOperationOptions): Promise<TEntity>;
237
+ /**
238
+ * Executes a repository operation and normalizes database failures.
239
+ *
240
+ * Honours `options.signal` for the whole duration of the call and
241
+ * `options.timeoutMs` as a client-side deadline (the underlying query is
242
+ * not cancelled server-side).
243
+ */
244
+ protected execute<TResult>(operation: RepositoryOperation | string, callback: () => Promise<TResult>, options?: DatabaseOperationOptions): Promise<TResult>;
245
+ /**
246
+ * Validates an entity identifier.
247
+ */
248
+ protected validateId(id: TId): void;
249
+ /**
250
+ * Validates a repository filter.
251
+ */
252
+ protected validateFilter(filter: TWhereInput): void;
253
+ /**
254
+ * Builds the primary-key `where` for an identifier.
255
+ */
256
+ protected whereId(id: TId): Record<string, unknown>;
257
+ /**
258
+ * Applies the soft-delete scope to a filter when enabled.
259
+ */
260
+ protected scope(filter?: TWhereInput): TWhereInput | undefined;
261
+ /**
262
+ * Converts generic sort definitions into Prisma-compatible orderBy.
263
+ */
264
+ protected buildOrderBy<TField extends string>(sort?: readonly SortInput<TField>[]): ReadonlyArray<Record<string, string>> | undefined;
265
+ private isScoped;
266
+ private requireSoftDelete;
267
+ private buildCursorSort;
268
+ private rebind;
269
+ }
270
+ //# sourceMappingURL=repository.base.d.ts.map