@zudojs/database 0.1.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +225 -17
- package/dist/cache/cache.memory.d.ts +167 -0
- package/dist/cache/cache.memory.js +186 -40
- package/dist/cache/index.d.ts +2 -2
- package/dist/cache/index.js +2 -2
- package/dist/database/database.core.d.ts +91 -0
- package/dist/database/database.core.js +21 -4
- package/dist/databaseClient/databaseClient.core.d.ts +171 -14
- package/dist/databaseClient/databaseClient.core.js +350 -70
- package/dist/databaseClient/databaseClient.errors.d.ts +112 -0
- package/dist/databaseClient/databaseClient.errors.js +425 -0
- package/dist/databaseClient/index.d.ts +2 -1
- package/dist/databaseClient/index.js +2 -1
- package/dist/databaseConnection/databaseConnection.manager.d.ts +163 -0
- package/dist/databaseConnection/databaseConnection.manager.js +138 -76
- package/dist/databaseConnection/index.d.ts +1 -1
- package/dist/databaseType/databaseType.type.d.ts +224 -0
- package/dist/databaseType/databaseType.type.js +0 -35
- package/dist/health/health.check.d.ts +74 -0
- package/dist/health/health.check.js +78 -47
- package/dist/health/index.d.ts +1 -1
- package/dist/health/index.js +1 -1
- package/dist/index.d.ts +14 -14
- package/dist/index.js +11 -11
- package/dist/locks/index.d.ts +2 -2
- package/dist/locks/index.js +2 -2
- package/dist/locks/locks.core.d.ts +132 -0
- package/dist/locks/locks.core.js +150 -85
- package/dist/migration/index.d.ts +3 -1
- package/dist/migration/index.js +2 -0
- package/dist/migration/migration.dialect.d.ts +65 -0
- package/dist/migration/migration.dialect.js +63 -0
- package/dist/migration/migration.helpers.d.ts +65 -0
- package/dist/migration/migration.helpers.js +60 -18
- package/dist/migration/migration.runner.d.ts +75 -0
- package/dist/migration/migration.runner.js +195 -107
- package/dist/migration/migration.types.d.ts +85 -0
- package/dist/pagination/index.d.ts +2 -1
- package/dist/pagination/index.js +2 -1
- package/dist/pagination/pagination.core.d.ts +163 -0
- package/dist/pagination/pagination.core.js +78 -9
- package/dist/pagination/pagination.keyset.d.ts +55 -0
- package/dist/pagination/pagination.keyset.js +108 -0
- package/dist/queryBuilder/index.d.ts +4 -3
- package/dist/queryBuilder/index.js +3 -2
- package/dist/queryBuilder/queryBuilder.core.d.ts +178 -0
- package/dist/queryBuilder/queryBuilder.core.js +92 -14
- package/dist/queryBuilder/queryBuilder.factory.d.ts +6 -0
- package/dist/queryBuilder/queryBuilder.factory.js +0 -25
- package/dist/queryBuilder/queryBuilder.filter.d.ts +170 -0
- package/dist/queryBuilder/queryBuilder.filter.js +191 -30
- package/dist/queryBuilder/queryBuilder.prisma.d.ts +60 -0
- package/dist/queryBuilder/queryBuilder.prisma.js +233 -0
- package/dist/queryBuilder/queryBuilder.type.d.ts +48 -0
- package/dist/relations/index.d.ts +1 -1
- package/dist/relations/index.js +1 -1
- package/dist/relations/relations.definition.d.ts +184 -0
- package/dist/relations/relations.definition.js +186 -19
- package/dist/repository/index.d.ts +2 -1
- package/dist/repository/index.js +1 -0
- package/dist/repository/repository.base.d.ts +283 -0
- package/dist/repository/repository.base.js +370 -89
- package/dist/repository/repository.errors.d.ts +60 -0
- package/dist/repository/repository.errors.js +235 -0
- package/dist/seed/index.d.ts +2 -2
- package/dist/seed/index.js +1 -1
- package/dist/seed/seed.runner.d.ts +160 -0
- package/dist/seed/seed.runner.js +194 -225
- package/dist/transaction/index.d.ts +1 -1
- package/dist/transaction/index.js +1 -1
- package/dist/transaction/transaction.core.d.ts +117 -0
- package/dist/transaction/transaction.core.js +83 -56
- package/dist/unitOfWork/unitOfWork.core.d.ts +44 -0
- package/dist/unitOfWork/unitOfWork.core.js +9 -20
- package/package.json +44 -24
- package/dist/cache/cache.memory.d.ts.map +0 -1
- package/dist/cache/cache.memory.js.map +0 -1
- package/dist/cache/index.d.ts.map +0 -1
- package/dist/cache/index.js.map +0 -1
- package/dist/database/database.core.d.ts.map +0 -1
- package/dist/database/database.core.js.map +0 -1
- package/dist/database/index.d.ts.map +0 -1
- package/dist/database/index.js.map +0 -1
- package/dist/databaseClient/databaseClient.core.d.ts.map +0 -1
- package/dist/databaseClient/databaseClient.core.js.map +0 -1
- package/dist/databaseClient/databaseClient.logger.d.ts.map +0 -1
- package/dist/databaseClient/databaseClient.logger.js.map +0 -1
- package/dist/databaseClient/index.d.ts.map +0 -1
- package/dist/databaseClient/index.js.map +0 -1
- package/dist/databaseConnection/databaseConnection.manager.d.ts.map +0 -1
- package/dist/databaseConnection/databaseConnection.manager.js.map +0 -1
- package/dist/databaseConnection/index.d.ts.map +0 -1
- package/dist/databaseConnection/index.js.map +0 -1
- package/dist/databaseType/databaseType.type.d.ts.map +0 -1
- package/dist/databaseType/databaseType.type.js.map +0 -1
- package/dist/databaseType/index.d.ts.map +0 -1
- package/dist/databaseType/index.js.map +0 -1
- package/dist/health/health.check.d.ts.map +0 -1
- package/dist/health/health.check.js.map +0 -1
- package/dist/health/index.d.ts.map +0 -1
- package/dist/health/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/locks/index.d.ts.map +0 -1
- package/dist/locks/index.js.map +0 -1
- package/dist/locks/locks.core.d.ts.map +0 -1
- package/dist/locks/locks.core.js.map +0 -1
- package/dist/migration/index.d.ts.map +0 -1
- package/dist/migration/index.js.map +0 -1
- package/dist/migration/migration.helpers.d.ts.map +0 -1
- package/dist/migration/migration.helpers.js.map +0 -1
- package/dist/migration/migration.runner.d.ts.map +0 -1
- package/dist/migration/migration.runner.js.map +0 -1
- package/dist/migration/migration.types.d.ts.map +0 -1
- package/dist/migration/migration.types.js.map +0 -1
- package/dist/pagination/index.d.ts.map +0 -1
- package/dist/pagination/index.js.map +0 -1
- package/dist/pagination/pagination.core.d.ts.map +0 -1
- package/dist/pagination/pagination.core.js.map +0 -1
- package/dist/queryBuilder/index.d.ts.map +0 -1
- package/dist/queryBuilder/index.js.map +0 -1
- package/dist/queryBuilder/queryBuilder.core.d.ts.map +0 -1
- package/dist/queryBuilder/queryBuilder.core.js.map +0 -1
- package/dist/queryBuilder/queryBuilder.factory.d.ts.map +0 -1
- package/dist/queryBuilder/queryBuilder.factory.js.map +0 -1
- package/dist/queryBuilder/queryBuilder.filter.d.ts.map +0 -1
- package/dist/queryBuilder/queryBuilder.filter.js.map +0 -1
- package/dist/queryBuilder/queryBuilder.type.d.ts.map +0 -1
- package/dist/queryBuilder/queryBuilder.type.js.map +0 -1
- package/dist/relations/index.d.ts.map +0 -1
- package/dist/relations/index.js.map +0 -1
- package/dist/relations/relations.definition.d.ts.map +0 -1
- package/dist/relations/relations.definition.js.map +0 -1
- package/dist/repository/index.d.ts.map +0 -1
- package/dist/repository/index.js.map +0 -1
- package/dist/repository/repository.base.d.ts.map +0 -1
- package/dist/repository/repository.base.js.map +0 -1
- package/dist/seed/index.d.ts.map +0 -1
- package/dist/seed/index.js.map +0 -1
- package/dist/seed/seed.runner.d.ts.map +0 -1
- package/dist/seed/seed.runner.js.map +0 -1
- package/dist/transaction/index.d.ts.map +0 -1
- package/dist/transaction/index.js.map +0 -1
- package/dist/transaction/transaction.core.d.ts.map +0 -1
- package/dist/transaction/transaction.core.js.map +0 -1
- package/dist/unitOfWork/index.d.ts.map +0 -1
- package/dist/unitOfWork/index.js.map +0 -1
- package/dist/unitOfWork/unitOfWork.core.d.ts.map +0 -1
- package/dist/unitOfWork/unitOfWork.core.js.map +0 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { PaginationInput, SortInput } from "../databaseType/databaseType.type.js";
|
|
2
|
+
import { type ToPrismaIncludeOptions } from "../relations/relations.definition.js";
|
|
3
|
+
import type { QueryBuilderState, QueryFilter } from "./queryBuilder.type.js";
|
|
4
|
+
/**
|
|
5
|
+
* A Prisma-compatible `where` object.
|
|
6
|
+
*/
|
|
7
|
+
export type PrismaWhere = Record<string, unknown>;
|
|
8
|
+
/**
|
|
9
|
+
* Prisma-compatible query arguments produced from a builder state.
|
|
10
|
+
*/
|
|
11
|
+
export interface PrismaQueryArgs {
|
|
12
|
+
readonly where?: PrismaWhere;
|
|
13
|
+
readonly orderBy?: readonly Record<string, "asc" | "desc">[];
|
|
14
|
+
readonly skip?: number;
|
|
15
|
+
readonly take?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Field projection. When the state carries both `select` and `include`,
|
|
18
|
+
* the relations are folded in here (Prisma does not accept both keys on
|
|
19
|
+
* one level), so values may be nested include objects.
|
|
20
|
+
*/
|
|
21
|
+
readonly select?: Record<string, boolean | Record<string, unknown>>;
|
|
22
|
+
readonly include?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Options for {@link toPrismaArgs}.
|
|
26
|
+
*/
|
|
27
|
+
export interface ToPrismaArgsOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Options forwarded to {@link toPrismaInclude} for `include` entries.
|
|
30
|
+
*/
|
|
31
|
+
readonly include?: ToPrismaIncludeOptions;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Translates a database-neutral {@link QueryFilter} into a Prisma `where`
|
|
35
|
+
* object.
|
|
36
|
+
*
|
|
37
|
+
* Returns `undefined` when the filter carries no constraints. Unknown
|
|
38
|
+
* operators and unsafe field names throw a `TypeError`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function toPrismaWhere(filter?: QueryFilter): PrismaWhere | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Translates a builder state into Prisma `findMany`-style arguments.
|
|
43
|
+
*/
|
|
44
|
+
export declare function toPrismaArgs<TField extends string = string>(state: QueryBuilderState<TField>, options?: ToPrismaArgsOptions): PrismaQueryArgs;
|
|
45
|
+
/**
|
|
46
|
+
* Translates sort definitions into Prisma `orderBy` entries.
|
|
47
|
+
*/
|
|
48
|
+
export declare function toPrismaOrderBy<TField extends string = string>(sort?: readonly SortInput<TField>[]): Record<string, "asc" | "desc">[] | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Translates a field list into a Prisma `select` object.
|
|
51
|
+
*/
|
|
52
|
+
export declare function toPrismaSelect(fields: readonly string[]): Record<string, boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Resolves pagination / offset into Prisma `skip` and `take`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function toPrismaSkipTake(pagination?: PaginationInput, offset?: number): {
|
|
57
|
+
readonly skip?: number;
|
|
58
|
+
readonly take?: number;
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=queryBuilder.prisma.d.ts.map
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { normalizePagination } from "../pagination/pagination.core.js";
|
|
2
|
+
import { toPrismaInclude, } from "../relations/relations.definition.js";
|
|
3
|
+
const FIELD_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
4
|
+
const FORBIDDEN_FIELDS = new Set(["__proto__", "constructor", "prototype"]);
|
|
5
|
+
const SIMPLE_OPERATORS = new Set([
|
|
6
|
+
"equals",
|
|
7
|
+
"not",
|
|
8
|
+
"in",
|
|
9
|
+
"notIn",
|
|
10
|
+
"lt",
|
|
11
|
+
"lte",
|
|
12
|
+
"gt",
|
|
13
|
+
"gte",
|
|
14
|
+
"contains",
|
|
15
|
+
"startsWith",
|
|
16
|
+
"endsWith",
|
|
17
|
+
]);
|
|
18
|
+
const RELATION_OPERATORS = new Set([
|
|
19
|
+
"some",
|
|
20
|
+
"every",
|
|
21
|
+
"none",
|
|
22
|
+
"is",
|
|
23
|
+
"isNot",
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* Translates a database-neutral {@link QueryFilter} into a Prisma `where`
|
|
27
|
+
* object.
|
|
28
|
+
*
|
|
29
|
+
* Returns `undefined` when the filter carries no constraints. Unknown
|
|
30
|
+
* operators and unsafe field names throw a `TypeError`.
|
|
31
|
+
*/
|
|
32
|
+
export function toPrismaWhere(filter) {
|
|
33
|
+
if (!filter || typeof filter !== "object") {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
const where = {};
|
|
37
|
+
const extraAnd = [];
|
|
38
|
+
for (const condition of filter.conditions ?? []) {
|
|
39
|
+
const entry = translateCondition(condition);
|
|
40
|
+
const fieldWhere = entry[condition.field];
|
|
41
|
+
const existing = where[condition.field];
|
|
42
|
+
if (existing === undefined) {
|
|
43
|
+
where[condition.field] = fieldWhere;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const [operatorKey] = Object.keys(fieldWhere);
|
|
47
|
+
if (isPlainObject(existing) &&
|
|
48
|
+
operatorKey !== undefined &&
|
|
49
|
+
!(operatorKey in existing)) {
|
|
50
|
+
where[condition.field] = { ...existing, ...fieldWhere };
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
extraAnd.push(entry);
|
|
54
|
+
}
|
|
55
|
+
const andChildren = [
|
|
56
|
+
...(filter.and ?? []).map((child) => toPrismaWhere(child)),
|
|
57
|
+
...extraAnd,
|
|
58
|
+
].filter((child) => child !== undefined);
|
|
59
|
+
if (andChildren.length > 0) {
|
|
60
|
+
where["AND"] = andChildren;
|
|
61
|
+
}
|
|
62
|
+
const orChildren = (filter.or ?? [])
|
|
63
|
+
.map((child) => toPrismaWhere(child))
|
|
64
|
+
.filter((child) => child !== undefined);
|
|
65
|
+
if (orChildren.length > 0) {
|
|
66
|
+
where["OR"] = orChildren;
|
|
67
|
+
}
|
|
68
|
+
if (filter.not) {
|
|
69
|
+
const negated = toPrismaWhere(filter.not);
|
|
70
|
+
if (negated !== undefined) {
|
|
71
|
+
where["NOT"] = negated;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return Object.keys(where).length === 0 ? undefined : where;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Translates a builder state into Prisma `findMany`-style arguments.
|
|
78
|
+
*/
|
|
79
|
+
export function toPrismaArgs(state, options = {}) {
|
|
80
|
+
const args = {};
|
|
81
|
+
const where = toPrismaWhere(state.filter);
|
|
82
|
+
if (where !== undefined) {
|
|
83
|
+
args.where = where;
|
|
84
|
+
}
|
|
85
|
+
const orderBy = toPrismaOrderBy(state.sort);
|
|
86
|
+
if (orderBy !== undefined) {
|
|
87
|
+
args.orderBy = orderBy;
|
|
88
|
+
}
|
|
89
|
+
const { skip, take } = toPrismaSkipTake(state.pagination, state.offset);
|
|
90
|
+
if (skip !== undefined) {
|
|
91
|
+
args.skip = skip;
|
|
92
|
+
}
|
|
93
|
+
if (take !== undefined) {
|
|
94
|
+
args.take = take;
|
|
95
|
+
}
|
|
96
|
+
const select = state.select && state.select.length > 0
|
|
97
|
+
? toPrismaSelect(state.select)
|
|
98
|
+
: undefined;
|
|
99
|
+
const include = state.include && state.include.length > 0
|
|
100
|
+
? toPrismaInclude(state.include, options.include)
|
|
101
|
+
: undefined;
|
|
102
|
+
if (select !== undefined && include !== undefined) {
|
|
103
|
+
// Prisma rejects `select` and `include` on the same level; relations
|
|
104
|
+
// are folded into the projection instead.
|
|
105
|
+
args.select = {
|
|
106
|
+
...select,
|
|
107
|
+
...include,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
else if (select !== undefined) {
|
|
111
|
+
args.select = select;
|
|
112
|
+
}
|
|
113
|
+
else if (include !== undefined) {
|
|
114
|
+
args.include = include;
|
|
115
|
+
}
|
|
116
|
+
return args;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Translates sort definitions into Prisma `orderBy` entries.
|
|
120
|
+
*/
|
|
121
|
+
export function toPrismaOrderBy(sort) {
|
|
122
|
+
if (!sort || sort.length === 0) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
return sort.map((entry) => {
|
|
126
|
+
validateFieldName(entry.field);
|
|
127
|
+
if (entry.direction !== "asc" && entry.direction !== "desc") {
|
|
128
|
+
throw new TypeError(`Sort field "${entry.field}" has an invalid direction.`);
|
|
129
|
+
}
|
|
130
|
+
return { [entry.field]: entry.direction };
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Translates a field list into a Prisma `select` object.
|
|
135
|
+
*/
|
|
136
|
+
export function toPrismaSelect(fields) {
|
|
137
|
+
const select = {};
|
|
138
|
+
for (const field of fields) {
|
|
139
|
+
validateFieldName(field);
|
|
140
|
+
select[field] = true;
|
|
141
|
+
}
|
|
142
|
+
return select;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Resolves pagination / offset into Prisma `skip` and `take`.
|
|
146
|
+
*/
|
|
147
|
+
export function toPrismaSkipTake(pagination, offset) {
|
|
148
|
+
if (offset !== undefined) {
|
|
149
|
+
if (!Number.isFinite(offset) || offset < 0) {
|
|
150
|
+
throw new TypeError("Query offset must be a non-negative number.");
|
|
151
|
+
}
|
|
152
|
+
const take = pagination?.limit !== undefined
|
|
153
|
+
? normalizePagination(pagination).limit
|
|
154
|
+
: undefined;
|
|
155
|
+
return { skip: Math.floor(offset), take };
|
|
156
|
+
}
|
|
157
|
+
if (!pagination) {
|
|
158
|
+
return {};
|
|
159
|
+
}
|
|
160
|
+
const normalized = normalizePagination(pagination);
|
|
161
|
+
return { skip: normalized.offset, take: normalized.limit };
|
|
162
|
+
}
|
|
163
|
+
function translateCondition(condition) {
|
|
164
|
+
if (!condition || typeof condition !== "object") {
|
|
165
|
+
throw new TypeError("Invalid query condition.");
|
|
166
|
+
}
|
|
167
|
+
validateFieldName(condition.field);
|
|
168
|
+
const { field, operator, value } = condition;
|
|
169
|
+
if (SIMPLE_OPERATORS.has(operator)) {
|
|
170
|
+
if ((operator === "in" || operator === "notIn") && !Array.isArray(value)) {
|
|
171
|
+
throw new TypeError(`Operator "${operator}" on field "${field}" requires an array value.`);
|
|
172
|
+
}
|
|
173
|
+
if ((operator === "contains" ||
|
|
174
|
+
operator === "startsWith" ||
|
|
175
|
+
operator === "endsWith") &&
|
|
176
|
+
typeof value !== "string") {
|
|
177
|
+
throw new TypeError(`Operator "${operator}" on field "${field}" requires a string value.`);
|
|
178
|
+
}
|
|
179
|
+
return { [field]: { [operator]: value } };
|
|
180
|
+
}
|
|
181
|
+
switch (operator) {
|
|
182
|
+
case "isNull":
|
|
183
|
+
return { [field]: { equals: null } };
|
|
184
|
+
case "isNotNull":
|
|
185
|
+
return { [field]: { not: null } };
|
|
186
|
+
case "like":
|
|
187
|
+
return { [field]: translatePattern(field, value) };
|
|
188
|
+
default:
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
if (RELATION_OPERATORS.has(operator)) {
|
|
192
|
+
const nested = toPrismaWhere(value) ?? {};
|
|
193
|
+
return { [field]: { [operator]: nested } };
|
|
194
|
+
}
|
|
195
|
+
throw new TypeError(`Unsupported query operator "${String(operator)}" on field "${field}".`);
|
|
196
|
+
}
|
|
197
|
+
function translatePattern(field, value) {
|
|
198
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
199
|
+
throw new TypeError(`Operator "like" on field "${field}" requires a pattern.`);
|
|
200
|
+
}
|
|
201
|
+
const leading = value.startsWith("%");
|
|
202
|
+
const trailing = value.endsWith("%");
|
|
203
|
+
// The lookbehind pins the trailing match to the start of a `%` run; plain
|
|
204
|
+
// `%+$` retries from every `%` in an interior run, which is quadratic.
|
|
205
|
+
const inner = value.replace(/^%+/, "").replace(/(?<!%)%+$/, "");
|
|
206
|
+
if (inner.length === 0 || inner.includes("%") || inner.includes("_")) {
|
|
207
|
+
throw new TypeError(`Pattern "${value}" on field "${field}" is not supported; only leading/trailing % wildcards are allowed.`);
|
|
208
|
+
}
|
|
209
|
+
if (leading && trailing) {
|
|
210
|
+
return { contains: inner };
|
|
211
|
+
}
|
|
212
|
+
if (trailing) {
|
|
213
|
+
return { startsWith: inner };
|
|
214
|
+
}
|
|
215
|
+
if (leading) {
|
|
216
|
+
return { endsWith: inner };
|
|
217
|
+
}
|
|
218
|
+
return { equals: inner };
|
|
219
|
+
}
|
|
220
|
+
function validateFieldName(field) {
|
|
221
|
+
if (typeof field !== "string" ||
|
|
222
|
+
!FIELD_PATTERN.test(field) ||
|
|
223
|
+
FORBIDDEN_FIELDS.has(field)) {
|
|
224
|
+
throw new TypeError(`Invalid query field name "${String(field)}".`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function isPlainObject(value) {
|
|
228
|
+
return (value !== null &&
|
|
229
|
+
typeof value === "object" &&
|
|
230
|
+
!Array.isArray(value) &&
|
|
231
|
+
!(value instanceof Date));
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=queryBuilder.prisma.js.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { PaginationInput, SortInput } from "../databaseType/databaseType.type.js";
|
|
2
|
+
import type { RelationInclude } from "../relations/relations.definition.js";
|
|
3
|
+
export type { PaginationInput, QueryOptions, SortDirection, SortInput, } from "../databaseType/databaseType.type.js";
|
|
4
|
+
/**
|
|
5
|
+
* Supported query operators.
|
|
6
|
+
*
|
|
7
|
+
* - `like` matches a SQL-style pattern using `%` wildcards at either end.
|
|
8
|
+
* - `some` / `every` / `none` apply a nested {@link QueryFilter} to a
|
|
9
|
+
* collection relation; `is` / `isNot` apply one to a single relation.
|
|
10
|
+
*/
|
|
11
|
+
export type QueryOperator = "equals" | "not" | "in" | "notIn" | "lt" | "lte" | "gt" | "gte" | "contains" | "startsWith" | "endsWith" | "like" | "isNull" | "isNotNull" | "some" | "every" | "none" | "is" | "isNot";
|
|
12
|
+
/**
|
|
13
|
+
* Operators that take a nested filter targeting a relation.
|
|
14
|
+
*/
|
|
15
|
+
export type RelationOperator = "some" | "every" | "none" | "is" | "isNot";
|
|
16
|
+
/**
|
|
17
|
+
* Generic filter condition.
|
|
18
|
+
*/
|
|
19
|
+
export interface QueryCondition {
|
|
20
|
+
readonly field: string;
|
|
21
|
+
readonly operator: QueryOperator;
|
|
22
|
+
readonly value?: unknown;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generic logical filter.
|
|
26
|
+
*/
|
|
27
|
+
export interface QueryFilter {
|
|
28
|
+
readonly conditions?: readonly QueryCondition[];
|
|
29
|
+
readonly and?: readonly QueryFilter[];
|
|
30
|
+
readonly or?: readonly QueryFilter[];
|
|
31
|
+
readonly not?: QueryFilter;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Query builder state.
|
|
35
|
+
*/
|
|
36
|
+
export interface QueryBuilderState<TField extends string = string> {
|
|
37
|
+
readonly filter?: QueryFilter;
|
|
38
|
+
readonly pagination?: PaginationInput;
|
|
39
|
+
/**
|
|
40
|
+
* Explicit row offset. Takes precedence over `pagination.page` when both
|
|
41
|
+
* are present.
|
|
42
|
+
*/
|
|
43
|
+
readonly offset?: number;
|
|
44
|
+
readonly sort?: readonly SortInput<TField>[];
|
|
45
|
+
readonly select?: readonly TField[];
|
|
46
|
+
readonly include?: readonly RelationInclude[];
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=queryBuilder.type.d.ts.map
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Entity relation definitions and registry.
|
|
5
5
|
*/
|
|
6
|
-
export { oneToOne, oneToMany, manyToOne, manyToMany, includeRelation, includeRelations, RelationRegistry, createRelationRegistry, validateRelation, isRelationType, isCollectionRelation, isSingleRelation, type RelationDefinition, type RelationType, type RelationLoadOptions, type RelationInclude, } from "./relations.definition.js";
|
|
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
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/relations/index.js
CHANGED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Entity relation definitions and registry.
|
|
5
5
|
*/
|
|
6
|
-
export { oneToOne, oneToMany, manyToOne, manyToMany, includeRelation, includeRelations, RelationRegistry, createRelationRegistry, validateRelation, isRelationType, isCollectionRelation, isSingleRelation, } from "./relations.definition.js";
|
|
6
|
+
export { oneToOne, oneToMany, manyToOne, manyToMany, includeRelation, includeRelations, RelationRegistry, createRelationRegistry, validateRelation, validateInclude, toPrismaInclude, DEFAULT_INCLUDE_DEPTH, isRelationType, isCollectionRelation, isSingleRelation, } from "./relations.definition.js";
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import type { DatabaseOperationOptions } from "../databaseType/databaseType.type.js";
|
|
2
|
+
/**
|
|
3
|
+
* Describes a relation between two database entities.
|
|
4
|
+
*/
|
|
5
|
+
export interface RelationDefinition<TParent = unknown, TChild = unknown> {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly parent: TParent;
|
|
8
|
+
readonly child: TChild;
|
|
9
|
+
readonly type: RelationType;
|
|
10
|
+
readonly foreignKey: string;
|
|
11
|
+
readonly referencedKey: string;
|
|
12
|
+
readonly nullable?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Supported database relation types.
|
|
16
|
+
*/
|
|
17
|
+
export type RelationType = "one-to-one" | "one-to-many" | "many-to-one" | "many-to-many";
|
|
18
|
+
/**
|
|
19
|
+
* Generic relation loading options.
|
|
20
|
+
*/
|
|
21
|
+
export interface RelationLoadOptions extends DatabaseOperationOptions {
|
|
22
|
+
/**
|
|
23
|
+
* When `false`, collection relations resolved through a registry are
|
|
24
|
+
* filtered to rows whose soft-delete field is null.
|
|
25
|
+
*/
|
|
26
|
+
readonly includeDeleted?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Maximum nesting depth allowed for includes (default 5).
|
|
29
|
+
*/
|
|
30
|
+
readonly depth?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Default maximum include depth.
|
|
34
|
+
*/
|
|
35
|
+
export declare const DEFAULT_INCLUDE_DEPTH = 5;
|
|
36
|
+
/**
|
|
37
|
+
* Options for {@link toPrismaInclude}.
|
|
38
|
+
*/
|
|
39
|
+
export interface ToPrismaIncludeOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Registry used to validate relation names and detect cycles. When
|
|
42
|
+
* supplied, `parent` identifies the root model.
|
|
43
|
+
*/
|
|
44
|
+
readonly registry?: RelationRegistry;
|
|
45
|
+
/**
|
|
46
|
+
* The model the top-level includes belong to (required with `registry`).
|
|
47
|
+
*/
|
|
48
|
+
readonly parent?: unknown;
|
|
49
|
+
/**
|
|
50
|
+
* Maximum nesting depth (default {@link DEFAULT_INCLUDE_DEPTH}).
|
|
51
|
+
*/
|
|
52
|
+
readonly depth?: number;
|
|
53
|
+
/**
|
|
54
|
+
* When `false`, collection relations are filtered on `softDeleteField`.
|
|
55
|
+
*/
|
|
56
|
+
readonly includeDeleted?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Soft-delete column applied when `includeDeleted` is `false`
|
|
59
|
+
* (default `deletedAt`).
|
|
60
|
+
*/
|
|
61
|
+
readonly softDeleteField?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Describes a relation that can be included in a query.
|
|
65
|
+
*/
|
|
66
|
+
export interface RelationInclude {
|
|
67
|
+
readonly relation: string;
|
|
68
|
+
readonly select?: readonly string[];
|
|
69
|
+
readonly include?: readonly RelationInclude[];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Creates a one-to-one relation definition.
|
|
73
|
+
*/
|
|
74
|
+
export declare function oneToOne<TParent = unknown, TChild = unknown>(definition: Omit<RelationDefinition<TParent, TChild>, "type">): RelationDefinition<TParent, TChild>;
|
|
75
|
+
/**
|
|
76
|
+
* Creates a one-to-many relation definition.
|
|
77
|
+
*/
|
|
78
|
+
export declare function oneToMany<TParent = unknown, TChild = unknown>(definition: Omit<RelationDefinition<TParent, TChild>, "type">): RelationDefinition<TParent, TChild>;
|
|
79
|
+
/**
|
|
80
|
+
* Creates a many-to-one relation definition.
|
|
81
|
+
*/
|
|
82
|
+
export declare function manyToOne<TParent = unknown, TChild = unknown>(definition: Omit<RelationDefinition<TParent, TChild>, "type">): RelationDefinition<TParent, TChild>;
|
|
83
|
+
/**
|
|
84
|
+
* Creates a many-to-many relation definition.
|
|
85
|
+
*/
|
|
86
|
+
export declare function manyToMany<TParent = unknown, TChild = unknown>(definition: Omit<RelationDefinition<TParent, TChild>, "type">): RelationDefinition<TParent, TChild>;
|
|
87
|
+
/**
|
|
88
|
+
* Creates a relation include definition.
|
|
89
|
+
*/
|
|
90
|
+
export declare function includeRelation(relation: string, options?: {
|
|
91
|
+
readonly select?: readonly string[];
|
|
92
|
+
readonly include?: readonly RelationInclude[];
|
|
93
|
+
}): RelationInclude;
|
|
94
|
+
/**
|
|
95
|
+
* Validates a relation include (recursively).
|
|
96
|
+
*/
|
|
97
|
+
export declare function validateInclude(include: RelationInclude): void;
|
|
98
|
+
/**
|
|
99
|
+
* Translates relation includes into a Prisma `include` object.
|
|
100
|
+
*
|
|
101
|
+
* When a registry is supplied every relation is validated against the
|
|
102
|
+
* parent model (descending through child models for nested includes) and
|
|
103
|
+
* cyclic includes are rejected. Depth is bounded in all cases.
|
|
104
|
+
*/
|
|
105
|
+
export declare function toPrismaInclude(includes: readonly RelationInclude[], options?: ToPrismaIncludeOptions): Record<string, unknown>;
|
|
106
|
+
/**
|
|
107
|
+
* Creates a nested relation include.
|
|
108
|
+
*/
|
|
109
|
+
export declare function includeRelations(...includes: readonly RelationInclude[]): readonly RelationInclude[];
|
|
110
|
+
/**
|
|
111
|
+
* Relation registry used by database infrastructure.
|
|
112
|
+
*
|
|
113
|
+
* Relations are keyed by parent model and name, so two models may each
|
|
114
|
+
* define a relation with the same name.
|
|
115
|
+
*/
|
|
116
|
+
export declare class RelationRegistry {
|
|
117
|
+
private readonly relations;
|
|
118
|
+
/**
|
|
119
|
+
* Registers a relation.
|
|
120
|
+
*/
|
|
121
|
+
register(relation: RelationDefinition): this;
|
|
122
|
+
/**
|
|
123
|
+
* Registers multiple relations.
|
|
124
|
+
*/
|
|
125
|
+
registerMany(relations: readonly RelationDefinition[]): this;
|
|
126
|
+
/**
|
|
127
|
+
* Gets a relation by name.
|
|
128
|
+
*
|
|
129
|
+
* Without `parent` the name must be unique across all parents; an
|
|
130
|
+
* ambiguous lookup throws.
|
|
131
|
+
*/
|
|
132
|
+
get(name: string, parent?: unknown): RelationDefinition | undefined;
|
|
133
|
+
/**
|
|
134
|
+
* Checks whether a relation exists.
|
|
135
|
+
*/
|
|
136
|
+
has(name: string, parent?: unknown): boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Removes a relation. Without `parent`, every relation with that name is
|
|
139
|
+
* removed.
|
|
140
|
+
*/
|
|
141
|
+
remove(name: string, parent?: unknown): boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Returns all registered relations.
|
|
144
|
+
*/
|
|
145
|
+
all(): readonly RelationDefinition[];
|
|
146
|
+
/**
|
|
147
|
+
* Returns relations for a specific parent entity.
|
|
148
|
+
*/
|
|
149
|
+
forParent(parent: unknown): readonly RelationDefinition[];
|
|
150
|
+
/**
|
|
151
|
+
* Returns relations for a specific child entity.
|
|
152
|
+
*/
|
|
153
|
+
forChild(child: unknown): readonly RelationDefinition[];
|
|
154
|
+
/**
|
|
155
|
+
* Clears all registered relations.
|
|
156
|
+
*/
|
|
157
|
+
clear(): void;
|
|
158
|
+
/**
|
|
159
|
+
* Returns the number of registered relations.
|
|
160
|
+
*/
|
|
161
|
+
get size(): number;
|
|
162
|
+
private findByName;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Creates a relation registry.
|
|
166
|
+
*/
|
|
167
|
+
export declare function createRelationRegistry(relations?: readonly RelationDefinition[]): RelationRegistry;
|
|
168
|
+
/**
|
|
169
|
+
* Validates a relation definition.
|
|
170
|
+
*/
|
|
171
|
+
export declare function validateRelation(relation: RelationDefinition): void;
|
|
172
|
+
/**
|
|
173
|
+
* Checks whether a value is a supported relation type.
|
|
174
|
+
*/
|
|
175
|
+
export declare function isRelationType(value: unknown): value is RelationType;
|
|
176
|
+
/**
|
|
177
|
+
* Returns whether the relation represents a collection.
|
|
178
|
+
*/
|
|
179
|
+
export declare function isCollectionRelation(relation: RelationDefinition): boolean;
|
|
180
|
+
/**
|
|
181
|
+
* Returns whether the relation represents a single entity.
|
|
182
|
+
*/
|
|
183
|
+
export declare function isSingleRelation(relation: RelationDefinition): boolean;
|
|
184
|
+
//# sourceMappingURL=relations.definition.d.ts.map
|