@t4h.framework/orm 0.3.0 → 0.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.
Files changed (64) hide show
  1. package/.ai/skills/framework-orm/SKILL.md +339 -0
  2. package/README.md +54 -0
  3. package/dist/activities/ORMGetSnapshotActivity.d.ts +3 -3
  4. package/dist/activities/ORMGetSnapshotActivity.d.ts.map +1 -1
  5. package/dist/activities/ORMGetSnapshotActivity.js.map +1 -1
  6. package/dist/claims/ORMClaim.d.ts +1 -1
  7. package/dist/claims/ORMClaim.d.ts.map +1 -1
  8. package/dist/constraints/__tests__/create-entity-metadata.d.ts +3 -0
  9. package/dist/constraints/__tests__/create-entity-metadata.d.ts.map +1 -0
  10. package/dist/constraints/__tests__/create-entity-metadata.js +10 -0
  11. package/dist/constraints/__tests__/create-entity-metadata.js.map +1 -0
  12. package/dist/constraints/apply-default-properties.d.ts +7 -0
  13. package/dist/constraints/apply-default-properties.d.ts.map +1 -0
  14. package/dist/constraints/apply-default-properties.js +16 -0
  15. package/dist/constraints/apply-default-properties.js.map +1 -0
  16. package/dist/constraints/assert-constraints.d.ts +7 -0
  17. package/dist/constraints/assert-constraints.d.ts.map +1 -0
  18. package/dist/constraints/assert-constraints.js +13 -0
  19. package/dist/constraints/assert-constraints.js.map +1 -0
  20. package/dist/constraints/assert-non-nullable-property-constraint.d.ts +7 -0
  21. package/dist/constraints/assert-non-nullable-property-constraint.d.ts.map +1 -0
  22. package/dist/constraints/assert-non-nullable-property-constraint.js +14 -0
  23. package/dist/constraints/assert-non-nullable-property-constraint.js.map +1 -0
  24. package/dist/constraints/assert-property-type-constraint.d.ts +7 -0
  25. package/dist/constraints/assert-property-type-constraint.d.ts.map +1 -0
  26. package/dist/constraints/assert-property-type-constraint.js +30 -0
  27. package/dist/constraints/assert-property-type-constraint.js.map +1 -0
  28. package/dist/constraints/assert-unique-constraint.d.ts +11 -0
  29. package/dist/constraints/assert-unique-constraint.d.ts.map +1 -0
  30. package/dist/constraints/assert-unique-constraint.js +41 -0
  31. package/dist/constraints/assert-unique-constraint.js.map +1 -0
  32. package/dist/decorators/Index.d.ts +6 -0
  33. package/dist/decorators/Index.d.ts.map +1 -0
  34. package/dist/decorators/Index.js +10 -0
  35. package/dist/decorators/Index.js.map +1 -0
  36. package/dist/decorators/Property.d.ts +1 -0
  37. package/dist/decorators/Property.d.ts.map +1 -1
  38. package/dist/decorators/Property.js +17 -1
  39. package/dist/decorators/Property.js.map +1 -1
  40. package/dist/decorators/metadata.d.ts +5 -2
  41. package/dist/decorators/metadata.d.ts.map +1 -1
  42. package/dist/decorators/metadata.js +1 -1
  43. package/dist/decorators/metadata.js.map +1 -1
  44. package/dist/errors/ConstraintError.d.ts +4 -0
  45. package/dist/errors/ConstraintError.d.ts.map +1 -0
  46. package/dist/errors/ConstraintError.js +7 -0
  47. package/dist/errors/ConstraintError.js.map +1 -0
  48. package/dist/models/ORM.d.ts +25 -5
  49. package/dist/models/ORM.d.ts.map +1 -1
  50. package/dist/models/ORM.js +42 -7
  51. package/dist/models/ORM.js.map +1 -1
  52. package/dist/models/Ref.d.ts +1 -1
  53. package/dist/models/Ref.d.ts.map +1 -1
  54. package/dist/models/Ref.js +11 -2
  55. package/dist/models/Ref.js.map +1 -1
  56. package/dist/orm.d.ts +3 -0
  57. package/dist/orm.d.ts.map +1 -1
  58. package/dist/orm.js +3 -0
  59. package/dist/orm.js.map +1 -1
  60. package/dist/testing/index.d.ts +4 -0
  61. package/dist/testing/index.d.ts.map +1 -0
  62. package/dist/testing/index.js +52 -0
  63. package/dist/testing/index.js.map +1 -0
  64. package/package.json +6 -4
