@kavo/mikroorm 0.6.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.
@@ -0,0 +1,202 @@
1
+ import { ConfigurationException } from "@kavo/core";
2
+ /**
3
+ * Translate a MikroORM property's declared type into the ORM-independent
4
+ * `FieldKind` core coerces against.
5
+ *
6
+ * `runtimeType` is preferred over `type`: MikroORM normalizes the former to
7
+ * the JavaScript type the property actually holds (`"string"`, `"Date"`),
8
+ * which is what core must coerce toward — a `decimal` column surfaces as
9
+ * `"string"` there, and `string` is genuinely the right target for it. The
10
+ * declared `type` is still consulted as a fallback, because `runtimeType` is
11
+ * `"any"` for the custom types that carry no JavaScript equivalent
12
+ * (`JsonType`). An unrecognized type degrades to `string` — comparison still
13
+ * works, coercion just doesn't narrow.
14
+ *
15
+ * A `bigint` column is a caveat, not a case this function special-cases: as
16
+ * of MikroORM v7, `BigIntType`'s default mode hands JavaScript a native
17
+ * `bigint`, and `runtimeType` reports that as `"bigint"`, matched below
18
+ * alongside `"number"`. An app that needs the old, precision-safe string
19
+ * representation back must construct the type explicitly —
20
+ * `new BigIntType("string")` — see doc 17 §1.
21
+ */
22
+ function fieldKindOf(property) {
23
+ if (property.enum === true)
24
+ return "enum";
25
+ const type = String(property.runtimeType ?? property.type).toLowerCase();
26
+ if (type === "date")
27
+ return "date";
28
+ if (type === "boolean" || type === "bool")
29
+ return "boolean";
30
+ if (type === "number" || type === "bigint")
31
+ return "number";
32
+ if (type === "string")
33
+ return "string";
34
+ if (type === "object" || type === "json" || type === "jsonb")
35
+ return "json";
36
+ // Fall back to the declared column type for anything `runtimeType` did not
37
+ // already answer (a custom `type: "int8"`, a driver-native column type).
38
+ const declared = String(property.type).toLowerCase();
39
+ if (/^(int|integer|tinyint|smallint|mediumint|bigint|float|double|real|decimal|numeric|number)/.test(declared)) {
40
+ return "number";
41
+ }
42
+ if (/^(bool|boolean)/.test(declared))
43
+ return "boolean";
44
+ if (/^(date|datetime|timestamp|time)/.test(declared))
45
+ return "date";
46
+ if (/^(json|jsonb)/.test(declared))
47
+ return "json";
48
+ return "string";
49
+ }
50
+ /**
51
+ * Whether a property is written by the database or the ORM rather than by
52
+ * the caller — excluded from the derived `create`/`update`/`patch` defaults
53
+ * and stripped from write payloads by the default deserializer.
54
+ *
55
+ * MikroORM has no single flag for this, so the four independent ways a
56
+ * property becomes non-caller-writable are each checked: an auto-increment
57
+ * or database-generated column, an `onCreate`/`onUpdate` hook (the
58
+ * equivalent of TypeORM's `@CreateDateColumn`/`@UpdateDateColumn`), an
59
+ * optimistic-lock `@Property({ version: true })`, and `persist: false`,
60
+ * which is not stored at all.
61
+ */
62
+ function isGenerated(property) {
63
+ return (property.autoincrement === true ||
64
+ property.generated !== undefined ||
65
+ property.onCreate !== undefined ||
66
+ property.onUpdate !== undefined ||
67
+ property.version === true ||
68
+ property.persist === false);
69
+ }
70
+ /** MikroORM's relation `kind` discriminators that carry many rows. */
71
+ const TO_MANY = new Set(["1:m", "m:n"]);
72
+ /**
73
+ * The lazy target-class thunk for one relation.
74
+ *
75
+ * A relation target can be declared two ways, and they do *not* arrive the
76
+ * same: `@ManyToOne(() => Owner)` leaves `property.entity` a thunk resolving
77
+ * to the class, while `@ManyToOne((): any => "Owner")` — the spelling that
78
+ * keeps a bidirectional relation's import cycle off the runtime graph, and
79
+ * therefore the one a `dependency-cruiser`-checked codebase reaches for —
80
+ * leaves it a thunk resolving to a plain **string** (MikroORM v7's decorator
81
+ * types no longer accept a bare string; `any` is what makes the thunk
82
+ * type-check). Calling it would return a string, not a class, for half the
83
+ * codebases that use this adapter.
84
+ *
85
+ * `targetMeta` is what both spellings have in common: MikroORM resolves it
86
+ * during metadata discovery either way. The metadata-storage lookup behind
87
+ * it covers a target discovered after this thunk was built, and the declared
88
+ * thunk is the last resort. The resolution is deferred until the thunk is
89
+ * called, because a bidirectional relation's target may not be registered at
90
+ * the time this entity's metadata is derived.
91
+ */
92
+ function targetOf(orm, property, owner) {
93
+ return () => {
94
+ const resolved = property.targetMeta?.class ?? orm.getMetadata().getByClassName(String(property.type), false)?.class;
95
+ if (resolved !== undefined)
96
+ return resolved;
97
+ if (typeof property.entity === "function") {
98
+ return property.entity();
99
+ }
100
+ throw new ConfigurationException(owner, `relations.${property.name}`, `cannot resolve the target entity of relation '${property.name}'; ` +
101
+ `MikroORM reports its type as '${String(property.type)}', which is not a registered entity`);
102
+ };
103
+ }
104
+ /**
105
+ * Build the core `EntityMetadata` for one entity from MikroORM's own
106
+ * `MetadataStorage`: the adapter feeds core's metadata seam; core never sees
107
+ * MikroORM types.
108
+ *
109
+ * Unlike `@kavo/prisma`, no marker class is needed (ADR-0017 exists because
110
+ * Prisma erases its models at compile time) — a MikroORM entity is a real
111
+ * runtime class that already carries its own metadata, so the class the
112
+ * caller passes to `createCrud` *is* the identity, exactly as in
113
+ * `@kavo/typeorm`.
114
+ */
115
+ export function buildEntityMetadata(orm, entity) {
116
+ const metadata = orm.getMetadata().getByClassName(entity.name, false);
117
+ if (metadata === undefined) {
118
+ throw new ConfigurationException(entity.name, "entity", `MikroORM has no registered entity named '${entity.name}'; ` +
119
+ `add it to the 'entities' array the ORM was initialized with`);
120
+ }
121
+ if (metadata.primaryKeys.length !== 1) {
122
+ throw new ConfigurationException(metadata.className, "primaryKeys", `Kavo v6 requires exactly one primary key; found ${metadata.primaryKeys.length}`);
123
+ }
124
+ const properties = Object.values(metadata.properties);
125
+ const discriminatorColumn = metadata.root?.discriminatorColumn ?? metadata.discriminatorColumn;
126
+ const fields = properties
127
+ // An embeddable contributes *two* kinds of property: the object-valued
128
+ // parent (`kind: "embedded"`, what a caller addresses) and one child per
129
+ // inner column, carrying an `embedded: [parent, child]` back-reference
130
+ // and a name that is an implementation detail (`addr~city`,
131
+ // `inline_city`). Only the parent belongs on the wire, so the children
132
+ // are dropped rather than leaked into DTOs and allowlists.
133
+ .filter((property) => property.embedded === undefined)
134
+ // `hidden: true` is MikroORM's "never expose this" — `toObject` drops it,
135
+ // so it can never reach a response. Excluding it from the metadata seam
136
+ // as well, rather than relying on that, is what stops it from landing on
137
+ // the *default allowlists*: a filterable-but-invisible column is a blind
138
+ // extraction oracle, where `filter[passwordHash][like]=a%` is answered by
139
+ // the row count even though the value is projected out of the body.
140
+ // `lazy: true` is excluded for the same reason — it is not loaded with
141
+ // the entity, so a DTO naming it would emit `undefined` while a filter on
142
+ // it still ran in the database. `@kavo/mongoose` excludes its
143
+ // `select: false` paths on identical reasoning (doc 15 §1). The trade is
144
+ // the same one it documents: Kavo does not manage such a property at all,
145
+ // so write it through a custom operation or the ORM directly.
146
+ .filter((property) => property.hidden !== true && property.lazy !== true)
147
+ .filter((property) => property.kind === "scalar" || property.kind === "embedded")
148
+ .map((property) => ({
149
+ name: property.name,
150
+ kind: property.kind === "embedded" ? "json" : fieldKindOf(property),
151
+ nullable: property.nullable === true,
152
+ // The single-table-inheritance discriminator: write-only bookkeeping
153
+ // MikroORM manages itself from the subtype being persisted. It never
154
+ // hydrates onto an entity and never survives `toObject`, so it cannot
155
+ // reach a response either way — what this flag stops is the *inbound*
156
+ // direction. Left un-generated it would join the writable projection,
157
+ // and a client sending `species: "cat"` on a Dog would produce a row
158
+ // that entity's own repository can no longer load.
159
+ //
160
+ // Read from `root`, because MikroORM records `discriminatorColumn` only
161
+ // on the inheritance root while the property itself is inherited by
162
+ // every subtype — and a subtype is what a caller passes to `createCrud`.
163
+ generated: isGenerated(property) || property.name === discriminatorColumn,
164
+ ...(property.items !== undefined && {
165
+ enumValues: property.items.map((value) => String(value)),
166
+ }),
167
+ }));
168
+ const relations = properties
169
+ .filter((property) => property.kind !== "scalar" && property.kind !== "embedded")
170
+ .map((property) => ({
171
+ name: property.name,
172
+ // Resolved lazily and from `targetMeta` rather than by calling
173
+ // `property.entity` — see `targetOf`, which exists because a
174
+ // string-declared target (the spelling that keeps a bidirectional
175
+ // relation's cycle off the runtime graph) leaves `entity` a string.
176
+ target: targetOf(orm, property, metadata.className),
177
+ cardinality: TO_MANY.has(property.kind) ? "many" : "one",
178
+ // Inclusion is an opt-in allowlist; ORM metadata only supplies shape,
179
+ // never permission.
180
+ includable: false,
181
+ strategy: "auto",
182
+ }));
183
+ return {
184
+ entity,
185
+ name: metadata.className,
186
+ idField: metadata.primaryKeys[0],
187
+ fields,
188
+ relations,
189
+ // MikroORM declares no delete-date marker of its own — its soft-delete
190
+ // pattern is a user-defined `@Filter`, which is a query concern rather
191
+ // than a column declaration, so there is nothing here to detect.
192
+ //
193
+ // This is *not* the same as "soft delete is off until configured".
194
+ // `softDelete` defaults to `{ field: "deletedAt", strategy: "auto" }`, and
195
+ // core matches that name against the entity's own columns — so a plain
196
+ // `deletedAt` property enables soft delete with no config at all. What
197
+ // reporting `null` here really costs is the ability to mark the marker
198
+ // generated, which is why it stays client-writable. See doc 17 §5 and §7.
199
+ softDeleteField: null,
200
+ };
201
+ }
202
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ import type { EntityId, EntityMetadata, KavoContext, NormalizedQueryContext, RepositoryAdapter } from "@kavo/core";
2
+ import { type MikroORM } from "@mikro-orm/core";
3
+ /**
4
+ * `RepositoryAdapter` over a MikroORM `EntityManager`: CRUD with hard *or*
5
+ * soft delete, restore, purge, filtering, sorting, pagination, optional
6
+ * counting, and nested relation includes.
7
+ *
8
+ * Two things are specific to MikroORM and load-bearing:
9
+ *
10
+ * **Every method forks the EntityManager.** MikroORM is a Unit-of-Work ORM:
11
+ * an `EntityManager` owns an identity map that caches every entity it has
12
+ * loaded, and reusing one across requests would serve stale rows and leak
13
+ * one caller's entities into another's. `orm.em` is the *root* manager and
14
+ * is not meant to be queried directly; `orm.em.fork()` gives each operation
15
+ * a clean, isolated one, which is the same scope a request-scoped
16
+ * `RequestContext` would give a hand-written MikroORM application.
17
+ *
18
+ * **`IncludeNode.strategy` is deliberately ignored**, exactly as in
19
+ * `@kavo/prisma` and unlike `@kavo/typeorm`. The TypeORM adapter translates
20
+ * the join/batch split because it drives a raw SQL query builder, where a
21
+ * to-many `JOIN` multiplies root rows and separate batched queries are how
22
+ * that is avoided. MikroORM resolves `populate` with its own queries and
23
+ * applies `limit`/`offset` to the root regardless of the load strategy, so a
24
+ * to-many include never disturbs pagination here. There is nothing left for
25
+ * the distinction to control, and MikroORM's `strategy` option is per-query
26
+ * rather than per-relation anyway — it could not express a mixed tree.
27
+ */
28
+ export declare class MikroOrmRepositoryAdapter<Entity extends object> implements RepositoryAdapter<Entity> {
29
+ private readonly orm;
30
+ private readonly entity;
31
+ private readonly idField;
32
+ private readonly filterOptions;
33
+ /**
34
+ * Relation property name → the target entity's primary-key property.
35
+ * Resolved lazily: a bidirectional relation's target may not be registered
36
+ * with MikroORM's metadata storage at the time this adapter is built.
37
+ */
38
+ private readonly relationIdFields;
39
+ constructor(orm: MikroORM, metadata: EntityMetadata<Entity>, options?: {
40
+ caseInsensitiveFilters?: boolean;
41
+ });
42
+ /** A clean, isolated `EntityManager` for one operation — see the class doc. */
43
+ private fork;
44
+ findOneById(id: EntityId, query: NormalizedQueryContext<Entity> | null, context: KavoContext<Entity>): Promise<Entity | null>;
45
+ findOne(query: NormalizedQueryContext<Entity>, context: KavoContext<Entity>): Promise<Entity | null>;
46
+ findMany(query: NormalizedQueryContext<Entity>, context: KavoContext<Entity>): Promise<readonly Entity[]>;
47
+ count(query: NormalizedQueryContext<Entity>, context: KavoContext<Entity>): Promise<number>;
48
+ /** The translated filter, narrowed to the request's soft-delete scope. */
49
+ private buildWhere;
50
+ private buildFindOptions;
51
+ /**
52
+ * Translate a validated `IncludeTree` into MikroORM's `populate` paths.
53
+ *
54
+ * Soft-delete scoping of included rows is deliberately **not** done here —
55
+ * see {@link pruneIncluded}. MikroORM's `populateWhere` cannot express it:
56
+ * a nested condition (`{ articles: { deletedAt: null, notes: { deletedAt:
57
+ * null } } }`) is read as a relation-path predicate on the *parent*, so an
58
+ * article with no live notes is dropped from the parent's collection
59
+ * altogether rather than coming back with an empty one. The dotted spelling
60
+ * MikroORM rejects outright, and the parent-only spelling silently leaves
61
+ * every deeper level unscoped.
62
+ */
63
+ private populateOptions;
64
+ /**
65
+ * Three-way soft-delete scope: exclude deleted rows by default, include
66
+ * both live and deleted with `withDeleted`, or restrict to only deleted
67
+ * with `onlyDeleted` (mutually exclusive — validated upstream).
68
+ *
69
+ * There is one shape to handle rather than TypeORM's two: MikroORM
70
+ * declares no delete-date column of its own, so the marker is always an
71
+ * ordinary property and always needs its predicate spelled out.
72
+ */
73
+ private scopeToLive;
74
+ /** The resolved strategy, refused when an operation requires soft. */
75
+ private requireSoftDelete;
76
+ private isDeleted;
77
+ /** One row by id, as a plain object, under the given soft-delete scope. */
78
+ private byId;
79
+ create(data: Partial<Entity>, context: KavoContext<Entity>): Promise<Entity>;
80
+ update(id: EntityId, data: Partial<Entity>, context: KavoContext<Entity>): Promise<Entity>;
81
+ patch(id: EntityId, data: Partial<Entity>, context: KavoContext<Entity>): Promise<Entity>;
82
+ /**
83
+ * update and patch share one load-merge-flush primitive: the *shape* of
84
+ * `data` differs (full body vs. sparse) because the DTO layer differs, not
85
+ * the persistence mechanics.
86
+ *
87
+ * This goes through the Unit of Work rather than `nativeUpdate` — one
88
+ * managed entity, assigned and flushed — so lifecycle hooks,
89
+ * `onUpdate` properties, and relation diffing all behave as they would in
90
+ * a hand-written MikroORM application. The row is loaded first anyway, to
91
+ * turn a missing id into `NotFoundException`, so this costs no extra
92
+ * query.
93
+ */
94
+ private mergeAndFlush;
95
+ delete(id: EntityId, context: KavoContext<Entity>): Promise<void>;
96
+ restore(id: EntityId, context: KavoContext<Entity>): Promise<Entity>;
97
+ purge(id: EntityId, context: KavoContext<Entity>): Promise<void>;
98
+ /**
99
+ * Normalize the engine's write payload for MikroORM.
100
+ *
101
+ * Core's default deserializer narrows a relation value to `{ id }` (or an
102
+ * array of them) — association by id, ADR-0014. MikroORM associates by
103
+ * *primary key value*, and would read a nested `{ id }` object as a
104
+ * request to create a new entity, so each relation value is unwrapped to
105
+ * the bare key before it reaches `create`/`assign`.
106
+ */
107
+ private toWriteData;
108
+ private notFound;
109
+ }
110
+ //# sourceMappingURL=mikro-orm-repository-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mikro-orm-repository-adapter.d.ts","sourceRoot":"","sources":["../src/mikro-orm-repository-adapter.ts"],"names":[],"mappings":"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"}