Skip to content

Commit 6b60ebe

Browse files
committed
Extract observer types
1 parent 5dad72c commit 6b60ebe

File tree

11 files changed

+380
-470
lines changed

11 files changed

+380
-470
lines changed

apps/meteor/client/lib/cachedCollections/Cursor.ts

Lines changed: 264 additions & 287 deletions
Large diffs are not rendered by default.

apps/meteor/client/lib/cachedCollections/DiffSequence.ts

Lines changed: 50 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { IdMap } from './IdMap';
2-
import { clone, hasOwn, isEqual } from './common';
2+
import { clone, entriesOf, hasOwn, isEqual } from './common';
3+
import type { Observer, OrderedObserver, UnorderedObserver } from './observers';
34

45
function isObjEmpty(obj: Record<string, unknown>): boolean {
56
for (const key in Object(obj)) {
@@ -10,79 +11,72 @@ function isObjEmpty(obj: Record<string, unknown>): boolean {
1011
return true;
1112
}
1213

13-
type Observer<T extends { _id: string }> = {
14-
added?: <TFields>(id: T['_id'], fields: TFields) => void;
15-
changed?: <TFields>(id: T['_id'], fields: TFields) => void;
16-
removed?: (id: T['_id']) => void;
17-
movedBefore?: (id: T['_id'], before: T['_id'] | null) => void;
18-
addedBefore?: <TFields>(id: T['_id'], fields: TFields, before: T['_id'] | null) => void;
19-
};
20-
21-
/** @deprecated internal use only */
2214
export class DiffSequence {
23-
static diffQueryChanges<T extends { _id: string }, TProjection extends T = T>(
15+
static diffQueryChanges<T extends { _id: string }>(
2416
ordered: true,
2517
oldResults: T[],
2618
newResults: T[],
27-
observer: Observer<T>,
28-
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => TProjection },
19+
observer: OrderedObserver<T>,
20+
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => Partial<T> },
2921
): void;
3022

31-
static diffQueryChanges<T extends { _id: string }, TProjection extends T = T>(
23+
static diffQueryChanges<T extends { _id: string }>(
3224
ordered: false,
3325
oldResults: IdMap<T['_id'], T>,
3426
newResults: IdMap<T['_id'], T>,
35-
observer: Observer<T>,
36-
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => TProjection },
27+
observer: UnorderedObserver<T>,
28+
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => Partial<T> },
3729
): void;
3830

39-
static diffQueryChanges<T extends { _id: string }, TProjection extends T = T>(
31+
static diffQueryChanges<T extends { _id: string }>(
4032
ordered: boolean,
4133
oldResults: T[] | IdMap<T['_id'], T>,
4234
newResults: T[] | IdMap<T['_id'], T>,
4335
observer: Observer<T>,
44-
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => TProjection },
36+
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => Partial<T> },
4537
): void;
4638

47-
static diffQueryChanges<T extends { _id: string }, TProjection extends T = T>(
39+
static diffQueryChanges<T extends { _id: string }>(
4840
ordered: boolean,
4941
oldResults: T[] | IdMap<T['_id'], T>,
5042
newResults: T[] | IdMap<T['_id'], T>,
5143
observer: Observer<T>,
52-
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => TProjection },
44+
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => Partial<T> },
5345
): void {
54-
if (ordered) DiffSequence.diffQueryOrderedChanges(oldResults as T[], newResults as T[], observer, options);
55-
else DiffSequence.diffQueryUnorderedChanges(oldResults as IdMap<T['_id'], T>, newResults as IdMap<T['_id'], T>, observer, options);
46+
if (ordered) DiffSequence.diffQueryOrderedChanges(oldResults as T[], newResults as T[], observer as OrderedObserver<T>, options);
47+
else
48+
DiffSequence.diffQueryUnorderedChanges(
49+
oldResults as IdMap<T['_id'], T>,
50+
newResults as IdMap<T['_id'], T>,
51+
observer as UnorderedObserver<T>,
52+
options,
53+
);
5654
}
5755

58-
private static diffQueryUnorderedChanges<T extends { _id: string }, TProjection extends T = T>(
56+
private static diffQueryUnorderedChanges<T extends { _id: string }>(
5957
oldResults: IdMap<T['_id'], T>,
6058
newResults: IdMap<T['_id'], T>,
61-
observer: Observer<T>,
62-
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => TProjection },
59+
observer: UnorderedObserver<T>,
60+
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => Partial<T> },
6361
): void {
6462
options = options || {};
6563
const projectionFn = options.projectionFn || clone;
6664

67-
if (observer.movedBefore) {
68-
throw new Error('_diffQueryUnordered called with a movedBefore observer!');
69-
}
70-
7165
newResults.forEach((newDoc, id) => {
7266
const oldDoc = oldResults.get(id);
7367
if (oldDoc) {
7468
if (observer.changed && !isEqual(oldDoc, newDoc as any)) {
7569
const projectedNew = projectionFn(newDoc);
7670
const projectedOld = projectionFn(oldDoc);
77-
const changedFields = DiffSequence.makeChangedFields<unknown, unknown>(projectedNew, projectedOld);
71+
const changedFields = DiffSequence.makeChangedFields(projectedNew, projectedOld);
7872
if (!isObjEmpty(changedFields)) {
79-
observer.changed(id, changedFields as TProjection);
73+
observer.changed(id, changedFields as Partial<T>);
8074
}
8175
}
8276
} else if (observer.added) {
83-
const fields = projectionFn(newDoc) as Omit<TProjection, '_id'> & { _id?: string };
77+
const fields = projectionFn(newDoc) as Omit<Partial<T>, '_id'> & { _id?: string };
8478
delete fields._id;
85-
observer.added(newDoc._id, fields);
79+
observer.added(newDoc._id, fields as Partial<T>);
8680
}
8781
});
8882

@@ -93,11 +87,11 @@ export class DiffSequence {
9387
}
9488
}
9589