@@ -0,0 +1,339 @@
1
+ ---
2
+ name: framework-orm
3
+ description: >-
4
+ Guides correct use of @t4h.framework/orm in T4H Framework workflows: entity
5
+ decorators (@Entity, @Property, @Index), the ORM model (create, find, findOne,
6
+ exists), Ref and RefCollection, query operators, constraint validation, ORM
7
+ activities, and ORMClaim wiring. Use when defining database entities, persisting
8
+ or querying rows in workflows, implementing ORMClaim providers, testing ORM
9
+ workflows with TestWorkflowEnvironment, or working in packages/orm.
10
+ ---
11
+
12
+ # @t4h.framework/orm
13
+
14
+ ORM activities, claim, and models for database operations within workflows. Package path: `framework/packages/orm`. Peer dependency: `@t4h.framework/core`.
15
+
16
+ Import from `src/orm.ts` only — do not reference unexported modules:
17
+
18
+ ```typescript
19
+ import {
20
+ Entity, Property, Index, ORM, Ref, RefCollection,
21
+ ORMClaim, ConstraintError,
22
+ ORMCreateActivity, ORMFindActivity, ORMFindOneActivity,
23
+ ORMGetSnapshotActivity, ORMUpdateActivity, ORMRemoveActivity,
24
+ getEntityMetadata, getEntityTableName, getEntityProperties,
25
+ type EntityInsertData, type EntityPartialData, type FindWhere,
26
+ type SerializableCreateInput, type SerializableFindInput,
27
+ type SerializableGetSnapshotInput, type SerializableUpdateInput,
28
+ type SerializableRemoveInput,
29
+ } from '@t4h.framework/orm'
30
+ ```
31
+
32
+ Node `>=22`. See [README.md](../../../README.md).
33
+
34
+ ---
35
+
36
+ ## Architecture
37
+
38
+ `Workflow` → `ORM` / `Ref` methods (`History.bind` on ORM activities) → `ORMClaim` (runtime database adapter).
39
+
40
+ | Layer | Role |
41
+ |-------|------|
42
+ | **ORM** | High-level API; applies defaults + constraints before activities |
43
+ | **Ref** / **RefCollection** | Row handles returned by create/find |
44
+ | **Activities** | Shipped, replay-safe activities the `ORM`/`Ref` APIs drive; delegate to `ORMClaim` |
45
+ | **ORMClaim** | Abstract claim; runtime provides concrete DB implementation |
46
+
47
+ ---
48
+
49
+ ## Defining entities
50
+
51
+ Enable decorator metadata in the project `tsconfig.json`:
52
+
53
+ ```json
54
+ {
55
+ "compilerOptions": {
56
+ "experimentalDecorators": true,
57
+ "emitDecoratorMetadata": true
58
+ }
59
+ }
60
+ ```
61
+
62
+ Import `reflect-metadata` where decorators are evaluated (Property decorator imports it).
63
+
64
+ ### @Entity
65
+
66
+ ```typescript
67
+ @Entity({ tableName: 'users' })
68
+ class User {
69
+ @Property({ type: 'string' })
70
+ public name!: string
71
+
72
+ @Property({ type: 'string' })
73
+ public email!: string
74
+
75
+ @Property({ type: 'boolean', default: true })
76
+ public active!: boolean
77
+ }
78
+ ```
79
+
80
+ - `tableName` is optional; defaults to the class name (`User` → `"User"`).
81
+ - Use `getEntityTableName(User)` or rely on ORM to resolve the table name.
82
+
83
+ ### @Property
84
+
85
+ Options: `type?`, `nullable?` (default required), `default?`, `index?` (adds index metadata).
86
+
87
+ Omit `type` to infer from design metadata (`String`→`string`, `Number`→`number`, etc.). Declare domain types (`uuid`) explicitly. Validated types: `string`, `uuid`, `number`, `boolean`, `array`, `date`, `object`. No `type` → skip type validation.
88
+
89
+ ### @Index
90
+
91
+ Class-level composite indexes:
92
+
93
+ ```typescript
94
+ @Index({ properties: ['tenantId', 'email'], name: 'accounts_tenant_email_idx' })
95
+ class Account { /* ... */ }
96
+ ```
97
+
98
+ `properties` must be non-empty or the decorator throws. Per-property `@Property({ index: true })` also registers `{ properties: [propertyKey] }`.
99
+
100
+ ---
101
+
102
+ ## ORM configuration
103
+
104
+ `ORM` extends `SerializableClass` — instances can be serialized for workflow persistence.
105
+
106
+ ```typescript
107
+ const orm = new ORM({
108
+ connectionString: 'postgresql://localhost:5432/mydb',
109
+ entities: [User, Product],
110
+ })
111
+ ```
112
+
113
+ - `entities`: array of entity **constructors** (decorated classes).
114
+ - `config.entities` stores resolved `EntityMetadata` (table name, properties map, indexes).
115
+
116
+ Restore from serialized state:
117
+
118
+ ```typescript
119
+ const orm = await ORM.fromSerializable(serialized, v => v)
120
+ ```
121
+
122
+ ---
123
+
124
+ ## CRUD in workflows
125
+
126
+ ORM methods bind activities via `History.bind` — calls inside a workflow are **reconciler-driven** (replay-safe).
127
+
128
+ ### Create
129
+
130
+ ```typescript
131
+ // Single row → Ref<T>
132
+ const userRef = await orm.create(User, {
133
+ name: 'John',
134
+ email: 'john@example.com',
135
+ active: true,
136
+ })
137
+
138
+ // Batch → RefCollection<T>
139
+ const usersRef = await orm.create(User, [
140
+ { name: 'Alice', email: 'alice@example.com', active: true },
141
+ { name: 'Bob', email: 'bob@example.com', active: true },
142
+ ])
143
+ ```
144
+
145
+ Defaults are applied before persistence (`applyDefaultProperties`). Omitted fields with `@Property({ default })` are filled in.
146
+
147
+ ### Find
148
+
149
+ ```typescript
150
+ const userRef = await orm.findOne(User, {
151
+ where: { email: 'john@example.com' },
152
+ orderBy: { name: 'asc' },
153
+ }) // Ref<User> | null
154
+
155
+ const usersRef = await orm.find(User, {
156
+ where: { active: true },
157
+ orderBy: { name: 'asc' },
158
+ limit: 10,
159
+ offset: 0,
160
+ }) // RefCollection<User>
161
+
162
+ const exists = await orm.exists(User, {
163
+ where: { email: 'john@example.com' },
164
+ }) // boolean (delegates to findOne)
165
+ ```
166
+
167
+ `findOne` activity internally calls `claim.find` with `limit: 1`.
168
+
169
+ ### Ref operations
170
+
171
+ ```typescript
172
+ const snapshot = await userRef.getSnapshot() // T | null — entity instance
173
+ await userRef.update({ name: 'Jane' }) // partial patch only
174
+ await userRef.remove()
175
+ ```
176
+
177
+ `getSnapshot` returns `null` when the row no longer exists. `update` validates only keys present in the patch.
178
+
179
+ **RefCollection:** `toArray()`, `length`, `at(i)`, async `forEach`/`map`/`filter`, `Symbol.iterator`.
180
+
181
+ ---
182
+
183
+ ## Query operators
184
+
185
+ `where` uses `FindWhere<T>` — implicit equality or operator objects:
186
+
187
+ ```typescript
188
+ await orm.find(User, {
189
+ where: {
190
+ name: 'John', // $eq (implicit)
191
+ active: { $ne: false },
192
+ email: { $like: '%@example%' },
193
+ age: { $gte: 18, $lt: 65 },
194
+ status: { $in: ['active', 'pending'] },
195
+ $or: [{ name: 'Alice' }, { name: 'Bob' }],
196
+ $and: [{ active: true }, { age: { $gte: 18 } }],
197
+ },
198
+ })
199
+ ```
200
+
201
+ Available operators: `$eq`, `$ne`, `$in`, `$nin`, `$not`, `$gt`, `$gte`, `$lt`, `$lte`, `$like`, `$ilike`, `$and`, `$or`.
202
+
203
+ ---
204
+
205
+ ## Constraint validation
206
+
207
+ Validation runs in the ORM library (`ORM.create` and `Ref.update`), **not** in `ORMClaim` implementations. Failures throw `ConstraintError`.
208
+
209
+ ### Create pipeline
210
+
211
+ 1. `applyDefaultProperties` — fills `default` for `undefined` fields
212
+ 2. `assertPropertyTypeConstraint` — validates declared types
213
+ 3. `assertNonNullablePropertyConstraint` — required fields must be present
214
+
215
+ ### Update pipeline
216
+
217
+ 1. Defaults only for keys present in the patch
218
+ 2. Same asserts, scoped to patch keys via `{ keys: Object.keys(data) }`
219
+
220
+ ### Handling errors
221
+
222
+ ```typescript
223
+ import { ConstraintError, ORM } from '@t4h.framework/orm'
224
+
225
+ try {
226
+ await orm.create(User, { email: 'bad' } as EntityInsertData<User>)
227
+ } catch (error) {
228
+ if (error instanceof ConstraintError) {
229
+ // e.g. 'Property "name" is required'
230
+ // e.g. 'Property "name" must be of type string'
231
+ }
232
+ }
233
+ ```
234
+
235
+ Constraint checks run **before** activities are invoked — failed creates/updates never reach `ORMClaim`.
236
+
237
+ ---
238
+
239
+ ## ORMClaim (runtime dependency)
240
+
241
+ Runtime must register a concrete implementation:
242
+
243
+ ```typescript
244
+ { provide: ORMClaim, value: new MyORMClaimImpl() }
245
+ ```
246
+
247
+ Contract:
248
+
249
+ ```typescript
250
+ abstract class ORMClaim<R extends SerializableRowRef> {
251
+ abstract find(input: SerializableFindInput): R[] | Promise<R[]>
252
+ abstract create(input: SerializableCreateInput): R[] | Promise<R[]>
253
+ abstract getSnapshot(input: SerializableGetSnapshotInput<R>): SerializedRow | null | Promise<SerializedRow | null>
254
+ abstract update(input: SerializableUpdateInput<R>): void | Promise<void>
255
+ abstract remove(input: SerializableRemoveInput<R>): void | Promise<void>
256
+ }
257
+ ```
258
+
259
+ Activity inputs always include `orm` + `table`; create adds `data[]`, find adds `where` (+ optional `orderBy`/`limit`/`offset`), snapshot/update/remove add `ref` (opaque `Serializable` row handle). Update also includes partial `data`.
260
+
261
+ The `ORM`/`Ref` calls run inside a workflow (the runtime, or `TestWorkflowEnvironment` in tests, provides the reconciler context).
262
+
263
+ ---
264
+
265
+ ## Activities
266
+
267
+ These are the **shipped, replay-safe activities** the `ORM`/`Ref` APIs drive for you (you can also pass them to `History.reconciler` directly). Never define your own:
268
+
269
+ | Activity | Input | Output |
270
+ |----------|-------|--------|
271
+ | `ORMCreateActivity` | `SerializableCreateInput` | `SerializableRowRef[]` |
272
+ | `ORMFindActivity` | `SerializableFindInput` | `SerializableRowRef[]` |
273
+ | `ORMFindOneActivity` | `SerializableFindInput` | `SerializableRowRef \| null` |
274
+ | `ORMGetSnapshotActivity` | `SerializableGetSnapshotInput` | `SerializedRow \| null` |
275
+ | `ORMUpdateActivity` | `SerializableUpdateInput` | `void` |
276
+ | `ORMRemoveActivity` | `SerializableRemoveInput` | `void` |
277
+
278
+ Prefer **`ORM` / `Ref` APIs** in workflow code — they apply constraints and return typed handles. Use activities directly only for advanced/testing scenarios.
279
+
280
+ ---
281
+
282
+ ## Workflow example
283
+
284
+ Define entities, instantiate `ORM` with `connectionString` + `entities`, and use it inside a `Workflow`:
285
+
286
+ ```typescript
287
+ export const orm = new ORM({ connectionString: '...', entities: [User] })
288
+
289
+ export const ormWorkflow = new Workflow({ id: 'orm' }, async () => {
290
+ await orm.create(User, { name: 'John', email: 'john@example.com', age: 20 })
291
+ const user = await orm.findOne(User, { where: { email: 'john@example.com' } })
292
+ await user?.update({ name: 'John Updated' })
293
+ await user?.remove()
294
+ return { user }
295
+ })
296
+ ```
297
+
298
+ Ensure the runtime provides `ORMClaim`.
299
+
300
+ ---
301
+
302
+ ## Testing
303
+
304
+ Test the **workflow** with `TestWorkflowEnvironment` from
305
+ `@t4h.framework/core/testing`, mocking `ORMClaim` — the single claim the ORM
306
+ activities resolve. Provide the methods your workflow triggers (`create`, `find`,
307
+ `findOne`, `getSnapshot`, `update`, `remove`). See the **framework-workflow-testing**
308
+ skill for the harness API.
309
+
310
+ ```typescript
311
+ import { TestWorkflowEnvironment, mockClaim } from '@t4h.framework/core/testing'
312
+ import { ORMClaim } from '@t4h.framework/orm'
313
+
314
+ const mockCreate = vi.fn().mockImplementation(async () => [{ id: 1 }])
315
+ const mockFindOne = vi.fn().mockImplementation(async () => ({ id: 1, name: 'John' }))
316
+
317
+ const env = TestWorkflowEnvironment.create({ now: 0 })
318
+
319
+ await env.execute(workflow, input, {
320
+ claims: [mockClaim(ORMClaim, { create: mockCreate, findOne: mockFindOne })],
321
+ })
322
+ ```
323
+
324
+ Constraint/validation errors are applied by the `ORM`/`Ref` layer before the
325
+ activity runs, so you can assert an invalid input rejects without the claim being
326
+ called: `expect(mockCreate).not.toHaveBeenCalled()`.
327
+
328
+ ---
329
+
330
+ ## Checklist for agents
331
+
332
+ 1. **`@Entity` + `@Property`** with `experimentalDecorators` + `emitDecoratorMetadata`.
333
+ 2. Register entities in **`ORM({ entities: [...] })`**; runtime provides **`ORMClaim`**.
334
+ 3. Use **`orm` / `Ref` APIs** in workflows — not raw SQL or direct claim calls.
335
+ 4. Handle **`ConstraintError`**; validation runs before activities.
336
+ 5. **`Ref.update`** is partial; **`getSnapshot`** returns entity instances.
337
+ 6. Test workflows with **`TestWorkflowEnvironment`** + **`mockClaim(ORMClaim, ...)`**; only use exported APIs.
338
+
339
+ See also: `packages/orm/README.md`; **framework-workflow-testing** for the test harness.
package/README.md CHANGED
@@ -64,6 +64,60 @@ class User {
64
64
  })
