@woltz/rich-domain 0.2.2 → 1.0.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/CHANGELOG.md +30 -0
- package/README.md +37 -20
- package/dist/base-entity.d.ts +1 -1
- package/dist/base-entity.d.ts.map +1 -1
- package/dist/base-entity.js +21 -15
- package/dist/base-entity.js.map +1 -1
- package/dist/constants.js +4 -1
- package/dist/constants.js.map +1 -1
- package/dist/criteria.d.ts.map +1 -1
- package/dist/criteria.js +7 -3
- package/dist/criteria.js.map +1 -1
- package/dist/deep-proxy.d.ts +3 -1
- package/dist/deep-proxy.d.ts.map +1 -1
- package/dist/deep-proxy.js +110 -33
- package/dist/deep-proxy.js.map +1 -1
- package/dist/domain-event-bus.js +7 -2
- package/dist/domain-event-bus.js.map +1 -1
- package/dist/domain-event.js +7 -3
- package/dist/domain-event.js.map +1 -1
- package/dist/entity.js +8 -3
- package/dist/entity.js.map +1 -1
- package/dist/id.d.ts +3 -3
- package/dist/id.d.ts.map +1 -1
- package/dist/id.js +10 -6
- package/dist/id.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -17
- package/dist/index.js.map +1 -1
- package/dist/mapper.js +5 -1
- package/dist/mapper.js.map +1 -1
- package/dist/paginated-result.js +7 -3
- package/dist/paginated-result.js.map +1 -1
- package/dist/repository/base-repository.js +11 -4
- package/dist/repository/base-repository.js.map +1 -1
- package/dist/repository/in-memory-repository.js +8 -4
- package/dist/repository/in-memory-repository.js.map +1 -1
- package/dist/repository/index.d.ts +1 -37
- package/dist/repository/index.d.ts.map +1 -1
- package/dist/repository/index.js +26 -40
- package/dist/repository/index.js.map +1 -1
- package/dist/repository/unit-of-work.js +9 -3
- package/dist/repository/unit-of-work.js.map +1 -1
- package/dist/types/criteria.d.ts +2 -2
- package/dist/types/criteria.d.ts.map +1 -1
- package/dist/types/criteria.js +4 -1
- package/dist/types/criteria.js.map +1 -1
- package/dist/types/domain.js +2 -1
- package/dist/types/history-tracker.js +2 -1
- package/dist/types/index.js +22 -6
- package/dist/types/index.js.map +1 -1
- package/dist/types/standard-schema.js +2 -1
- package/dist/types/unit-of-work.js +2 -1
- package/dist/types/utils.js +2 -1
- package/dist/validation-error.js +9 -3
- package/dist/validation-error.js.map +1 -1
- package/dist/value-object.js +9 -5
- package/dist/value-object.js.map +1 -1
- package/package.json +1 -1
- package/src/base-entity.ts +3 -2
- package/src/criteria.ts +2 -2
- package/src/deep-proxy.ts +435 -339
- package/src/id.ts +4 -4
- package/src/index.ts +1 -3
- package/src/repository/index.ts +1 -38
- package/src/types/criteria.ts +2 -2
- package/tests/entity-validation.test.ts +1 -1
- package/tests/history-tracker.spec.ts +57 -17
- package/tests/id.test.ts +341 -341
- package/tests/repository.test.ts +4 -2
- package/tests/to-json.test.ts +103 -91
- package/tests/value-objects.test.ts +52 -52
- package/tsconfig.json +2 -2
- package/dist/filtering.d.ts +0 -107
- package/dist/filtering.d.ts.map +0 -1
- package/dist/filtering.js +0 -202
- package/dist/filtering.js.map +0 -1
- package/dist/ordering.d.ts +0 -93
- package/dist/ordering.d.ts.map +0 -1
- package/dist/ordering.js +0 -154
- package/dist/ordering.js.map +0 -1
- package/dist/pagination.d.ts +0 -218
- package/dist/pagination.d.ts.map +0 -1
- package/dist/pagination.js +0 -281
- package/dist/pagination.js.map +0 -1
- package/dist/repository/mapper.d.ts +0 -56
- package/dist/repository/mapper.d.ts.map +0 -1
- package/dist/repository/mapper.js +0 -15
- package/dist/repository/mapper.js.map +0 -1
- package/dist/repository/types.d.ts +0 -87
- package/dist/repository/types.d.ts.map +0 -1
- package/dist/repository/types.js +0 -6
- package/dist/repository/types.js.map +0 -1
- package/dist/repository.d.ts +0 -2
- package/dist/repository.d.ts.map +0 -1
- package/dist/repository.js +0 -21
- package/dist/repository.js.map +0 -1
- package/dist/specification.d.ts +0 -102
- package/dist/specification.d.ts.map +0 -1
- package/dist/specification.js +0 -187
- package/dist/specification.js.map +0 -1
- package/dist/types/repository.d.ts +0 -43
- package/dist/types/repository.d.ts.map +0 -1
- package/dist/types/repository.js +0 -2
- package/dist/types/repository.js.map +0 -1
- package/dist/types.d.ts +0 -88
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -12
- package/dist/types.js.map +0 -1
package/src/id.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { randomUUID } from
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
2
|
// ============================================================================
|
|
3
3
|
// Id Class - Smart Identity Management
|
|
4
4
|
// ============================================================================
|
|
@@ -14,11 +14,11 @@ export class Id {
|
|
|
14
14
|
* @example
|
|
15
15
|
* // New entity (generates UUID)
|
|
16
16
|
* const newId = new Id();
|
|
17
|
-
*
|
|
17
|
+
* newuser.isNew() // true
|
|
18
18
|
*
|
|
19
19
|
* // Existing entity (uses provided ID)
|
|
20
20
|
* const existingId = new Id("550e8400-e29b-41d4-a716-446655440000");
|
|
21
|
-
*
|
|
21
|
+
* existinguser.isNew() // false
|
|
22
22
|
*/
|
|
23
23
|
constructor(value?: string) {
|
|
24
24
|
if (value !== undefined) {
|
|
@@ -42,7 +42,7 @@ export class Id {
|
|
|
42
42
|
/**
|
|
43
43
|
* Check if this ID represents a new entity
|
|
44
44
|
*/
|
|
45
|
-
|
|
45
|
+
public isNew(): boolean {
|
|
46
46
|
return this._isNew;
|
|
47
47
|
}
|
|
48
48
|
|
package/src/index.ts
CHANGED
|
@@ -16,14 +16,12 @@ export * from "./domain-event";
|
|
|
16
16
|
|
|
17
17
|
export * from "./domain-event-bus";
|
|
18
18
|
|
|
19
|
-
// Criteria
|
|
19
|
+
// Criteria
|
|
20
20
|
export * from "./criteria";
|
|
21
21
|
export * from "./paginated-result";
|
|
22
22
|
|
|
23
23
|
// Repository
|
|
24
24
|
export * from "./repository";
|
|
25
|
-
// Backward compatibility - re-export InMemoryRepository at top level
|
|
26
|
-
export { InMemoryRepository } from "./repository";
|
|
27
25
|
|
|
28
26
|
// Types
|
|
29
27
|
export * from "./types";
|
package/src/repository/index.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
export { Mapper } from "../mapper";
|
|
7
7
|
|
|
8
8
|
// Base implementations
|
|
9
|
-
export
|
|
9
|
+
export * from "./base-repository";
|
|
10
10
|
export { InMemoryRepository } from "./in-memory-repository";
|
|
11
11
|
|
|
12
12
|
// Unit of Work
|
|
@@ -15,40 +15,3 @@ export {
|
|
|
15
15
|
BaseTransactionContext,
|
|
16
16
|
InMemoryUnitOfWork,
|
|
17
17
|
} from "./unit-of-work";
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* QUICK START:
|
|
21
|
-
*
|
|
22
|
-
* 1. For Testing:
|
|
23
|
-
* ```ts
|
|
24
|
-
* import { InMemoryRepository } from 'rich-domain';
|
|
25
|
-
*
|
|
26
|
-
* const userRepo = new InMemoryRepository<User>();
|
|
27
|
-
* await userRepo.save(user);
|
|
28
|
-
* const found = await userRepo.findById(user.id);
|
|
29
|
-
* ```
|
|
30
|
-
*
|
|
31
|
-
* 2. For Production (Prisma, TypeORM, etc):
|
|
32
|
-
* - Extend BaseRepository
|
|
33
|
-
* - Implement abstract methods
|
|
34
|
-
* - Create a Mapper
|
|
35
|
-
* - See examples/ folder for reference
|
|
36
|
-
*
|
|
37
|
-
* 3. With Criteria:
|
|
38
|
-
* ```ts
|
|
39
|
-
* const result = await userRepo.find(
|
|
40
|
-
* Criteria.create<User>()
|
|
41
|
-
* .whereEquals('status', 'active')
|
|
42
|
-
* .orderByDesc('createdAt')
|
|
43
|
-
* .paginate(1, 10)
|
|
44
|
-
* );
|
|
45
|
-
* ```
|
|
46
|
-
*
|
|
47
|
-
* 4. With Unit of Work:
|
|
48
|
-
* ```ts
|
|
49
|
-
* await uow.transaction(async (ctx) => {
|
|
50
|
-
* const userRepo = uow.getRepository(UserRepository);
|
|
51
|
-
* await userRepo.save(user);
|
|
52
|
-
* });
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
package/src/types/criteria.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Primitive } from "./utils";
|
|
2
2
|
|
|
3
|
-
export const
|
|
3
|
+
export const FILTER_OPERATORS = [
|
|
4
4
|
"equals",
|
|
5
5
|
"notEquals",
|
|
6
6
|
"greaterThan",
|
|
@@ -36,7 +36,7 @@ export type PathValue<
|
|
|
36
36
|
? T[P]
|
|
37
37
|
: never;
|
|
38
38
|
|
|
39
|
-
export type FilterOperator = (typeof
|
|
39
|
+
export type FilterOperator = (typeof FILTER_OPERATORS)[number];
|
|
40
40
|
|
|
41
41
|
export interface Filter<TField = string, TValue = unknown> {
|
|
42
42
|
field: TField;
|
|
@@ -134,7 +134,7 @@ describe("Rich Domain with Standard Schema Validation", () => {
|
|
|
134
134
|
expect(user.name).toBe("John Doe");
|
|
135
135
|
expect(user.email).toBe("john@example.com");
|
|
136
136
|
expect(user.age).toBe(25);
|
|
137
|
-
expect(user.isNew).toBe(true);
|
|
137
|
+
expect(user.isNew()).toBe(true);
|
|
138
138
|
});
|
|
139
139
|
|
|
140
140
|
it("should throw on invalid email", () => {
|
|
@@ -4,28 +4,68 @@ import { Post, User, Address, Comment } from "./utils";
|
|
|
4
4
|
describe("History Tracker Tests", () => {
|
|
5
5
|
describe("Simple Property Changes", () => {
|
|
6
6
|
it("should track simple property changes", (done) => {
|
|
7
|
-
const
|
|
7
|
+
const user = new User({
|
|
8
8
|
id: new Id("1"),
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
name: "John Doe",
|
|
10
|
+
email: "john@example.com",
|
|
11
|
+
posts: [
|
|
12
|
+
new Post({
|
|
13
|
+
id: new Id("1"),
|
|
14
|
+
title: "First Post",
|
|
15
|
+
content: "Hello World",
|
|
16
|
+
likes: 0,
|
|
17
|
+
}),
|
|
18
|
+
],
|
|
19
|
+
address: new Address({
|
|
20
|
+
street: "Main St",
|
|
21
|
+
city: "NYC",
|
|
22
|
+
zipCode: "10001",
|
|
23
|
+
}),
|
|
24
|
+
comments: [],
|
|
12
25
|
});
|
|
13
26
|
|
|
14
|
-
|
|
27
|
+
user.changeEmail("new@example.com");
|
|
28
|
+
user.name = "New Name";
|
|
29
|
+
user.addPost(
|
|
30
|
+
new Post({
|
|
31
|
+
id: new Id("2"),
|
|
32
|
+
title: "Second Post",
|
|
33
|
+
content: "Hello World 2",
|
|
34
|
+
likes: 0,
|
|
35
|
+
})
|
|
36
|
+
);
|
|
15
37
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
38
|
+
function dispatch(entity: User) {
|
|
39
|
+
entity.subscribe({
|
|
40
|
+
email: {
|
|
41
|
+
onChange: ({ previous, current, path }) => {
|
|
42
|
+
expect(previous).toBe("john@example.com");
|
|
43
|
+
expect(current).toBe("new@example.com");
|
|
44
|
+
expect(path).toBe("email");
|
|
45
|
+
},
|
|
24
46
|
},
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
47
|
+
posts: {
|
|
48
|
+
onChange: ({ toCreate, toUpdate, toDelete }) => {
|
|
49
|
+
expect(toCreate).toHaveLength(1);
|
|
50
|
+
expect(toUpdate).toHaveLength(1);
|
|
51
|
+
expect(toDelete).toHaveLength(0);
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
name: {
|
|
55
|
+
onChange: ({ previous, current, path }) => {
|
|
56
|
+
expect(previous).toBe("John Doe");
|
|
57
|
+
expect(current).toBe("New Name");
|
|
58
|
+
expect(path).toBe("name");
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
user.posts[0].title = "Updated Title";
|
|
64
|
+
dispatch(user);
|
|
65
|
+
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
done();
|
|
68
|
+
}, 100);
|
|
29
69
|
});
|
|
30
70
|
|
|
31
71
|
it("should track multiple property changes", () => {
|