@t4h.framework/orm 0.4.0 → 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.
@@ -6,7 +6,7 @@ description: >-
6
6
  exists), Ref and RefCollection, query operators, constraint validation, ORM
7
7
  activities, and ORMClaim wiring. Use when defining database entities, persisting
8
8
  or querying rows in workflows, implementing ORMClaim providers, testing ORM
9
- activities with Claim.run, or working in packages/orm.
9
+ workflows with TestWorkflowEnvironment, or working in packages/orm.
10
10
  ---
11
11
 
12
12
  # @t4h.framework/orm
@@ -41,11 +41,9 @@ Node `>=22`. See [README.md](../../../README.md).
41
41
  |-------|------|
42
42
  | **ORM** | High-level API; applies defaults + constraints before activities |
43
43
  | **Ref** / **RefCollection** | Row handles returned by create/find |
44
- | **Activities** | `SyncActivity` classes delegating to `ORMClaim` |
44
+ | **Activities** | Shipped, replay-safe activities the `ORM`/`Ref` APIs drive; delegate to `ORMClaim` |
45
45
  | **ORMClaim** | Abstract claim; runtime provides concrete DB implementation |
46
46
 
47
- All ORM activities use `new Claim({ orm: ORMClaim })` and delegate in `run()`.
48
-
49
47
  ---
50
48
 
51
49
  ## Defining entities