65
65
  ```
66
66
 
67
+ When `type` is omitted, it is inferred from the TypeScript property type if the project enables `emitDecoratorMetadata` (and imports `reflect-metadata`). Domain types such as `uuid` must be declared explicitly.
68
+
69
+ If `nullable` is omitted, the property is required at runtime validation.
70
+
71
+ ### TypeScript configuration for entity classes
72
+
73
+ Projects that define entities with `@Property()` should enable:
74
+
75
+ ```json
76
+ {
77
+ "compilerOptions": {
78
+ "experimentalDecorators": true,
79
+ "emitDecoratorMetadata": true
80
+ }
81
+ }
82
+ ```
83
+
84
+ ## Constraints
85
+
86
+ Row validation runs in the ORM library (`ORM.create` and `Ref.update`), not in `ORMClaim` implementations. Failed checks throw `ConstraintError`.
87
+
88
+ ### Pipeline
89
+
90
+ **Create** (full row, after defaults):
91
+
92
+ 1. `applyDefaultProperties` — fills `default` for `undefined` fields
93
+ 2. `assertPropertyTypeConstraint` — validates declared types
94
+ 3. `assertNonNullablePropertyConstraint` — required fields must be present
95
+ 4. `assertUniqueConstraint` — no duplicates in the batch, then no conflicting row in storage via `orm.exists`
96
+
97
+ **Update** (partial patch only):
98
+
99
+ 1. Defaults only for keys present in the patch
100
+ 2. Same asserts, scoped to patch keys
101
+ 3. Unique checks skip values unchanged vs `getSnapshot()` (same row keeps its current unique value)
102
+
103
+ ### Supported property types
104
+
105
+ `string`, `uuid`, `number`, `boolean`, `array`, `date`, `object`. Properties without `type` skip type validation.
106
+
107
+ ### Example
108
+
109
+ ```typescript
110
+ import { ConstraintError, ORM } from '@t4h.framework/orm'
111
+
112
+ try {
113
+ await orm.create(User, { email: 'taken@example.com' })
114
+ } catch (error) {
115
+ if (error instanceof ConstraintError) {
116
+ // handle validation failure
117
+ }
118
+ }
119
+ ```
120
+
67
121
  ## ORM Model
68
122
 
69
123
  The `ORM` class provides a high-level API for database operations. It wraps the underlying activities (`ORMCreateActivity`, `ORMFindActivity`, `ORMFindOneActivity`).
@@ -3,11 +3,11 @@ import type { SerializableGetSnapshotInput, SerializableRowRef, SerializedRow }
3
3
  declare const CLAIMS_KEY: unique symbol;
4
4
  export declare class ORMGetSnapshotActivity extends SyncActivity<[
5
5
  input: SerializableGetSnapshotInput<SerializableRowRef>
6
- ], SerializableGetSnapshotInput<SerializableRowRef>, SerializedRow, SerializedRow> {
6
+ ], SerializableGetSnapshotInput<SerializableRowRef>, SerializedRow | null, SerializedRow | null> {
7
7
  private readonly [CLAIMS_KEY];
8
8
  toInput(input: SerializableGetSnapshotInput<SerializableRowRef>): SerializableGetSnapshotInput<SerializableRowRef>;
9
- run(input: SerializableGetSnapshotInput<SerializableRowRef>): SerializedRow | Promise<SerializedRow>;
10
- toOutput(output: SerializedRow): SerializedRow;
9
+ run(input: SerializableGetSnapshotInput<SerializableRowRef>): SerializedRow | Promise<SerializedRow | null> | null;
10
+ toOutput(output: SerializedRow | null): SerializedRow | null;
11
11
  }
12
12
  export {};
13
13
  //# sourceMappingURL=ORMGetSnapshotActivity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ORMGetSnapshotActivity.d.ts","sourceRoot":"","sources":["../../src/activities/ORMGetSnapshotActivity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAS,MAAM,qBAAqB,CAAA;AAGzD,OAAO,KAAK,EACV,4BAA4B,EAC5B,kBAAkB,EAClB,aAAa,EACd,MAAM,mBAAmB,CAAA;AAE1B,QAAA,MAAM,UAAU,eAA6C,CAAA;AAE7D,qBAAa,sBAAuB,SAAQ,YAAY,CACtD;IAAC,KAAK,EAAE,4BAA4B,CAAC,kBAAkB,CAAC;CAAC,EACzD,4BAA4B,CAAC,kBAAkB,CAAC,EAChD,aAAa,EACb,aAAa,CACd;IACC,OAAO,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAE3B;IAEK,OAAO,CACZ,KAAK,EAAE,4BAA4B,CAAC,kBAAkB,CAAC,GACtD,4BAA4B,CAAC,kBAAkB,CAAC;IAI5C,GAAG,CAAC,KAAK,EAAE,4BAA4B,CAAC,kBAAkB,CAAC;IAI3D,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa;CAGtD"}
1
+ {"version":3,"file":"ORMGetSnapshotActivity.d.ts","sourceRoot":"","sources":["../../src/activities/ORMGetSnapshotActivity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAS,MAAM,qBAAqB,CAAA;AAGzD,OAAO,KAAK,EACV,4BAA4B,EAC5B,kBAAkB,EAClB,aAAa,EACd,MAAM,mBAAmB,CAAA;AAE1B,QAAA,MAAM,UAAU,eAA6C,CAAA;AAE7D,qBAAa,sBAAuB,SAAQ,YAAY,CACtD;IAAC,KAAK,EAAE,4BAA4B,CAAC,kBAAkB,CAAC;CAAC,EACzD,4BAA4B,CAAC,kBAAkB,CAAC,EAChD,aAAa,GAAG,IAAI,EACpB,aAAa,GAAG,IAAI,CACrB;IACC,OAAO,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAE3B;IAEK,OAAO,CACZ,KAAK,EAAE,4BAA4B,CAAC,kBAAkB,CAAC,GACtD,4BAA4B,CAAC,kBAAkB,CAAC;IAI5C,GAAG,CAAC,KAAK,EAAE,4BAA4B,CAAC,kBAAkB,CAAC;IAI3D,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,aAAa,GAAG,IAAI;CAGpE"}
@@ -1 +1 @@
1
- {"version":3,"file":"ORMGetSnapshotActivity.js","sourceRoot":"","sources":["../../src/activities/ORMGetSnapshotActivity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAEzD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAOhD,MAAM,UAAU,GAAG,MAAM,CAAC,kCAAkC,CAAC,CAAA;AAE7D,MAAM,OAAO,sBAAuB,SAAQ,YAK3C;IACkB,CAAC,UAAU,CAAC,GAAG,IAAI,KAAK,CAAC;QACxC,GAAG,EAAE,QAAQ;KACd,CAAC,CAAA;IAEK,OAAO,CACZ,KAAuD;QAEvD,OAAO,KAAK,CAAA;IACd,CAAC;IAEM,GAAG,CAAC,KAAuD;QAChE,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;IAChD,CAAC;IAEM,QAAQ,CAAC,MAAqB;QACnC,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
1
+ {"version":3,"file":"ORMGetSnapshotActivity.js","sourceRoot":"","sources":["../../src/activities/ORMGetSnapshotActivity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAEzD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAOhD,MAAM,UAAU,GAAG,MAAM,CAAC,kCAAkC,CAAC,CAAA;AAE7D,MAAM,OAAO,sBAAuB,SAAQ,YAK3C;IACkB,CAAC,UAAU,CAAC,GAAG,IAAI,KAAK,CAAC;QACxC,GAAG,EAAE,QAAQ;KACd,CAAC,CAAA;IAEK,OAAO,CACZ,KAAuD;QAEvD,OAAO,KAAK,CAAA;IACd,CAAC;IAEM,GAAG,CAAC,KAAuD;QAChE,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;IAChD,CAAC;IAEM,QAAQ,CAAC,MAA4B;QAC1C,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
@@ -2,7 +2,7 @@ import type { SerializableCreateInput, SerializableFindInput, SerializableGetSna
2
2
  export declare abstract class ORMClaim<R extends SerializableRowRef> {
3
3
  abstract find(input: SerializableFindInput): R[] | Promise<R[]>;
4
4
  abstract create(input: SerializableCreateInput): R[] | Promise<R[]>;
5
- abstract getSnapshot(input: SerializableGetSnapshotInput<R>): SerializedRow | Promise<SerializedRow>;
5
+ abstract getSnapshot(input: SerializableGetSnapshotInput<R>): SerializedRow | null | Promise<SerializedRow | null>;
6
6
  abstract update(input: SerializableUpdateInput<R>): void | Promise<void>;
7
7
  abstract remove(input: SerializableRemoveInput<R>): void | Promise<void>;
8
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ORMClaim.d.ts","sourceRoot":"","sources":["../../src/claims/ORMClaim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EACrB,4BAA4B,EAC5B,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,aAAa,EACd,MAAM,mBAAmB,CAAA;AAE1B,8BAAsB,QAAQ,CAAC,CAAC,SAAS,kBAAkB;aACzC,IAAI,CAAC,KAAK,EAAE,qBAAqB,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;aAEtD,MAAM,CAAC,KAAK,EAAE,uBAAuB,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;aAE1D,WAAW,CACzB,KAAK,EAAE,4BAA4B,CAAC,CAAC,CAAC,GACrC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;aAEzB,MAAM,CACpB,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAChC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;aAEP,MAAM,CACpB,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAChC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CACxB"}
1
+ {"version":3,"file":"ORMClaim.d.ts","sourceRoot":"","sources":["../../src/claims/ORMClaim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EACrB,4BAA4B,EAC5B,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,aAAa,EACd,MAAM,mBAAmB,CAAA;AAE1B,8BAAsB,QAAQ,CAAC,CAAC,SAAS,kBAAkB;aACzC,IAAI,CAAC,KAAK,EAAE,qBAAqB,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;aAEtD,MAAM,CAAC,KAAK,EAAE,uBAAuB,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;aAE1D,WAAW,CACzB,KAAK,EAAE,4BAA4B,CAAC,CAAC,CAAC,GACrC,aAAa,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;aAEvC,MAAM,CACpB,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAChC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;aAEP,MAAM,CACpB,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAChC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CACxB"}
@@ -0,0 +1,3 @@
1
+ import type { EntityMetadata, PropertyMetadata } from '../../decorators/metadata.js';
2
+ export declare function createEntityMetadata(properties: Record<string, Omit<PropertyMetadata, 'name'>>): EntityMetadata;
3
+ //# sourceMappingURL=create-entity-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-entity-metadata.d.ts","sourceRoot":"","sources":["../../../src/constraints/__tests__/create-entity-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EACjB,MAAM,8BAA8B,CAAA;AAErC,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,GACzD,cAAc,CAUhB"}
@@ -0,0 +1,10 @@
1
+ export function createEntityMetadata(properties) {
2
+ return {
3
+ indexes: [],
4
+ properties: new Map(Object.entries(properties).map(([name, meta]) => [
5
+ name,
6
+ { name, indexes: [], ...meta },
7
+ ])),
8
+ };
9
+ }
10
+ //# sourceMappingURL=create-entity-metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-entity-metadata.js","sourceRoot":"","sources":["../../../src/constraints/__tests__/create-entity-metadata.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,oBAAoB,CAClC,UAA0D;IAE1D,OAAO;QACL,OAAO,EAAE,EAAE;QACX,UAAU,EAAE,IAAI,GAAG,CACjB,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;YAC/C,IAAI;YACJ,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE;SAC/B,CAAC,CACH;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { EntityMetadata, SerializedRow } from '../orm.js';
2
+ export declare function applyDefaultProperties(rows: SerializedRow[] | SerializedRow, entity: EntityMetadata, keys?: string[]): {
3
+ [x: string]: import("@t4h.framework/core").Serializable;
4
+ } | {
5
+ [x: string]: import("@t4h.framework/core").Serializable;
6
+ }[];
7
+ //# sourceMappingURL=apply-default-properties.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-default-properties.d.ts","sourceRoot":"","sources":["../../src/constraints/apply-default-properties.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAmB9D,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,aAAa,EAAE,GAAG,aAAa,EACrC,MAAM,EAAE,cAAc,EACtB,IAAI,CAAC,EAAE,MAAM,EAAE;;;;IAMhB"}
@@ -0,0 +1,16 @@
1
+ function applyDefaultPropertiesToRow(raw, entity, keys) {
2
+ const row = { ...raw };
3
+ for (const [name, meta] of entity.properties.entries()) {
4
+ if (keys && !keys.includes(name))
5
+ continue;
6
+ if (row[name] === undefined && meta.default !== undefined)
7
+ row[name] = meta.default;
8
+ }
9
+ return row;
10
+ }
11
+ export function applyDefaultProperties(rows, entity, keys) {
12
+ if (Array.isArray(rows))
13
+ return rows.map(raw => applyDefaultPropertiesToRow(raw, entity, keys));
14
+ return applyDefaultPropertiesToRow(rows, entity, keys);
15
+ }
16
+ //# sourceMappingURL=apply-default-properties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-default-properties.js","sourceRoot":"","sources":["../../src/constraints/apply-default-properties.ts"],"names":[],"mappings":"AAEA,SAAS,2BAA2B,CAClC,GAAkB,EAClB,MAAsB,EACtB,IAAe;IAEf,MAAM,GAAG,GAAG,EAAE,GAAG,GAAG,EAAE,CAAA;IAEtB,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAQ;QAE1C,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;YACvD,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAA;IAC5B,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,IAAqC,EACrC,MAAsB,EACtB,IAAe;IAEf,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QACrB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,2BAA2B,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;IAExE,OAAO,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAA;AACxD,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type EntityConstructor, type SerializedRow } from '../orm.js';
2
+ interface AssertConstraintsOptions {
3
+ keys?: string[];
4
+ }
5
+ export declare function assertConstraints<T>(entity: EntityConstructor<T>, rows: SerializedRow[], options?: AssertConstraintsOptions): Promise<void>;
6
+ export {};
7
+ //# sourceMappingURL=assert-constraints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-constraints.d.ts","sourceRoot":"","sources":["../../src/constraints/assert-constraints.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACnB,MAAM,WAAW,CAAA;AAIlB,UAAU,wBAAwB;IAChC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC5B,IAAI,EAAE,aAAa,EAAE,EACrB,OAAO,CAAC,EAAE,wBAAwB,iBAWnC"}
@@ -0,0 +1,13 @@
1
+ import { getEntityMetadata, } from '../orm.js';
2
+ import { assertNonNullablePropertyConstraint } from './assert-non-nullable-property-constraint.js';
3
+ import { assertPropertyTypeConstraint } from './assert-property-type-constraint.js';
4
+ export async function assertConstraints(entity, rows, options) {
5
+ const entityMetadata = getEntityMetadata(entity);
6
+ assertPropertyTypeConstraint(rows, entityMetadata, {
7
+ keys: options?.keys,
8
+ });
9
+ assertNonNullablePropertyConstraint(rows, entityMetadata, {
10
+ keys: options?.keys,
11
+ });
12
+ }
13
+ //# sourceMappingURL=assert-constraints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-constraints.js","sourceRoot":"","sources":["../../src/constraints/assert-constraints.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAGlB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,mCAAmC,EAAE,MAAM,8CAA8C,CAAA;AAClG,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAA;AAMnF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAA4B,EAC5B,IAAqB,EACrB,OAAkC;IAElC,MAAM,cAAc,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;IAEhD,4BAA4B,CAAC,IAAI,EAAE,cAAc,EAAE;QACjD,IAAI,EAAE,OAAO,EAAE,IAAI;KACpB,CAAC,CAAA;IAEF,mCAAmC,CAAC,IAAI,EAAE,cAAc,EAAE;QACxD,IAAI,EAAE,OAAO,EAAE,IAAI;KACpB,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { EntityMetadata, SerializedRow } from '../orm.js';
2
+ interface AssertNonNullablePropertyConstraintOptions {
3
+ keys?: string[];
4
+ }
5
+ export declare function assertNonNullablePropertyConstraint(rows: SerializedRow[], entity: EntityMetadata, options?: AssertNonNullablePropertyConstraintOptions): void;
6
+ export {};
7
+ //# sourceMappingURL=assert-non-nullable-property-constraint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-non-nullable-property-constraint.d.ts","sourceRoot":"","sources":["../../src/constraints/assert-non-nullable-property-constraint.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE9D,UAAU,0CAA0C;IAClD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,aAAa,EAAE,EACrB,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE,0CAA0C,QAYrD"}
@@ -0,0 +1,14 @@
1
+ import { ConstraintError } from '../errors/ConstraintError.js';
2
+ export function assertNonNullablePropertyConstraint(rows, entity, options) {
3
+ rows.forEach(row => {
4
+ for (const [name, meta] of entity.properties.entries()) {
5
+ if (options?.keys && !options.keys.includes(name))
6
+ continue;
7
+ if (meta.nullable)
8
+ continue;
9
+ if (row[name] === null || row[name] === undefined)
10
+ throw new ConstraintError(`Property "${name}" is required`);
11
+ }
12
+ });
13
+ }
14
+ //# sourceMappingURL=assert-non-nullable-property-constraint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-non-nullable-property-constraint.js","sourceRoot":"","sources":["../../src/constraints/assert-non-nullable-property-constraint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAO9D,MAAM,UAAU,mCAAmC,CACjD,IAAqB,EACrB,MAAsB,EACtB,OAAoD;IAEpD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;QACjB,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;YACvD,IAAI,OAAO,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,SAAQ;YAE3D,IAAI,IAAI,CAAC,QAAQ;gBAAE,SAAQ;YAE3B,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS;gBAC/C,MAAM,IAAI,eAAe,CAAC,aAAa,IAAI,eAAe,CAAC,CAAA;QAC/D,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { EntityMetadata, SerializedRow } from '../orm.js';
2
+ interface AssertPropertyTypeConstraintOptions {
3
+ keys?: string[];
4
+ }
5
+ export declare function assertPropertyTypeConstraint(rows: SerializedRow[], entity: EntityMetadata, options?: AssertPropertyTypeConstraintOptions): void;
6
+ export {};
7
+ //# sourceMappingURL=assert-property-type-constraint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-property-type-constraint.d.ts","sourceRoot":"","sources":["../../src/constraints/assert-property-type-constraint.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAgB9D,UAAU,mCAAmC;IAC3C,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,aAAa,EAAE,EACrB,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE,mCAAmC,QAyB9C"}
@@ -0,0 +1,30 @@
1
+ import { ConstraintError } from '../errors/ConstraintError.js';
2
+ const UUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
3
+ const PROPERTY_TYPE = {
4
+ string: (value) => typeof value === 'string',
5
+ uuid: (value) => typeof value === 'string' && UUID_REGEX.test(value),
6
+ number: (value) => typeof value === 'number' && !Number.isNaN(value),
7
+ boolean: (value) => typeof value === 'boolean',
8
+ array: (value) => Array.isArray(value),
9
+ date: (value) => value instanceof Date || typeof value === 'string',
10
+ object: (value) => typeof value === 'object' && value !== null && !Array.isArray(value),
11
+ };
12
+ export function assertPropertyTypeConstraint(rows, entity, options) {
13
+ rows.forEach(row => {
14
+ for (const [name, meta] of entity.properties.entries()) {
15
+ if (options?.keys && !options.keys.includes(name))
16
+ continue;
17
+ const value = row[name];
18
+ if (!meta.type)
19
+ continue;
20
+ if (value === undefined || value === null)
21
+ continue;
22
+ const validator = PROPERTY_TYPE[meta.type];
23
+ if (!validator)
24
+ throw new ConstraintError(`Property "${name}" has unsupported type "${meta.type}"`);
25
+ if (!validator(value))
26
+ throw new ConstraintError(`Property "${name}" must be of type ${meta.type}`);
27
+ }
28
+ });
29
+ }
30
+ //# sourceMappingURL=assert-property-type-constraint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-property-type-constraint.js","sourceRoot":"","sources":["../../src/constraints/assert-property-type-constraint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAG9D,MAAM,UAAU,GACd,+EAA+E,CAAA;AAEjF,MAAM,aAAa,GAAG;IACpB,MAAM,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ;IACrD,IAAI,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;IAC7E,MAAM,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;IAC7E,OAAO,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,SAAS;IACvD,KAAK,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;IAC/C,IAAI,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,KAAK,YAAY,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;IAC5E,MAAM,EAAE,CAAC,KAAc,EAAE,EAAE,CACzB,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;CACvE,CAAA;AAMD,MAAM,UAAU,4BAA4B,CAC1C,IAAqB,EACrB,MAAsB,EACtB,OAA6C;IAE7C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;QACjB,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;YACvD,IAAI,OAAO,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,SAAQ;YAE3D,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;YAEvB,IAAI,CAAC,IAAI,CAAC,IAAI;gBAAE,SAAQ;YAExB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;gBAAE,SAAQ;YAEnD,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,IAAkC,CAAC,CAAA;YAExE,IAAI,CAAC,SAAS;gBACZ,MAAM,IAAI,eAAe,CACvB,aAAa,IAAI,2BAA2B,IAAI,CAAC,IAAI,GAAG,CACzD,CAAA;YAEH,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;gBACnB,MAAM,IAAI,eAAe,CACvB,aAAa,IAAI,qBAAqB,IAAI,CAAC,IAAI,EAAE,CAClD,CAAA;QACL,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Serializable } from '@t4h.framework/core';
2
+ import type { EntityMetadata, SerializedRow } from '../orm.js';
3
+ import type { FindWhere } from '../typings/FindWhere.js';
4
+ interface AssertUniqueConstraintOptions<T> {
5
+ keys?: string[];
6
+ validator: (where: FindWhere<T>) => Promise<unknown>;
7
+ isUnchanged?: (name: string, value: Serializable) => boolean;
8
+ }
9
+ export declare function assertUniqueConstraint<T>(rows: SerializedRow[], entity: EntityMetadata, options: AssertUniqueConstraintOptions<T>): Promise<void>;
10
+ export {};
11
+ //# sourceMappingURL=assert-unique-constraint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-unique-constraint.d.ts","sourceRoot":"","sources":["../../src/constraints/assert-unique-constraint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAGvD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAExD,UAAU,6BAA6B,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,SAAS,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACpD,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAA;CAC7D;AA6BD,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,IAAI,EAAE,aAAa,EAAE,EACrB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,6BAA6B,CAAC,CAAC,CAAC,iBA6B1C"}