@zudojs/database 1.3.2 → 1.5.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.md +83 -0
- package/dist/cache/cache.memory.d.ts +0 -1
- package/dist/cache/cache.memory.js +0 -1
- package/dist/cache/index.d.ts +0 -1
- package/dist/cache/index.js +0 -1
- package/dist/database/database.core.d.ts +20 -7
- package/dist/database/database.core.js +8 -6
- package/dist/database/index.d.ts +0 -1
- package/dist/database/index.js +0 -1
- package/dist/databaseClient/databaseClient.core.d.ts +30 -15
- package/dist/databaseClient/databaseClient.core.js +19 -3
- package/dist/databaseClient/databaseClient.errors.d.ts +19 -2
- package/dist/databaseClient/databaseClient.errors.js +8 -1
- package/dist/databaseClient/databaseClient.logger.d.ts +0 -1
- package/dist/databaseClient/databaseClient.logger.js +0 -1
- package/dist/databaseClient/databaseClient.type.d.ts +52 -0
- package/dist/databaseClient/databaseClient.type.js +11 -0
- package/dist/databaseClient/index.d.ts +2 -3
- package/dist/databaseClient/index.js +1 -2
- package/dist/databaseConnection/databaseConnection.manager.d.ts +0 -1
- package/dist/databaseConnection/databaseConnection.manager.js +0 -1
- package/dist/databaseConnection/index.d.ts +0 -1
- package/dist/databaseConnection/index.js +0 -1
- package/dist/databaseType/databaseType.type.d.ts +6 -5
- package/dist/databaseType/databaseType.type.js +0 -1
- package/dist/databaseType/index.d.ts +0 -1
- package/dist/databaseType/index.js +0 -1
- package/dist/health/health.check.d.ts +0 -1
- package/dist/health/health.check.js +0 -1
- package/dist/health/index.d.ts +0 -1
- package/dist/health/index.js +0 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +2 -3
- package/dist/locks/index.d.ts +0 -1
- package/dist/locks/index.js +0 -1
- package/dist/locks/locks.core.d.ts +8 -7
- package/dist/locks/locks.core.js +2 -1
- package/dist/migration/index.d.ts +0 -1
- package/dist/migration/index.js +0 -1
- package/dist/migration/migration.dialect.d.ts +0 -1
- package/dist/migration/migration.dialect.js +0 -1
- package/dist/migration/migration.helpers.d.ts +4 -4
- package/dist/migration/migration.helpers.js +4 -1
- package/dist/migration/migration.runner.d.ts +16 -5
- package/dist/migration/migration.runner.js +69 -17
- package/dist/migration/migration.types.d.ts +20 -6
- package/dist/migration/migration.types.js +0 -1
- package/dist/pagination/index.d.ts +1 -1
- package/dist/pagination/index.js +1 -1
- package/dist/pagination/pagination.core.d.ts +0 -1
- package/dist/pagination/pagination.core.js +0 -1
- package/dist/pagination/pagination.cursorError.d.ts +0 -1
- package/dist/pagination/pagination.cursorError.js +0 -1
- package/dist/pagination/pagination.keyset.d.ts +12 -1
- package/dist/pagination/pagination.keyset.js +15 -3
- package/dist/pagination/pagination.keysetDirection.d.ts +0 -1
- package/dist/pagination/pagination.keysetDirection.js +0 -1
- package/dist/pagination/pagination.keysetValue.d.ts +37 -0
- package/dist/pagination/pagination.keysetValue.js +55 -0
- package/dist/queryBuilder/index.d.ts +0 -1
- package/dist/queryBuilder/index.js +0 -1
- package/dist/queryBuilder/queryBuilder.core.d.ts +0 -1
- package/dist/queryBuilder/queryBuilder.core.js +0 -1
- package/dist/queryBuilder/queryBuilder.factory.d.ts +0 -1
- package/dist/queryBuilder/queryBuilder.factory.js +0 -1
- package/dist/queryBuilder/queryBuilder.filter.d.ts +0 -1
- package/dist/queryBuilder/queryBuilder.filter.js +0 -1
- package/dist/queryBuilder/queryBuilder.prisma.d.ts +0 -1
- package/dist/queryBuilder/queryBuilder.prisma.js +0 -1
- package/dist/queryBuilder/queryBuilder.type.d.ts +0 -1
- package/dist/queryBuilder/queryBuilder.type.js +0 -1
- package/dist/relations/index.d.ts +0 -1
- package/dist/relations/index.js +0 -1
- package/dist/relations/relations.definition.d.ts +0 -1
- package/dist/relations/relations.definition.js +0 -1
- package/dist/repository/index.d.ts +1 -2
- package/dist/repository/index.js +0 -1
- package/dist/repository/repository.base.d.ts +27 -1
- package/dist/repository/repository.base.js +13 -2
- package/dist/repository/repository.delegate.d.ts +0 -1
- package/dist/repository/repository.delegate.js +0 -1
- package/dist/repository/repository.errors.d.ts +3 -1
- package/dist/repository/repository.errors.js +17 -2
- package/dist/seed/index.d.ts +0 -1
- package/dist/seed/index.js +0 -1
- package/dist/seed/seed.runner.d.ts +14 -12
- package/dist/seed/seed.runner.js +0 -1
- package/dist/transaction/index.d.ts +0 -1
- package/dist/transaction/index.js +0 -1
- package/dist/transaction/transaction.backoff.d.ts +0 -1
- package/dist/transaction/transaction.backoff.js +0 -1
- package/dist/transaction/transaction.core.d.ts +27 -11
- package/dist/transaction/transaction.core.js +11 -2
- package/dist/unitOfWork/index.d.ts +0 -1
- package/dist/unitOfWork/index.js +0 -1
- package/dist/unitOfWork/unitOfWork.core.d.ts +12 -11
- package/dist/unitOfWork/unitOfWork.core.js +0 -1
- package/package.json +4 -4
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor value comparisons for keyset pagination.
|
|
3
|
+
*
|
|
4
|
+
* A `Date` is encoded into a cursor as its ISO string, which carries
|
|
5
|
+
* millisecond precision. PostgreSQL `timestamp`/`timestamptz` columns keep
|
|
6
|
+
* microseconds unless declared with precision `(3)`, and Prisma hands rows
|
|
7
|
+
* back as JavaScript `Date`s, so the exact stored value is not available
|
|
8
|
+
* to the cursor. Comparing `field = C` against such a column matched
|
|
9
|
+
* nothing and `field < C` skipped every row created in the same
|
|
10
|
+
* millisecond as the cursor row.
|
|
11
|
+
*
|
|
12
|
+
* A date cursor value is therefore compared as its millisecond bucket
|
|
13
|
+
* `[C, C + 1ms)`: rows outside the bucket are ordered by the strict
|
|
14
|
+
* comparison, and rows inside it fall through to the next sort field (the
|
|
15
|
+
* id tiebreaker `paginateCursor` appends). On millisecond-precision
|
|
16
|
+
* columns this is exactly the old `=`/`<`/`>` comparison.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Whether a cursor value was encoded from a `Date` by `createKeysetCursor`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isDateCursorValue(value: unknown): value is string;
|
|
22
|
+
/**
|
|
23
|
+
* The ISO string one millisecond after a date cursor value: the exclusive
|
|
24
|
+
* upper bound of its millisecond bucket.
|
|
25
|
+
*/
|
|
26
|
+
export declare function nextMillisecond(value: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* The Prisma filter selecting rows that tie with a cursor value on a sort
|
|
29
|
+
* field: `{ equals }` for ordinary values, the millisecond bucket for dates.
|
|
30
|
+
*/
|
|
31
|
+
export declare function keysetTieFilter(value: unknown): Readonly<Record<string, unknown>>;
|
|
32
|
+
/**
|
|
33
|
+
* The Prisma filter selecting rows strictly after (`"gt"`) or before
|
|
34
|
+
* (`"lt"`) a cursor value on a sort field. For a date the boundary is the
|
|
35
|
+
* whole millisecond bucket: `lt C` below it, `gte C + 1ms` above it.
|
|
36
|
+
*/
|
|
37
|
+
export declare function keysetStrictFilter(value: unknown, comparison: "gt" | "lt"): Readonly<Record<string, unknown>>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor value comparisons for keyset pagination.
|
|
3
|
+
*
|
|
4
|
+
* A `Date` is encoded into a cursor as its ISO string, which carries
|
|
5
|
+
* millisecond precision. PostgreSQL `timestamp`/`timestamptz` columns keep
|
|
6
|
+
* microseconds unless declared with precision `(3)`, and Prisma hands rows
|
|
7
|
+
* back as JavaScript `Date`s, so the exact stored value is not available
|
|
8
|
+
* to the cursor. Comparing `field = C` against such a column matched
|
|
9
|
+
* nothing and `field < C` skipped every row created in the same
|
|
10
|
+
* millisecond as the cursor row.
|
|
11
|
+
*
|
|
12
|
+
* A date cursor value is therefore compared as its millisecond bucket
|
|
13
|
+
* `[C, C + 1ms)`: rows outside the bucket are ordered by the strict
|
|
14
|
+
* comparison, and rows inside it fall through to the next sort field (the
|
|
15
|
+
* id tiebreaker `paginateCursor` appends). On millisecond-precision
|
|
16
|
+
* columns this is exactly the old `=`/`<`/`>` comparison.
|
|
17
|
+
*/
|
|
18
|
+
/** Exactly the shape `Date.prototype.toISOString` emits. */
|
|
19
|
+
const ISO_MILLISECOND_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
20
|
+
/**
|
|
21
|
+
* Whether a cursor value was encoded from a `Date` by `createKeysetCursor`.
|
|
22
|
+
*/
|
|
23
|
+
export function isDateCursorValue(value) {
|
|
24
|
+
return (typeof value === "string" &&
|
|
25
|
+
ISO_MILLISECOND_PATTERN.test(value) &&
|
|
26
|
+
!Number.isNaN(Date.parse(value)));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The ISO string one millisecond after a date cursor value: the exclusive
|
|
30
|
+
* upper bound of its millisecond bucket.
|
|
31
|
+
*/
|
|
32
|
+
export function nextMillisecond(value) {
|
|
33
|
+
return new Date(Date.parse(value) + 1).toISOString();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The Prisma filter selecting rows that tie with a cursor value on a sort
|
|
37
|
+
* field: `{ equals }` for ordinary values, the millisecond bucket for dates.
|
|
38
|
+
*/
|
|
39
|
+
export function keysetTieFilter(value) {
|
|
40
|
+
if (isDateCursorValue(value)) {
|
|
41
|
+
return { gte: value, lt: nextMillisecond(value) };
|
|
42
|
+
}
|
|
43
|
+
return { equals: value };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The Prisma filter selecting rows strictly after (`"gt"`) or before
|
|
47
|
+
* (`"lt"`) a cursor value on a sort field. For a date the boundary is the
|
|
48
|
+
* whole millisecond bucket: `lt C` below it, `gte C + 1ms` above it.
|
|
49
|
+
*/
|
|
50
|
+
export function keysetStrictFilter(value, comparison) {
|
|
51
|
+
if (isDateCursorValue(value) && comparison === "gt") {
|
|
52
|
+
return { gte: nextMillisecond(value) };
|
|
53
|
+
}
|
|
54
|
+
return { [comparison]: value };
|
|
55
|
+
}
|
|
@@ -8,4 +8,3 @@ export { createQueryBuilder } from "./queryBuilder.factory.js";
|
|
|
8
8
|
export { toPrismaWhere, toPrismaArgs, toPrismaOrderBy, toPrismaSelect, toPrismaSkipTake, type PrismaWhere, type PrismaQueryArgs, type ToPrismaArgsOptions, } from "./queryBuilder.prisma.js";
|
|
9
9
|
export type { QueryCondition, QueryFilter, QueryOperator, RelationOperator, QueryBuilderState, } from "./queryBuilder.type.js";
|
|
10
10
|
export { equals, notEquals, inList, notInList, lessThan, lessThanOrEqual, greaterThan, greaterThanOrEqual, contains, startsWith, endsWith, isNull, isNotNull, and, or, not, condition, allOf, anyOf, fromObject, dateRange, oneOf, noneOf, optionalEquals, optionalContains, hasConditions, flattenAnd, cloneFilter, between, matchesPattern, isEmpty, isNotEmpty, dateOnly, isBefore, isAfter, isBetween, notCondition, relational, } from "./queryBuilder.filter.js";
|
|
11
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -7,4 +7,3 @@ export { QueryBuilder } from "./queryBuilder.core.js";
|
|
|
7
7
|
export { createQueryBuilder } from "./queryBuilder.factory.js";
|
|
8
8
|
export { toPrismaWhere, toPrismaArgs, toPrismaOrderBy, toPrismaSelect, toPrismaSkipTake, } from "./queryBuilder.prisma.js";
|
|
9
9
|
export { equals, notEquals, inList, notInList, lessThan, lessThanOrEqual, greaterThan, greaterThanOrEqual, contains, startsWith, endsWith, isNull, isNotNull, and, or, not, condition, allOf, anyOf, fromObject, dateRange, oneOf, noneOf, optionalEquals, optionalContains, hasConditions, flattenAnd, cloneFilter, between, matchesPattern, isEmpty, isNotEmpty, dateOnly, isBefore, isAfter, isBetween, notCondition, relational, } from "./queryBuilder.filter.js";
|
|
10
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -167,4 +167,3 @@ export declare function flattenAnd(filter: QueryFilter): QueryCondition[];
|
|
|
167
167
|
*/
|
|
168
168
|
export declare function cloneFilter(filter: QueryFilter): QueryFilter;
|
|
169
169
|
export declare function cloneFilter(filter?: QueryFilter): QueryFilter | undefined;
|
|
170
|
-
//# sourceMappingURL=queryBuilder.filter.d.ts.map
|
|
@@ -4,4 +4,3 @@
|
|
|
4
4
|
* Entity relation definitions and registry.
|
|
5
5
|
*/
|
|
6
6
|
export { oneToOne, oneToMany, manyToOne, manyToMany, includeRelation, includeRelations, RelationRegistry, createRelationRegistry, validateRelation, validateInclude, toPrismaInclude, DEFAULT_INCLUDE_DEPTH, isRelationType, isCollectionRelation, isSingleRelation, type RelationDefinition, type RelationType, type RelationLoadOptions, type RelationInclude, type ToPrismaIncludeOptions, } from "./relations.definition.js";
|
|
7
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/relations/index.js
CHANGED
|
@@ -4,4 +4,3 @@
|
|
|
4
4
|
* Entity relation definitions and registry.
|
|
5
5
|
*/
|
|
6
6
|
export { oneToOne, oneToMany, manyToOne, manyToMany, includeRelation, includeRelations, RelationRegistry, createRelationRegistry, validateRelation, validateInclude, toPrismaInclude, DEFAULT_INCLUDE_DEPTH, isRelationType, isCollectionRelation, isSingleRelation, } from "./relations.definition.js";
|
|
7
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -181,4 +181,3 @@ export declare function isCollectionRelation(relation: RelationDefinition): bool
|
|
|
181
181
|
* Returns whether the relation represents a single entity.
|
|
182
182
|
*/
|
|
183
183
|
export declare function isSingleRelation(relation: RelationDefinition): boolean;
|
|
184
|
-
//# sourceMappingURL=relations.definition.d.ts.map
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Generic repository pattern with Prisma delegate support.
|
|
5
5
|
*/
|
|
6
|
-
export { BaseRepository, type BaseRepositoryOptions, type SoftDeleteOptions, type CursorQueryOptions, type TransactionClientLike, } from "./repository.base.js";
|
|
6
|
+
export { BaseRepository, type BaseRepositoryOptions, type SoftDeleteOptions, type CreateCursorOptions, type CursorQueryOptions, type TransactionClientLike, } from "./repository.base.js";
|
|
7
7
|
export { type RepositoryDelegate, type RepositoryDelegateOperations, } from "./repository.delegate.js";
|
|
8
8
|
export { mapRepositoryError, isPrismaErrorLike, toDatabaseOperation, toErrorMetadata, createAbortError, createTimeoutError, type RepositoryOperation, type RepositoryErrorContext, type PrismaErrorLike, } from "./repository.errors.js";
|
|
9
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/repository/index.js
CHANGED
|
@@ -6,4 +6,3 @@
|
|
|
6
6
|
export { BaseRepository, } from "./repository.base.js";
|
|
7
7
|
export {} from "./repository.delegate.js";
|
|
8
8
|
export { mapRepositoryError, isPrismaErrorLike, toDatabaseOperation, toErrorMetadata, createAbortError, createTimeoutError, } from "./repository.errors.js";
|
|
9
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DatabaseOperationOptions, PaginatedResult, QueryOptions, Repository, SoftDeletableRepository, SortInput } from "../databaseType/databaseType.type.js";
|
|
2
2
|
import { type CursorPaginatedResult } from "../pagination/pagination.core.js";
|
|
3
|
+
import { type KeysetDirection } from "../pagination/pagination.keysetDirection.js";
|
|
3
4
|
import type { QueryBuilder } from "../queryBuilder/queryBuilder.core.js";
|
|
4
5
|
import type { QueryBuilderState } from "../queryBuilder/queryBuilder.type.js";
|
|
5
6
|
import type { RelationLoadOptions, RelationRegistry } from "../relations/relations.definition.js";
|
|
@@ -61,6 +62,22 @@ export interface CursorQueryOptions<TField extends string = string> extends Data
|
|
|
61
62
|
*/
|
|
62
63
|
readonly sort?: readonly SortInput<TField>[];
|
|
63
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Options for {@link BaseRepository.createCursor}.
|
|
67
|
+
*/
|
|
68
|
+
export interface CreateCursorOptions<TField extends string = string> {
|
|
69
|
+
/**
|
|
70
|
+
* The sort the page is fetched with, as passed to `paginateCursor`. The
|
|
71
|
+
* id field is appended as a tiebreaker when absent, exactly as
|
|
72
|
+
* `paginateCursor` does.
|
|
73
|
+
*/
|
|
74
|
+
readonly sort?: readonly SortInput<TField>[];
|
|
75
|
+
/**
|
|
76
|
+
* `"forward"` (default) selects the rows after `row`; `"backward"` the
|
|
77
|
+
* rows before it (a `previousCursor`).
|
|
78
|
+
*/
|
|
79
|
+
readonly direction?: KeysetDirection;
|
|
80
|
+
}
|
|
64
81
|
/**
|
|
65
82
|
* A Prisma transaction client (or any object exposing model delegates).
|
|
66
83
|
*/
|
|
@@ -133,6 +150,16 @@ export declare abstract class BaseRepository<TEntity, TId = string, TCreateInput
|
|
|
133
150
|
* before any query runs.
|
|
134
151
|
*/
|
|
135
152
|
paginateCursor<TField extends string = string>(filter?: TWhereInput, options?: CursorQueryOptions<TField>): Promise<CursorPaginatedResult<TEntity>>;
|
|
153
|
+
/**
|
|
154
|
+
* Builds a cursor positioned at `row` that `paginateCursor` accepts for
|
|
155
|
+
* the same `sort`: the id tiebreaker is appended and the cursor is
|
|
156
|
+
* signed with `cursorSecret` when configured.
|
|
157
|
+
*
|
|
158
|
+
* `createKeysetCursor(row, sort)` with the bare sort produces a cursor
|
|
159
|
+
* without the tiebreaker, which `paginateCursor` rejects as missing the
|
|
160
|
+
* id field.
|
|
161
|
+
*/
|
|
162
|
+
createCursor<TField extends string = string>(row: TEntity, options?: CreateCursorOptions<TField>): string;
|
|
136
163
|
/**
|
|
137
164
|
* Finds entities from a query builder (or its built state), applying the
|
|
138
165
|
* filter, sort, select, include and pagination it carries.
|
|
@@ -234,4 +261,3 @@ export declare abstract class BaseRepository<TEntity, TId = string, TCreateInput
|
|
|
234
261
|
private buildCursorSort;
|
|
235
262
|
private rebind;
|
|
236
263
|
}
|
|
237
|
-
//# sourceMappingURL=repository.base.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DatabaseError } from "@zudojs/errors";
|
|
2
2
|
import { createPaginationMeta, normalizeLimit, normalizePage, } from "../pagination/pagination.core.js";
|
|
3
|
-
import { buildKeysetWhere, createKeysetPage, decodeKeysetCursor, } from "../pagination/pagination.keyset.js";
|
|
3
|
+
import { buildKeysetWhere, createKeysetCursor, createKeysetPage, decodeKeysetCursor, } from "../pagination/pagination.keyset.js";
|
|
4
4
|
import { getKeysetDirection, keysetFetchSort, } from "../pagination/pagination.keysetDirection.js";
|
|
5
5
|
import { toPrismaArgs, toPrismaOrderBy, } from "../queryBuilder/queryBuilder.prisma.js";
|
|
6
6
|
import { toDelegateOperations, } from "./repository.delegate.js";
|
|
@@ -188,6 +188,18 @@ export class BaseRepository {
|
|
|
188
188
|
direction,
|
|
189
189
|
});
|
|
190
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Builds a cursor positioned at `row` that `paginateCursor` accepts for
|
|
193
|
+
* the same `sort`: the id tiebreaker is appended and the cursor is
|
|
194
|
+
* signed with `cursorSecret` when configured.
|
|
195
|
+
*
|
|
196
|
+
* `createKeysetCursor(row, sort)` with the bare sort produces a cursor
|
|
197
|
+
* without the tiebreaker, which `paginateCursor` rejects as missing the
|
|
198
|
+
* id field.
|
|
199
|
+
*/
|
|
200
|
+
createCursor(row, options) {
|
|
201
|
+
return createKeysetCursor(row, this.buildCursorSort(options?.sort), this.cursorSecret, options?.direction ?? "forward");
|
|
202
|
+
}
|
|
191
203
|
/**
|
|
192
204
|
* Finds entities from a query builder (or its built state), applying the
|
|
193
205
|
* filter, sort, select, include and pagination it carries.
|
|
@@ -536,4 +548,3 @@ function validateFieldName(field, name) {
|
|
|
536
548
|
function lowerFirst(value) {
|
|
537
549
|
return value.length === 0 ? value : value[0].toLowerCase() + value.slice(1);
|
|
538
550
|
}
|
|
539
|
-
//# sourceMappingURL=repository.base.js.map
|
|
@@ -90,4 +90,3 @@ export interface RepositoryDelegateOperations<TEntity, TId = string, TCreateInpu
|
|
|
90
90
|
* model delegate accepts at runtime.
|
|
91
91
|
*/
|
|
92
92
|
export declare function toDelegateOperations<TEntity, TId, TCreateInput, TUpdateInput, TWhereInput>(delegate: RepositoryDelegate<TEntity, TId, TCreateInput, TUpdateInput, TWhereInput>): RepositoryDelegateOperations<TEntity, TId, TCreateInput, TUpdateInput, TWhereInput>;
|
|
93
|
-
//# sourceMappingURL=repository.delegate.d.ts.map
|
|
@@ -40,6 +40,9 @@ export declare function toDatabaseOperation(operation: RepositoryOperation | str
|
|
|
40
40
|
* - `P2034` serialization failure → `ERR_DATABASE_TRANSACTION` / 409 (retryable)
|
|
41
41
|
* - `P2024` pool timeout → `ERR_DATABASE_TIMEOUT` / 503
|
|
42
42
|
* - `P1xxx` connection failures → `ERR_DATABASE_CONNECTION` / 503
|
|
43
|
+
* - every other code `normalizeDatabaseError` knows (`P2000` value too
|
|
44
|
+
* long / 400, `P2004` constraint / 409, `P2011` null / 400, `P2014`,
|
|
45
|
+
* `P2015`, `P2018`, `P2028`) → the same status, code and exposure
|
|
43
46
|
*
|
|
44
47
|
* Existing `DatabaseError`s are returned unchanged.
|
|
45
48
|
*/
|
|
@@ -57,4 +60,3 @@ export declare function createTimeoutError(context: Omit<RepositoryErrorContext,
|
|
|
57
60
|
* package accepts.
|
|
58
61
|
*/
|
|
59
62
|
export declare function toErrorMetadata(value?: Readonly<Record<string, unknown>>): ErrorMetadata;
|
|
60
|
-
//# sourceMappingURL=repository.errors.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DatabaseError, DatabaseOperation, ErrorCode, } from "@zudojs/errors";
|
|
2
|
-
import { isDatabaseErrorLike } from "../databaseClient/databaseClient.errors.js";
|
|
2
|
+
import { getPrismaCodeMapping, isDatabaseErrorLike, } from "../databaseClient/databaseClient.errors.js";
|
|
3
3
|
const PRISMA_CODE_PATTERN = /^P\d{4}$/;
|
|
4
4
|
/**
|
|
5
5
|
* Determines whether a value looks like a Prisma known request error.
|
|
@@ -53,6 +53,9 @@ export function toDatabaseOperation(operation) {
|
|
|
53
53
|
* - `P2034` serialization failure → `ERR_DATABASE_TRANSACTION` / 409 (retryable)
|
|
54
54
|
* - `P2024` pool timeout → `ERR_DATABASE_TIMEOUT` / 503
|
|
55
55
|
* - `P1xxx` connection failures → `ERR_DATABASE_CONNECTION` / 503
|
|
56
|
+
* - every other code `normalizeDatabaseError` knows (`P2000` value too
|
|
57
|
+
* long / 400, `P2004` constraint / 409, `P2011` null / 400, `P2014`,
|
|
58
|
+
* `P2015`, `P2018`, `P2028`) → the same status, code and exposure
|
|
56
59
|
*
|
|
57
60
|
* Existing `DatabaseError`s are returned unchanged.
|
|
58
61
|
*/
|
|
@@ -139,6 +142,16 @@ export function mapRepositoryError(error, context) {
|
|
|
139
142
|
statusCode: 503,
|
|
140
143
|
});
|
|
141
144
|
}
|
|
145
|
+
const mapping = getPrismaCodeMapping(error.code);
|
|
146
|
+
if (mapping !== undefined) {
|
|
147
|
+
return new DatabaseError(`${context.model} ${context.operation} failed: ${lowerFirst(mapping.message)}`, {
|
|
148
|
+
...options,
|
|
149
|
+
code: mapping.code,
|
|
150
|
+
statusCode: mapping.statusCode,
|
|
151
|
+
expose: mapping.expose,
|
|
152
|
+
metadata: { ...metadata, kind: mapping.kind },
|
|
153
|
+
});
|
|
154
|
+
}
|
|
142
155
|
return new DatabaseError(`${context.model} ${context.operation} failed.`, {
|
|
143
156
|
...options,
|
|
144
157
|
code: ErrorCode.DATABASE_QUERY,
|
|
@@ -222,6 +235,9 @@ function toMetadataValue(value) {
|
|
|
222
235
|
}
|
|
223
236
|
return String(value);
|
|
224
237
|
}
|
|
238
|
+
function lowerFirst(value) {
|
|
239
|
+
return value.length === 0 ? value : value[0].toLowerCase() + value.slice(1);
|
|
240
|
+
}
|
|
225
241
|
function extractTarget(meta) {
|
|
226
242
|
const target = meta?.["target"];
|
|
227
243
|
if (typeof target === "string") {
|
|
@@ -232,4 +248,3 @@ function extractTarget(meta) {
|
|
|
232
248
|
}
|
|
233
249
|
return undefined;
|
|
234
250
|
}
|
|
235
|
-
//# sourceMappingURL=repository.errors.js.map
|
package/dist/seed/index.d.ts
CHANGED
|
@@ -4,4 +4,3 @@
|
|
|
4
4
|
* Database seed runner with execution tracking (PostgreSQL).
|
|
5
5
|
*/
|
|
6
6
|
export { SeedRunner, createSeedRunner, normalizeSeeds, validateSeed, DEFAULT_SEED_TABLE, DEFAULT_SEED_LOCK, type Seed, type SeedRecord, type SeedResult, type SeedStatus, type SeedRunnerOptions, } from "./seed.runner.js";
|
|
7
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/seed/index.js
CHANGED
|
@@ -3,8 +3,11 @@ import { type SqlDialectName } from "../migration/migration.dialect.js";
|
|
|
3
3
|
import type { RunnerTransactionOptions } from "../migration/migration.types.js";
|
|
4
4
|
/**
|
|
5
5
|
* Defines a database seed operation.
|
|
6
|
+
*
|
|
7
|
+
* `TTransaction` is the transaction client handed to `run` and `rollback`;
|
|
8
|
+
* {@link createSeedRunner} infers it from the database client.
|
|
6
9
|
*/
|
|
7
|
-
export interface Seed {
|
|
10
|
+
export interface Seed<TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext> {
|
|
8
11
|
/**
|
|
9
12
|
* Unique seed name.
|
|
10
13
|
*/
|
|
@@ -16,11 +19,11 @@ export interface Seed {
|
|
|
16
19
|
/**
|
|
17
20
|
* Executes the seed.
|
|
18
21
|
*/
|
|
19
|
-
readonly run: (database:
|
|
22
|
+
readonly run: (database: TTransaction) => Promise<void>;
|
|
20
23
|
/**
|
|
21
24
|
* Optional cleanup operation.
|
|
22
25
|
*/
|
|
23
|
-
readonly rollback?: (database:
|
|
26
|
+
readonly rollback?: (database: TTransaction) => Promise<void>;
|
|
24
27
|
}
|
|
25
28
|
/**
|
|
26
29
|
* Persisted seed execution record.
|
|
@@ -45,8 +48,8 @@ export interface SeedResult {
|
|
|
45
48
|
/**
|
|
46
49
|
* Seed runner status.
|
|
47
50
|
*/
|
|
48
|
-
export interface SeedStatus {
|
|
49
|
-
readonly pending: readonly Seed[];
|
|
51
|
+
export interface SeedStatus<TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext> {
|
|
52
|
+
readonly pending: readonly Seed<TTransaction>[];
|
|
50
53
|
readonly applied: readonly SeedRecord[];
|
|
51
54
|
}
|
|
52
55
|
/**
|
|
@@ -91,7 +94,7 @@ export declare const DEFAULT_SEED_LOCK = "database:seeds";
|
|
|
91
94
|
* lock before deciding what to execute, so two runners started together
|
|
92
95
|
* never apply or revert the same seed twice.
|
|
93
96
|
*/
|
|
94
|
-
export declare class SeedRunner {
|
|
97
|
+
export declare class SeedRunner<TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext> {
|
|
95
98
|
private readonly client;
|
|
96
99
|
private readonly seeds;
|
|
97
100
|
private readonly tableName;
|
|
@@ -99,11 +102,11 @@ export declare class SeedRunner {
|
|
|
99
102
|
private readonly dialect;
|
|
100
103
|
private readonly transactionOptions;
|
|
101
104
|
private readonly perItemTransaction;
|
|
102
|
-
constructor(client: DatabaseClient
|
|
105
|
+
constructor(client: DatabaseClient<TTransaction>, seeds: readonly Seed<TTransaction>[], options?: SeedRunnerOptions);
|
|
103
106
|
/**
|
|
104
107
|
* Returns the seed runner status.
|
|
105
108
|
*/
|
|
106
|
-
status(): Promise<SeedStatus
|
|
109
|
+
status(): Promise<SeedStatus<TTransaction>>;
|
|
107
110
|
/**
|
|
108
111
|
* Executes every pending seed in order.
|
|
109
112
|
*/
|
|
@@ -148,13 +151,12 @@ export declare class SeedRunner {
|
|
|
148
151
|
/**
|
|
149
152
|
* Creates a seed runner.
|
|
150
153
|
*/
|
|
151
|
-
export declare function createSeedRunner(client: DatabaseClient
|
|
154
|
+
export declare function createSeedRunner<TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext>(client: DatabaseClient<TTransaction>, seeds: readonly Seed<TTransaction>[], options?: SeedRunnerOptions): SeedRunner<TTransaction>;
|
|
152
155
|
/**
|
|
153
156
|
* Validates and sorts seed definitions (stable sort on `order`).
|
|
154
157
|
*/
|
|
155
|
-
export declare function normalizeSeeds(seeds: readonly Seed[]): readonly Seed[];
|
|
158
|
+
export declare function normalizeSeeds<TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext>(seeds: readonly Seed<TTransaction>[]): readonly Seed<TTransaction>[];
|
|
156
159
|
/**
|
|
157
160
|
* Validates one seed definition.
|
|
158
161
|
*/
|
|
159
|
-
export declare function validateSeed(seed: Seed): void;
|
|
160
|
-
//# sourceMappingURL=seed.runner.d.ts.map
|
|
162
|
+
export declare function validateSeed<TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext>(seed: Seed<TTransaction>): void;
|
package/dist/seed/seed.runner.js
CHANGED
|
@@ -4,4 +4,3 @@
|
|
|
4
4
|
* Managed transaction execution with retry support.
|
|
5
5
|
*/
|
|
6
6
|
export { TransactionManager, createTransactionManager, withTransaction, withTransactionRetry, createTransactionContext, createTransactionId, getTransactionContextFromError, isTransactionActive, isTransactionCommitted, isTransactionFailed, type TransactionStatus, type TransactionContext, type TransactionOutcome, type TransactionRetryOptions, type ManagedTransactionOptions, } from "./transaction.core.js";
|
|
7
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -4,4 +4,3 @@
|
|
|
4
4
|
* Managed transaction execution with retry support.
|
|
5
5
|
*/
|
|
6
6
|
export { TransactionManager, createTransactionManager, withTransaction, withTransactionRetry, createTransactionContext, createTransactionId, getTransactionContextFromError, isTransactionActive, isTransactionCommitted, isTransactionFailed, } from "./transaction.core.js";
|
|
7
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -5,7 +5,14 @@ import type { TransactionIsolationLevel, TransactionOptions } from "../databaseT
|
|
|
5
5
|
*/
|
|
6
6
|
export type TransactionStatus = "idle" | "active" | "committed" | "rolled-back" | "failed";
|
|
7
7
|
/**
|
|
8
|
-
* Runtime transaction information
|
|
8
|
+
* Runtime transaction information: the immutable status record
|
|
9
|
+
* `TransactionManager.run` reports in its `TransactionOutcome` and attaches
|
|
10
|
+
* to failures (see `getTransactionContextFromError`).
|
|
11
|
+
*
|
|
12
|
+
* Not the `TransactionContext` of `@zudojs/transactions`, which is the
|
|
13
|
+
* AsyncLocalStorage store its manager propagates transactions through.
|
|
14
|
+
* The two packages share the name but not the concept; import from the
|
|
15
|
+
* package whose manager you use.
|
|
9
16
|
*/
|
|
10
17
|
export interface TransactionContext {
|
|
11
18
|
readonly transactionId: string;
|
|
@@ -64,15 +71,18 @@ export interface TransactionRetryOptions extends ManagedTransactionOptions {
|
|
|
64
71
|
export declare function createTransactionId(): string;
|
|
65
72
|
/**
|
|
66
73
|
* Manages transaction execution and lifecycle metadata.
|
|
74
|
+
*
|
|
75
|
+
* `TTransaction` is the transaction client handed to callbacks, taken from
|
|
76
|
+
* the {@link DatabaseClient} the manager wraps.
|
|
67
77
|
*/
|
|
68
|
-
export declare class TransactionManager {
|
|
78
|
+
export declare class TransactionManager<TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext> {
|
|
69
79
|
private readonly client;
|
|
70
|
-
constructor(client: DatabaseClient);
|
|
80
|
+
constructor(client: DatabaseClient<TTransaction>);
|
|
71
81
|
/**
|
|
72
82
|
* Executes a callback inside a managed transaction and returns its
|
|
73
83
|
* result.
|
|
74
84
|
*/
|
|
75
|
-
execute<TResult>(callback: (transaction:
|
|
85
|
+
execute<TResult>(callback: (transaction: TTransaction, context: TransactionContext) => Promise<TResult>, options?: ManagedTransactionOptions): Promise<TResult>;
|
|
76
86
|
/**
|
|
77
87
|
* Executes a callback inside a managed transaction and returns the
|
|
78
88
|
* result together with the final context (`status: "committed"`).
|
|
@@ -86,16 +96,16 @@ export declare class TransactionManager {
|
|
|
86
96
|
* `NotFoundError` or `DomainError`) rolls the transaction back and is
|
|
87
97
|
* rethrown as the same, unmodified instance.
|
|
88
98
|
*/
|
|
89
|
-
run<TResult>(callback: (transaction:
|
|
99
|
+
run<TResult>(callback: (transaction: TTransaction, context: TransactionContext) => Promise<TResult>, options?: ManagedTransactionOptions): Promise<TransactionOutcome<TResult>>;
|
|
90
100
|
/**
|
|
91
101
|
* Returns the database client used by the manager.
|
|
92
102
|
*/
|
|
93
|
-
getClient(): DatabaseClient
|
|
103
|
+
getClient(): DatabaseClient<TTransaction>;
|
|
94
104
|
}
|
|
95
105
|
/**
|
|
96
106
|
* Creates a transaction manager.
|
|
97
107
|
*/
|
|
98
|
-
export declare function createTransactionManager(client: DatabaseClient): TransactionManager
|
|
108
|
+
export declare function createTransactionManager<TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext>(client: DatabaseClient<TTransaction>): TransactionManager<TTransaction>;
|
|
99
109
|
/**
|
|
100
110
|
* Executes a managed database transaction.
|
|
101
111
|
*
|
|
@@ -104,7 +114,7 @@ export declare function createTransactionManager(client: DatabaseClient): Transa
|
|
|
104
114
|
* validation, not-found, ...) propagates unchanged; driver and database
|
|
105
115
|
* failures and any other thrown value become a `DatabaseError`.
|
|
106
116
|
*/
|
|
107
|
-
export declare function withTransaction<TResult>(client: DatabaseClient
|
|
117
|
+
export declare function withTransaction<TResult, TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext>(client: DatabaseClient<TTransaction>, callback: (transaction: TTransaction, context: TransactionContext) => Promise<TResult>, options?: ManagedTransactionOptions): Promise<TResult>;
|
|
108
118
|
/**
|
|
109
119
|
* Executes a transaction with retry support.
|
|
110
120
|
*
|
|
@@ -112,9 +122,16 @@ export declare function withTransaction<TResult>(client: DatabaseClient, callbac
|
|
|
112
122
|
* callback must be idempotent with respect to any side effects performed
|
|
113
123
|
* outside the transaction client (for example, sending emails).
|
|
114
124
|
*/
|
|
115
|
-
export declare function withTransactionRetry<TResult>(client: DatabaseClient
|
|
125
|
+
export declare function withTransactionRetry<TResult, TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext>(client: DatabaseClient<TTransaction>, callback: (transaction: TTransaction, context: TransactionContext) => Promise<TResult>, options?: TransactionRetryOptions): Promise<TResult>;
|
|
116
126
|
/**
|
|
117
|
-
* Creates an immutable transaction
|
|
127
|
+
* Creates an immutable transaction status record (see
|
|
128
|
+
* {@link TransactionContext}), as `TransactionManager.run` does for every
|
|
129
|
+
* transaction it opens.
|
|
130
|
+
*
|
|
131
|
+
* Unrelated to `createTransactionContext` from `@zudojs/transactions`,
|
|
132
|
+
* which creates the AsyncLocalStorage propagation store that package's
|
|
133
|
+
* manager runs callbacks in. This one holds no transaction and propagates
|
|
134
|
+
* nothing; it is data for logging and error reporting.
|
|
118
135
|
*/
|
|
119
136
|
export declare function createTransactionContext(options?: ManagedTransactionOptions): TransactionContext;
|
|
120
137
|
/**
|
|
@@ -134,4 +151,3 @@ export declare function isTransactionCommitted(context: TransactionContext): boo
|
|
|
134
151
|
* Determines whether a transaction failed.
|
|
135
152
|
*/
|
|
136
153
|
export declare function isTransactionFailed(context: TransactionContext): boolean;
|
|
137
|
-
//# sourceMappingURL=transaction.core.d.ts.map
|
|
@@ -12,6 +12,9 @@ export function createTransactionId() {
|
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Manages transaction execution and lifecycle metadata.
|
|
15
|
+
*
|
|
16
|
+
* `TTransaction` is the transaction client handed to callbacks, taken from
|
|
17
|
+
* the {@link DatabaseClient} the manager wraps.
|
|
15
18
|
*/
|
|
16
19
|
export class TransactionManager {
|
|
17
20
|
client;
|
|
@@ -120,7 +123,14 @@ export async function withTransactionRetry(client, callback, options = {}) {
|
|
|
120
123
|
}
|
|
121
124
|
}
|
|
122
125
|
/**
|
|
123
|
-
* Creates an immutable transaction
|
|
126
|
+
* Creates an immutable transaction status record (see
|
|
127
|
+
* {@link TransactionContext}), as `TransactionManager.run` does for every
|
|
128
|
+
* transaction it opens.
|
|
129
|
+
*
|
|
130
|
+
* Unrelated to `createTransactionContext` from `@zudojs/transactions`,
|
|
131
|
+
* which creates the AsyncLocalStorage propagation store that package's
|
|
132
|
+
* manager runs callbacks in. This one holds no transaction and propagates
|
|
133
|
+
* nothing; it is data for logging and error reporting.
|
|
124
134
|
*/
|
|
125
135
|
export function createTransactionContext(options = {}) {
|
|
126
136
|
return Object.freeze({
|
|
@@ -201,4 +211,3 @@ function sleep(milliseconds) {
|
|
|
201
211
|
setTimeout(resolve, milliseconds);
|
|
202
212
|
});
|
|
203
213
|
}
|
|
204
|
-
//# sourceMappingURL=transaction.core.js.map
|
package/dist/unitOfWork/index.js
CHANGED