@woltz/rich-domain 1.2.0 → 1.2.2
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 +58 -0
- package/dist/aggregate-changes.d.ts +164 -0
- package/dist/aggregate-changes.d.ts.map +1 -0
- package/dist/aggregate-changes.js +281 -0
- package/dist/aggregate-changes.js.map +1 -0
- package/dist/base-entity.d.ts +32 -8
- package/dist/base-entity.d.ts.map +1 -1
- package/dist/base-entity.js +86 -93
- package/dist/base-entity.js.map +1 -1
- package/dist/change-tracker.d.ts +97 -0
- package/dist/change-tracker.d.ts.map +1 -0
- package/dist/change-tracker.js +758 -0
- package/dist/change-tracker.js.map +1 -0
- package/dist/constants.d.ts +7 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +65 -0
- package/dist/constants.js.map +1 -1
- package/dist/criteria.d.ts +3 -3
- package/dist/criteria.d.ts.map +1 -1
- package/dist/criteria.js +6 -4
- package/dist/criteria.js.map +1 -1
- package/dist/crypto.d.ts +3 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +29 -0
- package/dist/crypto.js.map +1 -0
- package/dist/domain-event.d.ts.map +1 -1
- package/dist/domain-event.js +0 -3
- package/dist/domain-event.js.map +1 -1
- package/dist/entity-changes.d.ts +84 -0
- package/dist/entity-changes.d.ts.map +1 -0
- package/dist/entity-changes.js +131 -0
- package/dist/entity-changes.js.map +1 -0
- package/dist/entity-schema-registry.d.ts +148 -0
- package/dist/entity-schema-registry.d.ts.map +1 -0
- package/dist/entity-schema-registry.js +213 -0
- package/dist/entity-schema-registry.js.map +1 -0
- package/dist/entity.d.ts +0 -6
- package/dist/entity.d.ts.map +1 -1
- package/dist/entity.js +0 -9
- package/dist/entity.js.map +1 -1
- package/dist/id.d.ts +11 -10
- package/dist/id.d.ts.map +1 -1
- package/dist/id.js +4 -28
- package/dist/id.js.map +1 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -11
- package/dist/index.js.map +1 -1
- package/dist/mapper.d.ts +1 -1
- package/dist/mapper.d.ts.map +1 -1
- package/dist/mapper.js.map +1 -1
- package/dist/paginated-result.d.ts.map +1 -1
- package/dist/paginated-result.js +0 -15
- package/dist/paginated-result.js.map +1 -1
- package/dist/repository/base-repository.d.ts +7 -33
- package/dist/repository/base-repository.d.ts.map +1 -1
- package/dist/repository/base-repository.js +0 -27
- package/dist/repository/base-repository.js.map +1 -1
- package/dist/repository/index.d.ts.map +1 -1
- package/dist/repository/index.js +0 -6
- package/dist/repository/index.js.map +1 -1
- package/dist/repository/unit-of-work.d.ts +0 -25
- package/dist/repository/unit-of-work.d.ts.map +1 -1
- package/dist/repository/unit-of-work.js +0 -28
- package/dist/repository/unit-of-work.js.map +1 -1
- package/dist/types/change-tracker.d.ts +196 -0
- package/dist/types/change-tracker.d.ts.map +1 -0
- package/dist/types/change-tracker.js +2 -0
- package/dist/types/change-tracker.js.map +1 -0
- package/dist/types/criteria.d.ts +5 -1
- package/dist/types/criteria.d.ts.map +1 -1
- package/dist/types/domain.d.ts +4 -6
- package/dist/types/domain.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/utils.d.ts +0 -1
- package/dist/types/utils.d.ts.map +1 -1
- package/dist/utils/criteria-operator-validation.d.ts +1 -0
- package/dist/utils/criteria-operator-validation.d.ts.map +1 -1
- package/dist/utils/criteria-operator-validation.js +39 -17
- package/dist/utils/criteria-operator-validation.js.map +1 -1
- package/dist/validation-error.d.ts.map +1 -1
- package/dist/validation-error.js +1 -6
- package/dist/validation-error.js.map +1 -1
- package/dist/value-object.d.ts +57 -8
- package/dist/value-object.d.ts.map +1 -1
- package/dist/value-object.js +49 -22
- package/dist/value-object.js.map +1 -1
- package/package.json +2 -1
- package/src/aggregate-changes.ts +335 -0
- package/src/base-entity.ts +102 -109
- package/src/change-tracker.ts +1062 -0
- package/src/constants.ts +75 -1
- package/src/criteria.ts +11 -4
- package/src/crypto.ts +31 -0
- package/src/domain-event.ts +0 -4
- package/src/entity-changes.ts +146 -0
- package/src/entity-schema-registry.ts +255 -0
- package/src/entity.ts +0 -11
- package/src/id.ts +17 -26
- package/src/index.ts +15 -19
- package/src/mapper.ts +4 -1
- package/src/paginated-result.ts +0 -21
- package/src/repository/base-repository.ts +7 -38
- package/src/repository/index.ts +0 -9
- package/src/repository/unit-of-work.ts +0 -29
- package/src/types/change-tracker.ts +233 -0
- package/src/types/criteria.ts +6 -1
- package/src/types/domain.ts +4 -8
- package/src/types/index.ts +1 -1
- package/src/types/utils.ts +0 -9
- package/src/utils/criteria-operator-validation.ts +57 -19
- package/src/validation-error.ts +1 -7
- package/src/value-object.ts +84 -24
- package/tests/aggregate-changes.test.ts +284 -0
- package/tests/criteria.test.ts +122 -161
- package/tests/entity-equality.test.ts +38 -61
- package/tests/entity-schema-registry.test.ts +382 -0
- package/tests/entity-validation.test.ts +7 -94
- package/tests/history-tracker.spec.ts +349 -617
- package/tests/id.test.ts +41 -44
- package/tests/load-test/data.json +346041 -0
- package/tests/load-test/entities.ts +97 -0
- package/tests/load-test/generate-data.ts +81 -0
- package/tests/load-test/lead-to-domain.mapper.ts +24 -0
- package/tests/load-test/load.test.ts +38 -0
- package/tests/repository.test.ts +30 -54
- package/tests/to-json.test.ts +14 -18
- package/tests/utils.ts +138 -102
- package/tests/value-objects.test.ts +57 -29
- package/dist/deep-proxy.d.ts +0 -36
- package/dist/deep-proxy.d.ts.map +0 -1
- package/dist/deep-proxy.js +0 -384
- package/dist/deep-proxy.js.map +0 -1
- package/dist/types/history-tracker.d.ts +0 -36
- package/dist/types/history-tracker.d.ts.map +0 -1
- package/dist/types/history-tracker.js +0 -2
- package/dist/types/history-tracker.js.map +0 -1
- package/src/deep-proxy.ts +0 -447
- package/src/types/history-tracker.ts +0 -45
- package/tests/entity.test.ts +0 -33
|
@@ -1,707 +1,439 @@
|
|
|
1
|
-
import { Id } from "../src";
|
|
2
|
-
import { Post, User, Address, Comment } from "./utils";
|
|
1
|
+
import { Id } from "../src/id";
|
|
2
|
+
import { Post, TagReference, User, Like, Address, Comment } from "./utils";
|
|
3
|
+
|
|
4
|
+
function createUser(
|
|
5
|
+
overrides: Partial<{
|
|
6
|
+
name: string;
|
|
7
|
+
email: string;
|
|
8
|
+
address: Address | null;
|
|
9
|
+
posts: Post[];
|
|
10
|
+
tags: TagReference[];
|
|
11
|
+
}> = {}
|
|
12
|
+
) {
|
|
13
|
+
const user = new User({
|
|
14
|
+
id: new Id("user-1"),
|
|
15
|
+
name: overrides.name ?? "Test User",
|
|
16
|
+
email: overrides.email ?? "test@test.com",
|
|
17
|
+
address: overrides.address ?? null,
|
|
18
|
+
posts: overrides.posts ?? [],
|
|
19
|
+
tags: overrides.tags ?? [],
|
|
20
|
+
});
|
|
3
21
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
return user;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createPost(
|
|
26
|
+
overrides: Partial<{
|
|
27
|
+
title: string;
|
|
28
|
+
content: string;
|
|
29
|
+
published: boolean;
|
|
30
|
+
comments: Comment[];
|
|
31
|
+
}> = {}
|
|
32
|
+
): Post {
|
|
33
|
+
return new Post({
|
|
34
|
+
id: new Id(),
|
|
35
|
+
title: overrides.title ?? "Test Post",
|
|
36
|
+
content: overrides.content ?? "Test content",
|
|
37
|
+
published: overrides.published ?? false,
|
|
38
|
+
comments: overrides.comments ?? [],
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function createComment(
|
|
43
|
+
overrides: Partial<{
|
|
44
|
+
text: string;
|
|
45
|
+
authorId: string;
|
|
46
|
+
likes: Like[];
|
|
47
|
+
}> = {}
|
|
48
|
+
): Comment {
|
|
49
|
+
return new Comment({
|
|
50
|
+
id: new Id(),
|
|
51
|
+
text: overrides.text ?? "Test comment",
|
|
52
|
+
authorId: overrides.authorId ?? "author-1",
|
|
53
|
+
likes: overrides.likes ?? [],
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function createAddress(street = "123 Main St", city = "Test City"): Address {
|
|
58
|
+
return new Address({
|
|
59
|
+
id: new Id(),
|
|
60
|
+
street,
|
|
61
|
+
city,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
describe("ChangeTracker.getChanges()", () => {
|
|
66
|
+
describe("no changes", () => {
|
|
67
|
+
it("should return empty changes when nothing modified", () => {
|
|
68
|
+
const user = createUser();
|
|
26
69
|
|
|
27
|
-
user.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
content: "Hello World 2",
|
|
34
|
-
likes: 0,
|
|
35
|
-
})
|
|
36
|
-
);
|
|
37
|
-
|
|
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
|
-
},
|
|
46
|
-
},
|
|
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);
|
|
70
|
+
const changes = user.getChanges();
|
|
71
|
+
|
|
72
|
+
expect(changes.isEmpty()).toBe(true);
|
|
73
|
+
expect(changes.hasCreates()).toBe(false);
|
|
74
|
+
expect(changes.hasUpdates()).toBe(false);
|
|
75
|
+
expect(changes.hasDeletes()).toBe(false);
|
|
69
76
|
});
|
|
77
|
+
});
|
|
70
78
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
title: "First Post",
|
|
75
|
-
content: "Hello World",
|
|
76
|
-
likes: 0,
|
|
77
|
-
});
|
|
79
|
+
describe("root property changes", () => {
|
|
80
|
+
it("should detect primitive property changes", () => {
|
|
81
|
+
const user = createUser();
|
|
78
82
|
|
|
79
|
-
|
|
83
|
+
user.changeName("New Name");
|
|
84
|
+
user.changeEmail("new@email.com");
|
|
80
85
|
|
|
81
|
-
|
|
82
|
-
title: {
|
|
83
|
-
onChange: (event) => changes.push({ property: "title", ...event }),
|
|
84
|
-
},
|
|
85
|
-
likes: {
|
|
86
|
-
onChange: (event) => changes.push({ property: "likes", ...event }),
|
|
87
|
-
},
|
|
88
|
-
});
|
|
86
|
+
const changes = user.getTypedChanges();
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
post.likes = 10;
|
|
88
|
+
expect(changes.hasUpdates()).toBe(true);
|
|
92
89
|
|
|
93
|
-
|
|
94
|
-
expect(
|
|
95
|
-
expect(
|
|
90
|
+
const userUpdates = changes.for("User");
|
|
91
|
+
expect(userUpdates.hasUpdates()).toBe(true);
|
|
92
|
+
expect(userUpdates.updates[0].changed).toMatchObject({
|
|
93
|
+
name: "New Name",
|
|
94
|
+
email: "new@email.com",
|
|
95
|
+
});
|
|
96
96
|
});
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
describe("collection changes (1:N)", () => {
|
|
100
|
+
it("should detect added items", () => {
|
|
101
|
+
const user = createUser();
|
|
102
|
+
const newPost = createPost({ title: "New Post" });
|
|
102
103
|
|
|
103
|
-
|
|
104
|
-
it("should detect new items added to array", (done) => {
|
|
105
|
-
const user = new User({
|
|
106
|
-
id: new Id("1"),
|
|
107
|
-
name: "John Doe",
|
|
108
|
-
email: "john@example.com",
|
|
109
|
-
posts: [],
|
|
110
|
-
address: new Address({
|
|
111
|
-
street: "Main St",
|
|
112
|
-
city: "NYC",
|
|
113
|
-
zipCode: "10001",
|
|
114
|
-
}),
|
|
115
|
-
comments: [],
|
|
116
|
-
});
|
|
104
|
+
user.addPost(newPost);
|
|
117
105
|
|
|
118
|
-
user.
|
|
119
|
-
posts: {
|
|
120
|
-
onChange: ({ toCreate, toUpdate, toDelete }) => {
|
|
121
|
-
expect(toCreate).toHaveLength(2);
|
|
122
|
-
expect(toUpdate).toHaveLength(0);
|
|
123
|
-
expect(toDelete).toHaveLength(0);
|
|
124
|
-
expect(toCreate[0].title).toBe("Post 1");
|
|
125
|
-
done();
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
});
|
|
106
|
+
const changes = user.getTypedChanges();
|
|
129
107
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
new Post({
|
|
138
|
-
id: new Id("2"),
|
|
139
|
-
title: "Post 2",
|
|
140
|
-
content: "Content 2",
|
|
141
|
-
likes: 0,
|
|
142
|
-
}),
|
|
143
|
-
]);
|
|
108
|
+
expect(changes.hasCreates()).toBe(true);
|
|
109
|
+
|
|
110
|
+
const postChanges = changes.for("Post");
|
|
111
|
+
|
|
112
|
+
expect(postChanges.hasCreates()).toBe(true);
|
|
113
|
+
expect(postChanges.creates).toHaveLength(1);
|
|
114
|
+
expect(postChanges.creates[0].title).toBe("New Post");
|
|
144
115
|
});
|
|
145
116
|
|
|
146
|
-
it("should detect items
|
|
147
|
-
const
|
|
148
|
-
id: new Id(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
new Post({
|
|
153
|
-
id: new Id("1"),
|
|
154
|
-
title: "Post 1",
|
|
155
|
-
content: "Content 1",
|
|
156
|
-
likes: 0,
|
|
157
|
-
}),
|
|
158
|
-
],
|
|
159
|
-
address: new Address({
|
|
160
|
-
street: "Main St",
|
|
161
|
-
city: "NYC",
|
|
162
|
-
zipCode: "10001",
|
|
163
|
-
}),
|
|
117
|
+
it("should detect removed items", () => {
|
|
118
|
+
const existingPost = new Post({
|
|
119
|
+
id: new Id(),
|
|
120
|
+
title: "Existing Post",
|
|
121
|
+
content: "Existing content",
|
|
122
|
+
published: false,
|
|
164
123
|
comments: [],
|
|
165
124
|
});
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
},
|
|
174
|
-
},
|
|
125
|
+
const user = new User({
|
|
126
|
+
id: new Id(),
|
|
127
|
+
name: "Test User",
|
|
128
|
+
email: "test@test.com",
|
|
129
|
+
address: null,
|
|
130
|
+
posts: [existingPost],
|
|
131
|
+
tags: [],
|
|
175
132
|
});
|
|
176
133
|
|
|
177
|
-
user.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
);
|
|
134
|
+
user.removePost(existingPost.id);
|
|
135
|
+
|
|
136
|
+
const changes = user.getChanges();
|
|
137
|
+
|
|
138
|
+
expect(changes.hasDeletes()).toBe(true);
|
|
139
|
+
|
|
140
|
+
const postChanges = changes.for("Post");
|
|
141
|
+
expect(postChanges.hasDeletes()).toBe(true);
|
|
142
|
+
expect(postChanges.deletes.length).toBe(1);
|
|
185
143
|
});
|
|
186
|
-
});
|
|
187
144
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
describe("Array Changes - Update", () => {
|
|
193
|
-
it("should detect updated items in array", (done) => {
|
|
194
|
-
const id1 = new Id("1");
|
|
195
|
-
const post1 = new Post({
|
|
196
|
-
id: id1,
|
|
197
|
-
title: "Post 1",
|
|
198
|
-
content: "Content 1",
|
|
199
|
-
likes: 0,
|
|
200
|
-
});
|
|
201
|
-
const post2 = new Post({
|
|
202
|
-
id: new Id("2"),
|
|
203
|
-
title: "Post 2",
|
|
204
|
-
content: "Content 2",
|
|
205
|
-
likes: 0,
|
|
206
|
-
});
|
|
145
|
+
it("should detect updated items", () => {
|
|
146
|
+
const existingPost = createPost({ title: "Original Title" });
|
|
147
|
+
const user = createUser({ posts: [existingPost] });
|
|
207
148
|
|
|
208
|
-
|
|
209
|
-
id: new Id("1"),
|
|
210
|
-
name: "John Doe",
|
|
211
|
-
email: "john@example.com",
|
|
212
|
-
posts: [post1, post2],
|
|
213
|
-
address: new Address({
|
|
214
|
-
street: "Main St",
|
|
215
|
-
city: "NYC",
|
|
216
|
-
zipCode: "10001",
|
|
217
|
-
}),
|
|
218
|
-
comments: [],
|
|
219
|
-
});
|
|
149
|
+
user.posts[0].changeTitle("Updated Title");
|
|
220
150
|
|
|
221
|
-
user.
|
|
222
|
-
posts: {
|
|
223
|
-
onChange: ({ toCreate, toUpdate, toDelete }) => {
|
|
224
|
-
expect(toCreate).toHaveLength(0);
|
|
225
|
-
expect(toUpdate).toHaveLength(1);
|
|
226
|
-
expect(toDelete).toHaveLength(0);
|
|
227
|
-
expect(toUpdate[0].id).toBe(id1);
|
|
228
|
-
done();
|
|
229
|
-
},
|
|
230
|
-
},
|
|
231
|
-
});
|
|
151
|
+
const changes = user.getTypedChanges();
|
|
232
152
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
153
|
+
const postChanges = changes.for("Post");
|
|
154
|
+
expect(postChanges.hasUpdates()).toBe(true);
|
|
155
|
+
expect(postChanges.updates[0].changed).toMatchObject({
|
|
156
|
+
title: "Updated Title",
|
|
157
|
+
});
|
|
237
158
|
});
|
|
238
159
|
|
|
239
|
-
it("should detect multiple
|
|
240
|
-
const post1 =
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
content: "Content 1",
|
|
244
|
-
likes: 0,
|
|
245
|
-
});
|
|
246
|
-
const post2 = new Post({
|
|
247
|
-
id: new Id("2"),
|
|
248
|
-
title: "Post 2",
|
|
249
|
-
content: "Content 2",
|
|
250
|
-
likes: 0,
|
|
251
|
-
});
|
|
160
|
+
it("should detect multiple operations", () => {
|
|
161
|
+
const post1 = createPost({ title: "Post 1" });
|
|
162
|
+
const post2 = createPost({ title: "Post 2" });
|
|
163
|
+
const user = createUser({ posts: [post1, post2] });
|
|
252
164
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
name: "John Doe",
|
|
256
|
-
email: "john@example.com",
|
|
257
|
-
posts: [post1, post2],
|
|
258
|
-
address: new Address({
|
|
259
|
-
street: "Main St",
|
|
260
|
-
city: "NYC",
|
|
261
|
-
zipCode: "10001",
|
|
262
|
-
}),
|
|
263
|
-
comments: [],
|
|
264
|
-
});
|
|
165
|
+
// Remove post1
|
|
166
|
+
user.removePost(post1.id);
|
|
265
167
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
expect(toUpdate).toHaveLength(2);
|
|
270
|
-
done();
|
|
271
|
-
},
|
|
272
|
-
},
|
|
273
|
-
});
|
|
168
|
+
// Add new post
|
|
169
|
+
const post3 = createPost({ title: "Post 3" });
|
|
170
|
+
user.addPost(post3);
|
|
274
171
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
172
|
+
// Update post2
|
|
173
|
+
user.posts[0].changeTitle("Post 2 Updated");
|
|
174
|
+
|
|
175
|
+
const changes = user.getTypedChanges();
|
|
176
|
+
const postChanges = changes.for("Post");
|
|
177
|
+
|
|
178
|
+
expect(postChanges.hasCreates()).toBe(true);
|
|
179
|
+
expect(postChanges.hasUpdates()).toBe(true);
|
|
180
|
+
expect(postChanges.hasDeletes()).toBe(true);
|
|
181
|
+
expect(postChanges.creates).toHaveLength(1);
|
|
182
|
+
expect(postChanges.updates).toHaveLength(1);
|
|
183
|
+
expect(postChanges.deletes).toHaveLength(1);
|
|
278
184
|
});
|
|
279
185
|
});
|
|
280
186
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
it("should detect deleted items from array", (done) => {
|
|
287
|
-
const post1 = new Post({
|
|
288
|
-
id: new Id("1"),
|
|
289
|
-
title: "Post 1",
|
|
290
|
-
content: "Content 1",
|
|
291
|
-
likes: 0,
|
|
292
|
-
});
|
|
293
|
-
const post2 = new Post({
|
|
294
|
-
id: new Id("2"),
|
|
295
|
-
title: "Post 2",
|
|
296
|
-
content: "Content 2",
|
|
297
|
-
likes: 0,
|
|
298
|
-
});
|
|
187
|
+
describe("nested collections", () => {
|
|
188
|
+
it("should detect changes in deeply nested collections", () => {
|
|
189
|
+
const comment = createComment({ text: "Original comment" });
|
|
190
|
+
const post = createPost({ comments: [comment] });
|
|
191
|
+
const user = createUser({ posts: [post] });
|
|
299
192
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
email: "john@example.com",
|
|
304
|
-
posts: [post1, post2],
|
|
305
|
-
address: new Address({
|
|
306
|
-
street: "Main St",
|
|
307
|
-
city: "NYC",
|
|
308
|
-
zipCode: "10001",
|
|
309
|
-
}),
|
|
310
|
-
comments: [],
|
|
311
|
-
});
|
|
193
|
+
// Add new comment
|
|
194
|
+
const newComment = createComment({ text: "New comment" });
|
|
195
|
+
user.posts[0].addComment(newComment);
|
|
312
196
|
|
|
313
|
-
user.
|
|
314
|
-
|
|
315
|
-
onChange: ({ toCreate, toUpdate, toDelete }) => {
|
|
316
|
-
expect(toCreate).toHaveLength(0);
|
|
317
|
-
expect(toUpdate).toHaveLength(0);
|
|
318
|
-
expect(toDelete).toHaveLength(1);
|
|
319
|
-
done();
|
|
320
|
-
},
|
|
321
|
-
},
|
|
322
|
-
});
|
|
197
|
+
const changes = user.getTypedChanges();
|
|
198
|
+
const commentChanges = changes.for("Comment");
|
|
323
199
|
|
|
324
|
-
|
|
200
|
+
expect(commentChanges.hasCreates()).toBe(true);
|
|
201
|
+
expect(commentChanges.creates[0].text).toBe("New comment");
|
|
202
|
+
expect(commentChanges.updates).toHaveLength(0);
|
|
203
|
+
expect(commentChanges.deletes).toHaveLength(0);
|
|
204
|
+
expect(commentChanges.creates).toHaveLength(1);
|
|
325
205
|
});
|
|
326
206
|
|
|
327
|
-
it("should
|
|
328
|
-
const
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
name: "John Doe",
|
|
332
|
-
email: "john@example.com",
|
|
333
|
-
posts: [
|
|
334
|
-
new Post({
|
|
335
|
-
id: id1,
|
|
336
|
-
title: "Post 1",
|
|
337
|
-
content: "Content 1",
|
|
338
|
-
likes: 0,
|
|
339
|
-
}),
|
|
340
|
-
new Post({
|
|
341
|
-
id: new Id("2"),
|
|
342
|
-
title: "Post 2",
|
|
343
|
-
content: "Content 2",
|
|
344
|
-
likes: 0,
|
|
345
|
-
}),
|
|
346
|
-
],
|
|
347
|
-
address: new Address({
|
|
348
|
-
street: "Main St",
|
|
349
|
-
city: "NYC",
|
|
350
|
-
zipCode: "10001",
|
|
351
|
-
}),
|
|
352
|
-
comments: [],
|
|
353
|
-
});
|
|
207
|
+
it("should handle 3+ levels of nesting (User > Post > Comment > Like)", () => {
|
|
208
|
+
const comment = createComment({ likes: [] });
|
|
209
|
+
const post = createPost({ comments: [comment] });
|
|
210
|
+
const user = createUser({ posts: [post] });
|
|
354
211
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
expect(toDelete[0].id.value).toBe(id1.value);
|
|
360
|
-
done();
|
|
361
|
-
},
|
|
362
|
-
},
|
|
212
|
+
const newLike = new Like({
|
|
213
|
+
postId: "post-1",
|
|
214
|
+
userId: "user-2",
|
|
215
|
+
createdAt: new Date(),
|
|
363
216
|
});
|
|
217
|
+
user.posts[0].comments[0].addLike(newLike);
|
|
218
|
+
|
|
219
|
+
const changes = user.getTypedChanges();
|
|
220
|
+
const likeChanges = changes.for("Like");
|
|
364
221
|
|
|
365
|
-
|
|
222
|
+
expect(likeChanges.hasCreates()).toBe(true);
|
|
223
|
+
expect(likeChanges.creates).toHaveLength(1);
|
|
224
|
+
expect(likeChanges.updates).toHaveLength(0);
|
|
225
|
+
expect(likeChanges.deletes).toHaveLength(0);
|
|
366
226
|
});
|
|
367
227
|
});
|
|
368
228
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
describe("Array Changes - Mixed Operations", () => {
|
|
374
|
-
it("should detect mixed create and update operations", (done) => {
|
|
375
|
-
const post1 = new Post({
|
|
376
|
-
id: new Id("1"),
|
|
377
|
-
title: "Post 1",
|
|
378
|
-
content: "Content 1",
|
|
379
|
-
likes: 0,
|
|
380
|
-
});
|
|
229
|
+
describe("entity relations (1:1)", () => {
|
|
230
|
+
it("should detect created entity (null → Entity)", () => {
|
|
231
|
+
const user = createUser({ address: null });
|
|
381
232
|
|
|
382
|
-
|
|
383
|
-
id: new Id("1"),
|
|
384
|
-
name: "John Doe",
|
|
385
|
-
email: "john@example.com",
|
|
386
|
-
posts: [post1],
|
|
387
|
-
address: new Address({
|
|
388
|
-
street: "Main St",
|
|
389
|
-
city: "NYC",
|
|
390
|
-
zipCode: "10001",
|
|
391
|
-
}),
|
|
392
|
-
comments: [],
|
|
393
|
-
});
|
|
233
|
+
user.setAddress(createAddress("New Street", "New City"));
|
|
394
234
|
|
|
395
|
-
user.
|
|
396
|
-
|
|
397
|
-
onChange: ({ toCreate, toUpdate, toDelete }) => {
|
|
398
|
-
expect(toCreate).toHaveLength(2);
|
|
399
|
-
expect(toUpdate).toHaveLength(1);
|
|
400
|
-
expect(toDelete).toHaveLength(0);
|
|
401
|
-
done();
|
|
402
|
-
},
|
|
403
|
-
},
|
|
404
|
-
});
|
|
235
|
+
const changes = user.getTypedChanges();
|
|
236
|
+
const addressChanges = changes.for("Address");
|
|
405
237
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
post1,
|
|
409
|
-
new Post({
|
|
410
|
-
id: new Id("2"),
|
|
411
|
-
title: "Post 2",
|
|
412
|
-
content: "Content 2",
|
|
413
|
-
likes: 0,
|
|
414
|
-
}),
|
|
415
|
-
new Post({
|
|
416
|
-
id: new Id("3"),
|
|
417
|
-
title: "Post 3",
|
|
418
|
-
content: "Content 3",
|
|
419
|
-
likes: 0,
|
|
420
|
-
}),
|
|
421
|
-
];
|
|
238
|
+
expect(addressChanges.hasCreates()).toBe(true);
|
|
239
|
+
expect(addressChanges.creates[0].street).toBe("New Street");
|
|
422
240
|
});
|
|
423
241
|
|
|
424
|
-
it("should detect
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
title: "Post 1",
|
|
428
|
-
content: "Content 1",
|
|
429
|
-
likes: 0,
|
|
430
|
-
});
|
|
431
|
-
const post2 = new Post({
|
|
432
|
-
id: new Id("2"),
|
|
433
|
-
title: "Post 2",
|
|
434
|
-
content: "Content 2",
|
|
435
|
-
likes: 0,
|
|
436
|
-
});
|
|
437
|
-
const post3 = new Post({
|
|
438
|
-
id: new Id("3"),
|
|
439
|
-
title: "Post 3",
|
|
440
|
-
content: "Content 3",
|
|
441
|
-
likes: 0,
|
|
442
|
-
});
|
|
242
|
+
it("should detect deleted entity (Entity → null)", () => {
|
|
243
|
+
const address = createAddress();
|
|
244
|
+
const user = createUser({ address });
|
|
443
245
|
|
|
444
|
-
|
|
445
|
-
id: new Id("1"),
|
|
446
|
-
name: "John Doe",
|
|
447
|
-
email: "john@example.com",
|
|
448
|
-
posts: [post1, post2, post3],
|
|
449
|
-
address: new Address({
|
|
450
|
-
street: "Main St",
|
|
451
|
-
city: "NYC",
|
|
452
|
-
zipCode: "10001",
|
|
453
|
-
}),
|
|
454
|
-
comments: [],
|
|
455
|
-
});
|
|
246
|
+
user.removeAddress();
|
|
456
247
|
|
|
457
|
-
user.
|
|
458
|
-
|
|
459
|
-
onChange: ({ toCreate, toUpdate, toDelete }) => {
|
|
460
|
-
expect(toCreate).toHaveLength(1); // post4
|
|
461
|
-
expect(toUpdate).toHaveLength(1); // post2 modified
|
|
462
|
-
expect(toDelete).toHaveLength(2); // post1 and post3 removed
|
|
463
|
-
done();
|
|
464
|
-
},
|
|
465
|
-
},
|
|
466
|
-
});
|
|
248
|
+
const changes = user.getTypedChanges();
|
|
249
|
+
const addressChanges = changes.for("Address");
|
|
467
250
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
post2,
|
|
471
|
-
new Post({
|
|
472
|
-
id: new Id("4"),
|
|
473
|
-
title: "Post 4",
|
|
474
|
-
content: "Content 4",
|
|
475
|
-
likes: 0,
|
|
476
|
-
}),
|
|
477
|
-
];
|
|
251
|
+
expect(addressChanges.hasDeletes()).toBe(true);
|
|
252
|
+
expect(addressChanges.deletes).toHaveLength(1);
|
|
478
253
|
});
|
|
479
|
-
});
|
|
480
254
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
255
|
+
it("should detect updated entity (same ID with changes)", () => {
|
|
256
|
+
const address = createAddress("Old Street", "Old City");
|
|
257
|
+
const user = createUser({ address });
|
|
484
258
|
|
|
485
|
-
|
|
486
|
-
it("should track changes in nested value objects", (done) => {
|
|
487
|
-
const user = new User({
|
|
488
|
-
id: new Id("1"),
|
|
489
|
-
name: "John Doe",
|
|
490
|
-
email: "john@example.com",
|
|
491
|
-
posts: [],
|
|
492
|
-
address: new Address({
|
|
493
|
-
street: "Main St",
|
|
494
|
-
city: "NYC",
|
|
495
|
-
zipCode: "10001",
|
|
496
|
-
}),
|
|
497
|
-
comments: [],
|
|
498
|
-
});
|
|
259
|
+
user.address?.changeStreet("New Street");
|
|
499
260
|
|
|
500
|
-
user.
|
|
501
|
-
|
|
502
|
-
onChange: ({ previous, current }) => {
|
|
503
|
-
expect(previous).toBeInstanceOf(Address);
|
|
504
|
-
expect(current).toBeInstanceOf(Address);
|
|
505
|
-
expect(current.city).toBe("LA");
|
|
506
|
-
done();
|
|
507
|
-
},
|
|
508
|
-
},
|
|
509
|
-
});
|
|
261
|
+
const changes = user.getTypedChanges();
|
|
262
|
+
const addressChanges = changes.for("Address");
|
|
510
263
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
zipCode: "90001",
|
|
264
|
+
expect(addressChanges.hasUpdates()).toBe(true);
|
|
265
|
+
expect(addressChanges.updates[0].changed).toMatchObject({
|
|
266
|
+
street: "New Street",
|
|
515
267
|
});
|
|
516
268
|
});
|
|
517
269
|
|
|
518
|
-
it("should
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
name: "John Doe",
|
|
522
|
-
email: "john@example.com",
|
|
523
|
-
posts: [],
|
|
524
|
-
address: new Address({
|
|
525
|
-
street: "Main St",
|
|
526
|
-
city: "NYC",
|
|
527
|
-
zipCode: "10001",
|
|
528
|
-
}),
|
|
529
|
-
comments: [
|
|
530
|
-
new Comment({
|
|
531
|
-
text: "Nice post!",
|
|
532
|
-
author: "Alice",
|
|
533
|
-
}),
|
|
534
|
-
],
|
|
535
|
-
});
|
|
270
|
+
it("should detect replaced entity (different ID)", () => {
|
|
271
|
+
const oldAddress = createAddress("Old Street", "Old City");
|
|
272
|
+
const user = createUser({ address: oldAddress });
|
|
536
273
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
count++;
|
|
543
|
-
if (count === MAX_COUNT_TO_EXPECT) {
|
|
544
|
-
expect(toCreate).toHaveLength(2);
|
|
545
|
-
expect(toDelete).toHaveLength(1);
|
|
546
|
-
expect(toUpdate).toHaveLength(0);
|
|
547
|
-
done();
|
|
548
|
-
}
|
|
549
|
-
},
|
|
550
|
-
},
|
|
551
|
-
});
|
|
274
|
+
const newAddress = createAddress("New Street", "New City");
|
|
275
|
+
user.setAddress(newAddress);
|
|
276
|
+
|
|
277
|
+
const changes = user.getTypedChanges();
|
|
278
|
+
const addressChanges = changes.for("Address");
|
|
552
279
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
);
|
|
559
|
-
user.comments.push(
|
|
560
|
-
new Comment({
|
|
561
|
-
text: "Nice post3!",
|
|
562
|
-
author: "Alice3",
|
|
563
|
-
})
|
|
564
|
-
);
|
|
565
|
-
|
|
566
|
-
user.comments = [
|
|
567
|
-
new Comment({
|
|
568
|
-
text: "Nice post2!",
|
|
569
|
-
author: "Alice2",
|
|
570
|
-
}),
|
|
571
|
-
new Comment({
|
|
572
|
-
text: "Nice post3!",
|
|
573
|
-
author: "Alice3",
|
|
574
|
-
}),
|
|
575
|
-
];
|
|
280
|
+
expect(addressChanges.hasDeletes()).toBe(true);
|
|
281
|
+
expect(addressChanges.hasCreates()).toBe(true);
|
|
282
|
+
expect(addressChanges.deletes).toHaveLength(1);
|
|
283
|
+
expect(addressChanges.deletes[0].id.value).toBe(oldAddress.id.value);
|
|
284
|
+
expect(addressChanges.creates).toHaveLength(1);
|
|
285
|
+
expect(addressChanges.creates[0].id.value).toBe(newAddress.id.value);
|
|
576
286
|
});
|
|
577
287
|
});
|
|
578
288
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
289
|
+
describe("Value Objects with identityKey", () => {
|
|
290
|
+
it("should detect added VOs using identityKey", () => {
|
|
291
|
+
const user = createUser({ tags: [] });
|
|
292
|
+
|
|
293
|
+
const tag = new TagReference({ tagId: "tag-1", name: "JavaScript" });
|
|
294
|
+
user.addTag(tag);
|
|
295
|
+
|
|
296
|
+
const changes = user.getTypedChanges();
|
|
297
|
+
const tagChanges = changes.for("TagReference");
|
|
298
|
+
|
|
299
|
+
expect(tagChanges.hasCreates()).toBe(true);
|
|
300
|
+
expect(tagChanges.creates).toHaveLength(1);
|
|
301
|
+
expect(tagChanges.creates[0].tagId).toBe("tag-1");
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it("should detect removed VOs using identityKey", () => {
|
|
305
|
+
const tag = new TagReference({ tagId: "tag-1", name: "JavaScript" });
|
|
306
|
+
const user = createUser({ tags: [tag] });
|
|
307
|
+
|
|
308
|
+
user.removeTag(tag.tagId);
|
|
591
309
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
post.content = "Updated Content";
|
|
310
|
+
const changes = user.getTypedChanges();
|
|
311
|
+
const tagChanges = changes.for("TagReference");
|
|
595
312
|
|
|
596
|
-
|
|
597
|
-
expect(
|
|
598
|
-
expect(
|
|
599
|
-
expect(history[1].path).toBe("likes");
|
|
600
|
-
expect(history[2].path).toBe("content");
|
|
313
|
+
expect(tagChanges.hasDeletes()).toBe(true);
|
|
314
|
+
expect(tagChanges.deletes).toHaveLength(1);
|
|
315
|
+
expect(tagChanges.deletes[0].tagId).toBe("tag-1");
|
|
601
316
|
});
|
|
602
317
|
|
|
603
|
-
it("should
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
likes: 0,
|
|
318
|
+
it("should use composite identityKey for Likes", () => {
|
|
319
|
+
const like = new Like({
|
|
320
|
+
postId: "post-1",
|
|
321
|
+
userId: "user-1",
|
|
322
|
+
createdAt: new Date(),
|
|
609
323
|
});
|
|
324
|
+
const comment = createComment({ likes: [like] });
|
|
325
|
+
const post = createPost({ comments: [comment] });
|
|
326
|
+
const user = createUser({ posts: [post] });
|
|
610
327
|
|
|
611
|
-
|
|
612
|
-
expect(post.getHistory()).toHaveLength(1);
|
|
328
|
+
user.posts[0].comments[0].removeLike(like.postId, like.userId);
|
|
613
329
|
|
|
614
|
-
|
|
615
|
-
|
|
330
|
+
const changes = user.getTypedChanges();
|
|
331
|
+
const likeChanges = changes.for("Like");
|
|
332
|
+
|
|
333
|
+
expect(likeChanges.hasDeletes()).toBe(true);
|
|
334
|
+
expect(likeChanges.deletes).toHaveLength(1);
|
|
335
|
+
expect(likeChanges.deletes[0].postId).toBe("post-1");
|
|
336
|
+
expect(likeChanges.deletes[0].userId).toBe("user-1");
|
|
616
337
|
});
|
|
617
338
|
});
|
|
618
339
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
const post = new Post({
|
|
626
|
-
id: new Id("1"),
|
|
627
|
-
title: "First Post",
|
|
628
|
-
content: "Hello World",
|
|
629
|
-
likes: 0,
|
|
630
|
-
});
|
|
340
|
+
describe("toBatchOperations", () => {
|
|
341
|
+
it("should group and order operations correctly", () => {
|
|
342
|
+
const comment = createComment();
|
|
343
|
+
const post = createPost({ comments: [comment] });
|
|
344
|
+
const address = createAddress();
|
|
345
|
+
const user = createUser({ posts: [post], address });
|
|
631
346
|
|
|
632
|
-
|
|
633
|
-
|
|
347
|
+
user.changeName("New Name"); // depth 0
|
|
348
|
+
user.address?.changeStreet("New Street"); // depth 1
|
|
349
|
+
user.posts[0].changeTitle("New Title"); // depth 1
|
|
350
|
+
user.posts[0].comments[0].changeText("New Comment"); // depth 2
|
|
634
351
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
},
|
|
641
|
-
});
|
|
352
|
+
const newPost = createPost({ title: "Brand New Post" });
|
|
353
|
+
user.addPost(newPost);
|
|
354
|
+
|
|
355
|
+
const changes = user.getTypedChanges();
|
|
356
|
+
const batch = changes.toBatchOperations();
|
|
642
357
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
358
|
+
expect(batch.deletes).toHaveLength(0);
|
|
359
|
+
|
|
360
|
+
expect(batch.creates.length).toBe(1);
|
|
361
|
+
expect(batch.creates[0].entity).toBe("Post");
|
|
362
|
+
expect(batch.creates[0].depth).toBe(1);
|
|
363
|
+
|
|
364
|
+
expect(batch.updates.length).toBe(4);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it("should order deletes by depth DESC (leaf → root)", () => {
|
|
368
|
+
const like = new Like({
|
|
369
|
+
postId: "post-1",
|
|
370
|
+
userId: "user-1",
|
|
371
|
+
createdAt: new Date(),
|
|
649
372
|
});
|
|
373
|
+
const comment = createComment({ likes: [like] });
|
|
374
|
+
const post = createPost({ comments: [comment] });
|
|
375
|
+
const user = createUser({ posts: [post] });
|
|
376
|
+
|
|
377
|
+
user.posts[0].comments[0].removeLike(like.postId, like.userId);
|
|
378
|
+
user.posts[0].comments = [];
|
|
379
|
+
user.posts = [];
|
|
380
|
+
|
|
381
|
+
const changes = user.getChanges();
|
|
382
|
+
const batch = changes.toBatchOperations();
|
|
383
|
+
|
|
384
|
+
// Like (depth 3) → Comment (depth 2) → Post (depth 1)
|
|
385
|
+
const likeIdx = batch.deletes.findIndex((d) => d.entity === "Like");
|
|
386
|
+
const commentIdx = batch.deletes.findIndex((d) => d.entity === "Comment");
|
|
387
|
+
const postIdx = batch.deletes.findIndex((d) => d.entity === "Post");
|
|
388
|
+
|
|
389
|
+
expect(batch.deletes).toHaveLength(3);
|
|
390
|
+
expect(likeIdx).toBeLessThan(commentIdx);
|
|
391
|
+
expect(commentIdx).toBeLessThan(postIdx);
|
|
392
|
+
});
|
|
650
393
|
|
|
651
|
-
|
|
394
|
+
it("should order creates by depth ASC (root → leaf)", () => {
|
|
395
|
+
const user = createUser();
|
|
652
396
|
|
|
653
|
-
|
|
654
|
-
|
|
397
|
+
const newComment = createComment({ text: "New Comment" });
|
|
398
|
+
const newPost = createPost({ title: "New Post" });
|
|
399
|
+
user.addPost(newPost);
|
|
400
|
+
user.posts[0].addComment(newComment);
|
|
401
|
+
|
|
402
|
+
const changes = user.getTypedChanges();
|
|
403
|
+
const batch = changes.toBatchOperations();
|
|
404
|
+
|
|
405
|
+
const postIdx = batch.creates.findIndex((c) => c.entity === "Post");
|
|
406
|
+
const commentIdx = batch.creates.findIndex((c) => c.entity === "Comment");
|
|
407
|
+
|
|
408
|
+
expect(batch.creates.length).toBe(2);
|
|
409
|
+
expect(batch.creates[0].entity).toBe("Post");
|
|
410
|
+
expect(batch.creates[0].depth).toBe(1);
|
|
411
|
+
expect(batch.creates[1].entity).toBe("Comment");
|
|
412
|
+
expect(batch.creates[1].depth).toBe(2);
|
|
413
|
+
expect(postIdx).toBeLessThan(commentIdx);
|
|
655
414
|
});
|
|
656
415
|
});
|
|
657
416
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
417
|
+
describe("markAsClean", () => {
|
|
418
|
+
it("should reset changes after clearHistory", () => {
|
|
419
|
+
const user = createUser();
|
|
661
420
|
|
|
662
|
-
|
|
663
|
-
it("should create a plain object", () => {
|
|
664
|
-
const user = new User({
|
|
665
|
-
id: new Id("1"),
|
|
666
|
-
name: "John Doe",
|
|
667
|
-
email: "john@example.com",
|
|
668
|
-
posts: [],
|
|
669
|
-
address: new Address({
|
|
670
|
-
street: "Main St",
|
|
671
|
-
city: "NYC",
|
|
672
|
-
zipCode: "10001",
|
|
673
|
-
}),
|
|
674
|
-
comments: [],
|
|
675
|
-
});
|
|
421
|
+
user.changeName("Changed Name");
|
|
676
422
|
|
|
677
|
-
user.
|
|
678
|
-
email: {
|
|
679
|
-
onChange: ({ previous, current }) => {
|
|
680
|
-
expect(previous).toBe("john@example.com");
|
|
681
|
-
expect(current).toBe("new@example.com");
|
|
682
|
-
},
|
|
683
|
-
},
|
|
684
|
-
extra: {
|
|
685
|
-
onChange: ({ previous, current }) => {
|
|
686
|
-
expect(previous).toBe(undefined);
|
|
687
|
-
expect(current).toEqual({
|
|
688
|
-
age: 20,
|
|
689
|
-
height: 180,
|
|
690
|
-
});
|
|
691
|
-
},
|
|
692
|
-
},
|
|
693
|
-
address: {
|
|
694
|
-
onChange: ({ previous, current }) => {
|
|
695
|
-
expect(previous).toBeInstanceOf(Address);
|
|
696
|
-
expect(current).toBeInstanceOf(Address);
|
|
697
|
-
},
|
|
698
|
-
},
|
|
699
|
-
});
|
|
423
|
+
expect(user.getChanges().hasChanges()).toBe(true);
|
|
700
424
|
|
|
701
|
-
user.
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
425
|
+
user.markAsClean();
|
|
426
|
+
|
|
427
|
+
expect(user.getChanges().isEmpty()).toBe(true);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it("should reset changes after markAsClean", () => {
|
|
431
|
+
const user = createUser();
|
|
432
|
+
|
|
433
|
+
user.changeName("Changed Name");
|
|
434
|
+
user.markAsClean();
|
|
435
|
+
|
|
436
|
+
expect(user.getChanges().isEmpty()).toBe(true);
|
|
705
437
|
});
|
|
706
438
|
});
|
|
707
439
|
});
|