1
1
import { Injectable } from '@angular/core' ;
2
2
import { merge } from 'lodash-es' ;
3
3
import * as OTJson0 from 'ot-json0' ;
4
+ import { Json0OpBuilder } from 'realtime-server/lib/esm/common/utils/json0-op-builder' ;
4
5
import { MemoryOfflineStore } from './memory-offline-store' ;
5
- import { MemoryRealtimeQueryAdapter , MemoryRealtimeRemoteStore } from './memory-realtime-remote-store' ;
6
+ import {
7
+ MemoryRealtimeDocAdapter ,
8
+ MemoryRealtimeQueryAdapter ,
9
+ MemoryRealtimeRemoteStore
10
+ } from './memory-realtime-remote-store' ;
6
11
import { FileOfflineData , FileType } from './models/file-offline-data' ;
12
+ import { RealtimeDoc } from './models/realtime-doc' ;
7
13
import { Snapshot } from './models/snapshot' ;
8
14
import { RealtimeService } from './realtime.service' ;
9
15
import { objectId } from './utils' ;
@@ -33,6 +39,8 @@ export class TestRealtimeService extends RealtimeService {
33
39
}
34
40
}
35
41
42
+ /** Write a realtime doc into the store, for a given collection. An existing realtime doc with the same id is
43
+ * overwritten. */
36
44
addSnapshot < T > ( collection : string , snapshot : Partial < Snapshot < T > > , addToOfflineStore : boolean = false ) : void {
37
45
const completeSnapshot = addSnapshotDefaults ( snapshot ) ;
38
46
( this . remoteStore as MemoryRealtimeRemoteStore ) . addSnapshot ( collection , completeSnapshot ) ;
@@ -57,6 +65,48 @@ export class TestRealtimeService extends RealtimeService {
57
65
}
58
66
}
59
67
68
+ /** Intended to do the same thing as `updateQueryAdaptersRemote` but without remoteChanges$ emitting, which can be
69
+ * done in follow up. */
70
+ updateQueryAdaptersRemoteQuietly ( ) : MemoryRealtimeQueryAdapter [ ] {
71
+ const adaptersToEmit : MemoryRealtimeQueryAdapter [ ] = [ ] ;
72
+ for ( const collectionQueries of this . subscribeQueries . values ( ) ) {
73
+ for ( const query of collectionQueries ) {
74
+ const adapter = query . adapter as MemoryRealtimeQueryAdapter ;
75
+ if ( ( adapter as any ) . performQuery ( ) ) {
76
+ adaptersToEmit . push ( adapter ) ;
77
+ }
78
+ }
79
+ }
80
+ return adaptersToEmit ;
81
+ }
82
+
83
+ /** Simulate a change happening externally. The MemoryRealtimeDocAdapter data and MemoryRealtimeQueryAdapter results
84
+ * are updated before changes are announced, so when changes begin to be announced, the docs and queries are all
85
+ * up-to-date. The order of emits, and presence or absence of RealtimeQuery.remoteDocChanges$, may be different than
86
+ * when running the app. */
87
+ async simulateRemoteChange ( doc : RealtimeDoc , ops : any ) : Promise < void > {
88
+ const docAdapter : MemoryRealtimeDocAdapter = doc . adapter as MemoryRealtimeDocAdapter ;
89
+ // Submitting ops to the realtime doc adapter to simulate writing data on a remote server may seem backwards but
90
+ // is getting the job done.
91
+ docAdapter . submitOpWithoutEmitting ( ops ) ;
92
+ const queryAdaptersToEmit : MemoryRealtimeQueryAdapter [ ] = this . updateQueryAdaptersRemoteQuietly ( ) ;
93
+ docAdapter . emitChange ( ops ) ;
94
+ docAdapter . emitRemoteChange ( ops ) ;
95
+ for ( const adapter of queryAdaptersToEmit ) {
96
+ adapter . remoteChanges$ . next ( ) ;
97
+ }
98
+ }
99
+
100
+ async simulateRemoteChangeJson0Op < T > (
101
+ doc : RealtimeDoc < T > ,
102
+ build : ( builder : Json0OpBuilder < T > ) => void
103
+ ) : Promise < void > {
104
+ if ( doc . data == null ) throw new Error ( 'Cannot simulate remote change on document with null data' ) ;
105
+ const builder = new Json0OpBuilder ( doc . data ) as Json0OpBuilder < T > ;
106
+ build ( builder ) ;
107
+ if ( builder . op . length > 0 ) await this . simulateRemoteChange ( doc , builder . op ) ;
108
+ }
109
+
60
110
async updateQueriesLocal ( ) : Promise < void > {
61
111
for ( const collectionQueries of this . subscribeQueries . values ( ) ) {
62
112
for ( const query of collectionQueries ) {
0 commit comments