@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.
Files changed (109) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +37 -20
  3. package/dist/base-entity.d.ts +1 -1
  4. package/dist/base-entity.d.ts.map +1 -1
  5. package/dist/base-entity.js +21 -15
  6. package/dist/base-entity.js.map +1 -1
  7. package/dist/constants.js +4 -1
  8. package/dist/constants.js.map +1 -1
  9. package/dist/criteria.d.ts.map +1 -1
  10. package/dist/criteria.js +7 -3
  11. package/dist/criteria.js.map +1 -1
  12. package/dist/deep-proxy.d.ts +3 -1
  13. package/dist/deep-proxy.d.ts.map +1 -1
  14. package/dist/deep-proxy.js +110 -33
  15. package/dist/deep-proxy.js.map +1 -1
  16. package/dist/domain-event-bus.js +7 -2
  17. package/dist/domain-event-bus.js.map +1 -1
  18. package/dist/domain-event.js +7 -3
  19. package/dist/domain-event.js.map +1 -1
  20. package/dist/entity.js +8 -3
  21. package/dist/entity.js.map +1 -1
  22. package/dist/id.d.ts +3 -3
  23. package/dist/id.d.ts.map +1 -1
  24. package/dist/id.js +10 -6
  25. package/dist/id.js.map +1 -1
  26. package/dist/index.d.ts +0 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +39 -17
  29. package/dist/index.js.map +1 -1
  30. package/dist/mapper.js +5 -1
  31. package/dist/mapper.js.map +1 -1
  32. package/dist/paginated-result.js +7 -3
  33. package/dist/paginated-result.js.map +1 -1
  34. package/dist/repository/base-repository.js +11 -4
  35. package/dist/repository/base-repository.js.map +1 -1
  36. package/dist/repository/in-memory-repository.js +8 -4
  37. package/dist/repository/in-memory-repository.js.map +1 -1
  38. package/dist/repository/index.d.ts +1 -37
  39. package/dist/repository/index.d.ts.map +1 -1
  40. package/dist/repository/index.js +26 -40
  41. package/dist/repository/index.js.map +1 -1
  42. package/dist/repository/unit-of-work.js +9 -3
  43. package/dist/repository/unit-of-work.js.map +1 -1
  44. package/dist/types/criteria.d.ts +2 -2
  45. package/dist/types/criteria.d.ts.map +1 -1
  46. package/dist/types/criteria.js +4 -1
  47. package/dist/types/criteria.js.map +1 -1
  48. package/dist/types/domain.js +2 -1
  49. package/dist/types/history-tracker.js +2 -1
  50. package/dist/types/index.js +22 -6
  51. package/dist/types/index.js.map +1 -1
  52. package/dist/types/standard-schema.js +2 -1
  53. package/dist/types/unit-of-work.js +2 -1
  54. package/dist/types/utils.js +2 -1
  55. package/dist/validation-error.js +9 -3
  56. package/dist/validation-error.js.map +1 -1
  57. package/dist/value-object.js +9 -5
  58. package/dist/value-object.js.map +1 -1
  59. package/package.json +1 -1
  60. package/src/base-entity.ts +3 -2
  61. package/src/criteria.ts +2 -2
  62. package/src/deep-proxy.ts +435 -339
  63. package/src/id.ts +4 -4
  64. package/src/index.ts +1 -3
  65. package/src/repository/index.ts +1 -38
  66. package/src/types/criteria.ts +2 -2
  67. package/tests/entity-validation.test.ts +1 -1
  68. package/tests/history-tracker.spec.ts +57 -17
  69. package/tests/id.test.ts +341 -341
  70. package/tests/repository.test.ts +4 -2
  71. package/tests/to-json.test.ts +103 -91
  72. package/tests/value-objects.test.ts +52 -52
  73. package/tsconfig.json +2 -2
  74. package/dist/filtering.d.ts +0 -107
  75. package/dist/filtering.d.ts.map +0 -1
  76. package/dist/filtering.js +0 -202
  77. package/dist/filtering.js.map +0 -1
  78. package/dist/ordering.d.ts +0 -93
  79. package/dist/ordering.d.ts.map +0 -1
  80. package/dist/ordering.js +0 -154
  81. package/dist/ordering.js.map +0 -1
  82. package/dist/pagination.d.ts +0 -218
  83. package/dist/pagination.d.ts.map +0 -1
  84. package/dist/pagination.js +0 -281
  85. package/dist/pagination.js.map +0 -1
  86. package/dist/repository/mapper.d.ts +0 -56
  87. package/dist/repository/mapper.d.ts.map +0 -1
  88. package/dist/repository/mapper.js +0 -15
  89. package/dist/repository/mapper.js.map +0 -1
  90. package/dist/repository/types.d.ts +0 -87
  91. package/dist/repository/types.d.ts.map +0 -1
  92. package/dist/repository/types.js +0 -6
  93. package/dist/repository/types.js.map +0 -1
  94. package/dist/repository.d.ts +0 -2
  95. package/dist/repository.d.ts.map +0 -1
  96. package/dist/repository.js +0 -21
  97. package/dist/repository.js.map +0 -1
  98. package/dist/specification.d.ts +0 -102
  99. package/dist/specification.d.ts.map +0 -1
  100. package/dist/specification.js +0 -187
  101. package/dist/specification.js.map +0 -1
  102. package/dist/types/repository.d.ts +0 -43
  103. package/dist/types/repository.d.ts.map +0 -1
  104. package/dist/types/repository.js +0 -2
  105. package/dist/types/repository.js.map +0 -1
  106. package/dist/types.d.ts +0 -88
  107. package/dist/types.d.ts.map +0 -1
  108. package/dist/types.js +0 -12
  109. package/dist/types.js.map +0 -1
package/src/id.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { randomUUID } from 'crypto';
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
- * newId.isNew // true
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
- * existingId.isNew // false
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
- get isNew(): boolean {
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 & Repository
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";
@@ -6,7 +6,7 @@
6
6
  export { Mapper } from "../mapper";
7
7
 
8
8
  // Base implementations
9
- export { Repository as BaseRepository } from "./base-repository";
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
- */
@@ -1,6 +1,6 @@
1
1
  import { Primitive } from "./utils";
2
2
 
3
- export const FilterOperator = [
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 FilterOperator)[number];
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 post = new Post({
7
+ const user = new User({
8
8
  id: new Id("1"),
9
- title: "First Post",
10
- content: "Hello World",
11
- likes: 0,
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
- let changeCount = 0;
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
- post.subscribe({
17
- title: {
18
- onChange: ({ previous, current, path }) => {
19
- changeCount++;
20
- expect(previous).toBe("First Post");
21
- expect(current).toBe("Updated Title");
22
- expect(path).toBe("title");
23
- done();
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
- post.title = "Updated Title";
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", () => {