11import { Injectable } from '@angular/core' ;
22import { merge } from 'lodash-es' ;
33import * as OTJson0 from 'ot-json0' ;
4+ import { Json0OpBuilder } from 'realtime-server/lib/esm/common/utils/json0-op-builder' ;
45import { 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' ;
611import { FileOfflineData , FileType } from './models/file-offline-data' ;
12+ import { RealtimeDoc } from './models/realtime-doc' ;
713import { Snapshot } from './models/snapshot' ;
814import { RealtimeService } from './realtime.service' ;
915import { objectId } from './utils' ;
@@ -33,6 +39,8 @@ export class TestRealtimeService extends RealtimeService {
3339 }
3440 }
3541
42+ /** Write a realtime doc into the store, for a given collection. An existing realtime doc with the same id is
43+ * overwritten. */
3644 addSnapshot < T > ( collection : string , snapshot : Partial < Snapshot < T > > , addToOfflineStore : boolean = false ) : void {
3745 const completeSnapshot = addSnapshotDefaults ( snapshot ) ;
3846 ( this . remoteStore as MemoryRealtimeRemoteStore ) . addSnapshot ( collection , completeSnapshot ) ;
@@ -57,6 +65,48 @@ export class TestRealtimeService extends RealtimeService {
5765 }
5866 }
5967
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+
60110 async updateQueriesLocal ( ) : Promise < void > {
61111 for ( const collectionQueries of this . subscribeQueries . values ( ) ) {
62112 for ( const query of collectionQueries ) {
0 commit comments