96-
private static diffQueryOrderedChanges<T extends { _id: string }, TProjection extends T = T>(
90+
private static diffQueryOrderedChanges<T extends { _id: string }>(
9791
oldResults: T[],
9892
newResults: T[],
99-
observer: Observer<T>,
100-
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => TProjection },
93+
observer: OrderedObserver<T>,
94+
options?: { projectionFn?: (doc: T | Omit<T, '_id'>) => Partial<T> },
10195
): void {
10296
options = options || {};
10397
const projectionFn = options.projectionFn || clone;
@@ -164,10 +158,10 @@ export class DiffSequence {
164158
for (let i = startOfGroup; i < endOfGroup; i++) {
165159
newDoc = newResults[i];
166160
if (!hasOwn.call(oldIndexOfId, newDoc._id)) {
167-
fields = projectionFn(newDoc) as Omit<TProjection, '_id'> & { _id?: string };
161+
fields = projectionFn(newDoc) as Omit<Partial<T>, '_id'> & { _id?: string };
168162
delete fields._id;
169-
observer.addedBefore?.(newDoc._id, fields, groupId);
170-
observer.added?.(newDoc._id, fields);
163+
if ('addedBefore' in observer) observer.addedBefore?.(newDoc._id, fields as Partial<T>, groupId);
164+
observer.added?.(newDoc._id, fields as Partial<T>);
171165
} else {
172166
oldDoc = oldResults[oldIndexOfId.get(newDoc._id)!];
173167
projectedNew = projectionFn(newDoc);
@@ -176,7 +170,7 @@ export class DiffSequence {
176170
if (!isObjEmpty(fields)) {
177171
observer.changed?.(newDoc._id, fields);
178172
}
179-
observer.movedBefore?.(newDoc._id, groupId);
173+
if ('movedBefore' in observer) observer.movedBefore?.(newDoc._id, groupId);
180174
}
181175
}
182176
if (groupId) {
@@ -193,56 +187,50 @@ export class DiffSequence {
193187
});
194188
}
195189

196-
private static diffObjects<TLeft, TRight>(
197-
left: Record<string, TLeft>,
198-
right: Record<string, TRight>,
190+
private static diffObjects<T extends object>(
191+
left: T,
192+
right: T,
199193
callbacks: {
200-
leftOnly?: (key: string, leftValue: TLeft) => void;
201-
rightOnly?: (key: string, rightValue: TRight) => void;
202-
both?: (key: string, leftValue: TLeft, rightValue: TRight) => void;
194+
leftOnly?: (key: keyof T, leftValue: T[keyof T]) => void;
195+
rightOnly?: (key: keyof T, rightValue: T[keyof T]) => void;
196+
both?: (key: keyof T, leftValue: T[keyof T], rightValue: T[keyof T]) => void;
203197
},
204198
): void {
205-
Object.keys(left).forEach((key) => {
206-
const leftValue = left[key];
207-
if (hasOwn.call(right, key)) {
199+
entriesOf(left).forEach(([key, leftValue]) => {
200+
if (key in right) {
208201
callbacks.both?.(key, leftValue, right[key]);
209202
} else {
210203
callbacks.leftOnly?.(key, leftValue);
211204
}
212205
});
213206

214207
if (callbacks.rightOnly) {
215-
Object.keys(right).forEach((key) => {
216-
const rightValue = right[key];
217-
if (!hasOwn.call(left, key)) {
208+
entriesOf(right).forEach(([key, rightValue]) => {
209+
if (!(key in left)) {
218210
callbacks.rightOnly?.(key, rightValue);
219211
}
220212
});
221213
}
222214
}
223215

224-
static makeChangedFields<TLeft, TRight>(
225-
newDoc: Record<string, TRight>,
226-
oldDoc: Record<string, TLeft>,
227-
): Record<string, TRight | undefined> {
228-
const fields: Record<string, TRight | undefined> = {};
229-
DiffSequence.diffObjects<TLeft, TRight>(oldDoc, newDoc, {
216+
static makeChangedFields<T extends object>(newDoc: T, oldDoc: T): Partial<T> {
217+
const fields: Partial<T> = {};
218+
DiffSequence.diffObjects(oldDoc, newDoc, {
230219
leftOnly(key) {
231220
fields[key] = undefined;
232221
},
233222
rightOnly(key, value) {
234223
fields[key] = value;
235224
},
236225
both(key, leftValue, rightValue) {
237-
if (!isEqual(leftValue as any, rightValue as any)) fields[key] = rightValue;
226+
if (!isEqual(leftValue, rightValue)) fields[key] = rightValue;
238227
},
239228
});
240229
return fields;
241230
}
242231

243-
static applyChanges(doc: Record<string, any>, changeFields: Record<string, any>): void {
244-
Object.keys(changeFields).forEach((key) => {
245-
const value = changeFields[key];
232+
static applyChanges<T extends object>(doc: T, changeFields: T): void {
233+
entriesOf(changeFields).forEach(([key, value]) => {
246234
if (typeof value === 'undefined') {
247235
delete doc[key];
248236
} else {

0 commit comments

Comments
 (0)