@@ -171,7 +169,7 @@ const exists = await orm.exists(User, {
171
169
  ### Ref operations
172
170
 
173
171
  ```typescript
174
- const snapshot = await userRef.getSnapshot() // T | null — entity instance via Reflect.construct
172
+ const snapshot = await userRef.getSnapshot() // T | null — entity instance
175
173
  await userRef.update({ name: 'Jane' }) // partial patch only
176
174
  await userRef.remove()
177
175
  ```
@@ -260,13 +258,13 @@ abstract class ORMClaim<R extends SerializableRowRef> {
260
258
 
261
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`.
262
260
 
263
- Access claim-backed activity logic only inside `Claim.run` or workflow `History.run` context.
261
+ The `ORM`/`Ref` calls run inside a workflow (the runtime, or `TestWorkflowEnvironment` in tests, provides the reconciler context).
264
262
 
265
263
  ---
266
264
 
267
265
  ## Activities
268
266
 
269
- All extend `SyncActivity` and delegate to `ORMClaim`:
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:
270
268
 
271
269
  | Activity | Input | Output |
272
270
  |----------|-------|--------|
@@ -283,7 +281,7 @@ Prefer **`ORM` / `Ref` APIs** in workflow code — they apply constraints and re
283
281
 
284
282
  ## Workflow example
285
283
 
286
- From `examples/basic/src/workflows/orm.ts` — define entities, instantiate `ORM` with `connectionString` + `entities`, use inside `Workflow`:
284
+ Define entities, instantiate `ORM` with `connectionString` + `entities`, and use it inside a `Workflow`:
287
285
 
288
286
  ```typescript
289
287
  export const orm = new ORM({ connectionString: '...', entities: [User] })
@@ -303,13 +301,29 @@ Ensure the runtime provides `ORMClaim`.
303
301
 
304
302
  ## Testing
305
303
 
306
- Run: `yarn test` in `packages/orm`.
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' }))
307
316
 
308
- **ORM / Ref unit tests** — mock `History.bind` by activity name (`ORMCreateActivity`, `ORMFindOneActivity`, etc.) per `src/models/__tests__/ORM.spec.ts`. Assert `ConstraintError` before activities run: `expect(mockCreate).not.toHaveBeenCalled()`.
317
+ const env = TestWorkflowEnvironment.create({ now: 0 })
309
318
 
310
- **Activity unit tests** — wrap `activity.run(input)` in `Claim.run([{ provide: ORMClaim, value: mockClaim }], fn)` per `src/activities/__tests__/ORMCreateActivity.spec.ts`.
319
+ await env.execute(workflow, input, {
320
+ claims: [mockClaim(ORMClaim, { create: mockCreate, findOne: mockFindOne })],
321
+ })
322
+ ```
311
323
 
312
- **Workflow integration** — `WorkflowTesting.run` with a mocked `ORMClaim` provider (see **framework-core** skill).
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()`.
313
327
 
314
328
  ---
315
329
 
@@ -320,6 +334,6 @@ Run: `yarn test` in `packages/orm`.
320
334
  3. Use **`orm` / `Ref` APIs** in workflows — not raw SQL or direct claim calls.
321
335
  4. Handle **`ConstraintError`**; validation runs before activities.
322
336
  5. **`Ref.update`** is partial; **`getSnapshot`** returns entity instances.
323
- 6. Test with **`History.bind` mocks** or **`Claim.run` + ORMClaim mock**; only use exported APIs.
337
+ 6. Test workflows with **`TestWorkflowEnvironment`** + **`mockClaim(ORMClaim, ...)`**; only use exported APIs.
324
338
 
325
- See also: `packages/orm/README.md`, `examples/basic/src/workflows/orm.ts`.
339
+ See also: `packages/orm/README.md`; **framework-workflow-testing** for the test harness.
@@ -0,0 +1,4 @@
1
+ import type { ClaimProvider } from '@t4h.framework/core';
2
+ import { ORMClaim } from '../claims/ORMClaim.js';
3
+ export declare function createInMemoryORMClaim(): ClaimProvider<ORMClaim<string>>;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGxD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAUhD,wBAAgB,sBAAsB,IAAI,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CA2DxE"}
@@ -0,0 +1,52 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mockClaim } from '@t4h.framework/core/testing';
3
+ import { ORMClaim } from '../claims/ORMClaim.js';
4
+ export function createInMemoryORMClaim() {
5
+ const tables = new Map();
6
+ const table = (name) => {
7
+ let rows = tables.get(name);
8
+ if (!rows) {
9
+ rows = new Map();
10
+ tables.set(name, rows);
11
+ }
12
+ return rows;
13
+ };
14
+ const claim = {
15
+ find(input) {
16
+ const rows = [...table(input.table).values()];
17
+ return rows
18
+ .filter(row => matchesWhere(row, input.where))
19
+ .slice(input.offset ?? 0, input.limit ? (input.offset ?? 0) + input.limit : undefined)
20
+ .map(row => row.id);
21
+ },
22
+ create(input) {
23
+ const rows = table(input.table);
24
+ return input.data.map(row => {
25
+ const id = String(row.id ?? randomUUID());
26
+ const snapshot = { ...row, id };
27
+ rows.set(id, snapshot);
28
+ return id;
29
+ });
30
+ },
31
+ getSnapshot(input) {
32
+ return table(input.table).get(input.ref) ?? null;
33
+ },
34
+ update(input) {
35
+ const rows = table(input.table);
36
+ const current = rows.get(input.ref);
37
+ if (!current)
38
+ return;
39
+ rows.set(input.ref, { ...current, ...input.data });
40
+ },
41
+ remove(input) {
42
+ table(input.table).delete(input.ref);
43
+ },
44
+ };
45
+ return mockClaim(ORMClaim, claim);
46
+ }
47
+ function matchesWhere(row, where) {
48
+ if (!where)
49
+ return true;
50
+ return Object.entries(where).every(([key, expected]) => row[key] === expected);
51
+ }
52
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t4h.framework/orm",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "ORM module for the T4H Framework",
5
5
  "homepage": "https://github.com/tech4humans-brasil/framework/tree/main/packages/orm",
6
6
  "bugs": "https://github.com/tech4humans-brasil/framework/issues",
@@ -35,12 +35,12 @@
35
35
  "reflect-metadata": "^0.2.2"
36
36
  },
37
37
  "devDependencies": {
38
- "@t4h.framework/core": "^0.6.0",
38
+ "@t4h.framework/core": "^0.9.0",
39
39
  "typescript": "^5.9.3",
40
40
  "vitest": "^4.0.18"
41
41
  },
42
42
  "peerDependencies": {
43
- "@t4h.framework/core": "^0.6.0"
43
+ "@t4h.framework/core": "^0.9.0"
44
44
  },
45
45
  "packageManager": "yarn@4.12.0",
46
46
  "engines": {