@@ -3,9 +3,8 @@ import logging from '../logging'
3
3
import { isImmutableValue } from '../immutable-helpers'
4
4
import { toImmutable } from '../immutable-helpers'
5
5
import { fromKeyPath , getStoreDeps , getComputeFn , getDeps , isGetter } from '../getter'
6
- import { isKeyPath } from '../key-path'
6
+ import { isEqual , isKeyPath } from '../key-path'
7
7
import { each } from '../utils'
8
- import isEqual from '../is-equal'
9
8
10
9
/**
11
10
* Immutable Types
@@ -96,20 +95,24 @@ exports.dispatch = function(reactorState, actionType, payload) {
96
95
* @return {ReactorState }
97
96
*/
98
97
exports . loadState = function ( reactorState , state ) {
99
- var stateToLoad = toImmutable ( { } ) . withMutations ( stateToLoad => {
98
+ let dirtyStores = [ ]
99
+ const stateToLoad = toImmutable ( { } ) . withMutations ( stateToLoad => {
100
100
each ( state , ( serializedStoreState , storeId ) => {
101
101
var store = reactorState . getIn ( [ 'stores' , storeId ] )
102
102
if ( store ) {
103
103
var storeState = store . deserialize ( serializedStoreState )
104
104
if ( storeState !== undefined ) {
105
105
stateToLoad . set ( storeId , storeState )
106
+ dirtyStores . push ( storeId )
106
107
}
107
108
}
108
109
} )
109
110
} )
110
111
111
- var newState = reactorState . get ( 'state' ) . merge ( stateToLoad )
112
- return reactorState . set ( 'state' , newState )
112
+ var dirtyStoresSet = Immutable . Set ( dirtyStores )
113
+ return reactorState
114
+ . update ( 'state' , state => state . merge ( stateToLoad ) )
115
+ . update ( 'dirtyStores' , stores => stores . union ( dirtyStoresSet ) )
113
116
}
114
117
115
118
/**
@@ -171,33 +174,35 @@ exports.addObserver = function(observerStoreMap, getter, handler) {
171
174
const currId = observerStoreMap . get ( 'nextId' )
172
175
const storeDeps = getStoreDeps ( getter )
173
176
const entry = Immutable . Map ( {
177
+ id : currId ,
174
178
storeDeps : storeDeps ,
175
179
getterKey : getterKey ,
176
180
getter : getter ,
177
181
handler : handler ,
178
- unwatched : false ,
179
182
} )
180
183
181
184
let updatedObserverStoreMap
182
185
if ( storeDeps . size === 0 ) {
183
- updatedObserverStoreMap = observerStoreMap . setIn ( [ 'any' , getterKey , handler ] , currId )
186
+ updatedObserverStoreMap = observerStoreMap . update ( 'any' , observerIds => observerIds . add ( currId ) )
184
187
} else {
185
188
updatedObserverStoreMap = observerStoreMap . withMutations ( map => {
186
189
storeDeps . forEach ( storeId => {
187
- map . setIn ( [ 'stores' , storeId , getterKey , handler ] , currId ) ;
190
+ let path = [ 'stores' , storeId ]
191
+ if ( ! map . hasIn ( path ) ) {
192
+ map . setIn ( path , Immutable . Set ( [ ] ) )
193
+ }
194
+ map . updateIn ( [ 'stores' , storeId ] , observerIds => observerIds . add ( currId ) ) ;
188
195
} )
189
196
} )
190
197
}
191
198
192
199
updatedObserverStoreMap = updatedObserverStoreMap
193
200
. set ( 'nextId' , currId + 1 )
194
- . update ( 'observersMap' , entries => {
195
- return entries . set ( currId , entry )
196
- } )
201
+ . setIn ( [ 'observersMap' , currId ] , entry )
197
202
198
203
return {
199
204
observerStoreMap : updatedObserverStoreMap ,
200
- unwatchEntry : entry ,
205
+ entry : entry ,
201
206
}
202
207
}
203
208
@@ -211,43 +216,47 @@ exports.addObserver = function(observerStoreMap, getter, handler) {
211
216
* removeObserver(observerStoreMap, getter, handler)
212
217
* @param {ObserverStoreMap } observerStoreMap
213
218
* @param {KeyPath|Getter } getter
214
- * @param {function } handler
219
+ * @param {Function } handler
215
220
* @return {ObserverStoreMap }
216
221
*/
217
222
exports . removeObserver = function ( observerStoreMap , getter , handler ) {
218
- debugger ;
219
- const getterKey = getter
220
- if ( isKeyPath ( getter ) ) {
221
- getter = fromKeyPath ( getter )
222
- }
223
- const storeDeps = getStoreDeps ( getter )
224
- let pathsToRemove = [ ]
225
-
226
- if ( storeDeps . size === 0 ) {
227
- let path = [ 'any' , getterKey ]
228
- if ( handler ) {
229
- path . push ( handler )
223
+ const entriesToRemove = observerStoreMap . get ( 'observersMap' ) . filter ( entry => {
224
+ // use the getterKey in the case of a keyPath is transformed to a getter in addObserver
225
+ let entryGetter = entry . get ( 'getterKey' )
226
+ let handlersMatch = ( ! handler || entry . get ( 'handler' ) === handler )
227
+ if ( ! handlersMatch ) {
228
+ return false
230
229
}
231
- pathsToRemove . push ( path )
232
- } else {
233
- storeDeps . forEach ( storeId => {
234
- let path = [ 'stores' , storeId , getterKey ]
235
- if ( handler ) {
236
- path . push ( handler )
237
- }
238
- pathsToRemove . push ( path )
239
- } )
240
- }
230
+ // check for a by-value equality of keypaths
231
+ if ( isKeyPath ( getter ) && isKeyPath ( entryGetter ) ) {
232
+ return isEqual ( getter , entryGetter )
233
+ }
234
+ // we are comparing two getters do it by reference
235
+ return ( getter === entryGetter )
236
+ } )
241
237
242
238
return observerStoreMap . withMutations ( map => {
243
- pathsToRemove . forEach ( path => {
244
- var observerId = observerStoreMap . getIn ( path )
239
+ entriesToRemove . forEach ( entry => exports . removeObserverByEntry ( map , entry ) )
240
+ } )
241
+ }
245
242
246
- map . removeIn ( path )
247
- if ( observerId ) {
248
- map . removeIn ( [ 'observersMap' , observerId ] )
249
- }
250
- } )
243
+ /**
244
+ * Removes an observer entry by id from the observerStoreMap
245
+ */
246
+ exports . removeObserverByEntry = function ( observerStoreMap , entry ) {
247
+ return observerStoreMap . withMutations ( map => {
248
+ const id = entry . get ( 'id' )
249
+ const storeDeps = entry . get ( 'storeDeps' )
250
+
251
+ if ( storeDeps . size === 0 ) {
252
+ map . update ( 'any' , anyObsevers => anyObsevers . remove ( id ) )
253
+ } else {
254
+ storeDeps . forEach ( storeId => {
255
+ map . updateIn ( [ 'stores' , storeId ] , observers => observers . remove ( id ) )
256
+ } )
257
+ }
258
+
259
+ map . removeIn ( [ 'observersMap' , id ] )
251
260
} )
252
261
}
253
262
@@ -334,6 +343,23 @@ exports.evaluate = function evaluate(reactorState, keyPathOrGetter) {
334
343
)
335
344
}
336
345
346
+ /**
347
+ * Returns serialized state for all stores
348
+ * @param {ReactorState } reactorState
349
+ * @return {Object }
350
+ */
351
+ exports . serialize = function ( reactorState ) {
352
+ let serialized = { }
353
+ reactorState . get ( 'stores' ) . forEach ( ( store , id ) => {
354
+ let storeState = reactorState . getIn ( [ 'state' , id ] )
355
+ let serializedState = store . serialize ( storeState )
356
+ if ( serializedState !== undefined ) {
357
+ serialized [ id ] = serializedState
358
+ }
359
+ } )
360
+ return serialized
361
+ }
362
+
337
363
/**
338
364
* @param {ReactorState } reactorState
339
365
* @param {Getter } getter
0 commit comments