2017-03-02 11:40:08 +00:00
/ * *
* @ flow
* /
import { NativeModules } from 'react-native' ;
import Query from './query.js' ;
import Snapshot from './snapshot' ;
import Disconnect from './disconnect' ;
import { ReferenceBase } from './../base' ;
import { promisify , isFunction , isObject , tryJSONParse , tryJSONStringify , generatePushID } from './../../utils' ;
2017-03-02 13:09:41 +00:00
const FirebaseDatabase = NativeModules . RNFirebaseDatabase ;
2017-04-26 11:21:53 +00:00
// Unique Reference ID for native events
let refId = 1 ;
2017-03-02 11:40:08 +00:00
/ * *
2017-05-06 13:33:55 +00:00
* Enum for event types
* @ readonly
* @ enum { String }
* /
const ReferenceEventTypes = {
value : 'value' ,
child _added : 'child_added' ,
child _removed : 'child_removed' ,
child _changed : 'child_changed' ,
child _moved : 'child_moved' ,
} ;
/ * *
* @ typedef { String } ReferenceLocation - Path to location in the database , relative
* to the root reference . Consists of a path where segments are separated by a
* forward slash ( / ) a n d e n d s i n a R e f e r e n c e K e y - e x c e p t t h e r o o t l o c a t i o n , w h i c h
* has no ReferenceKey .
*
* @ example
* // root reference location: '/'
* // non-root reference: '/path/to/referenceKey'
* /
/ * *
* @ typedef { String } ReferenceKey - Identifier for each location that is unique to that
* location , within the scope of its parent . The last part of a ReferenceLocation .
* /
/ * *
* Represents a specific location in your Database that can be used for
* reading or writing data .
*
* You can reference the root using firebase . database ( ) . ref ( ) or a child location
* by calling firebase . database ( ) . ref ( "child/path" ) .
*
2017-03-10 10:46:55 +00:00
* @ link https : //firebase.google.com/docs/reference/js/firebase.database.Reference
2017-03-02 11:40:08 +00:00
* @ class Reference
2017-05-06 13:33:55 +00:00
* @ extends ReferenceBase
2017-03-02 11:40:08 +00:00
* /
export default class Reference extends ReferenceBase {
2017-04-26 11:21:53 +00:00
refId : number ;
2017-05-30 11:46:28 +00:00
refListeners : { [ listenerId : number ] : DatabaseListener } ;
2017-03-24 22:53:56 +00:00
database : FirebaseDatabase ;
2017-03-02 11:40:08 +00:00
query : Query ;
2017-04-26 11:21:53 +00:00
constructor ( database : FirebaseDatabase , path : string , existingModifiers ? : Array < DatabaseModifier > ) {
2017-05-30 11:28:53 +00:00
super ( path ) ;
2017-04-26 11:21:53 +00:00
this . refId = refId ++ ;
2017-05-30 11:46:28 +00:00
this . refListeners = { } ;
2017-03-24 22:53:56 +00:00
this . database = database ;
2017-03-02 11:40:08 +00:00
this . namespace = 'firebase:db:ref' ;
this . query = new Query ( this , path , existingModifiers ) ;
2017-04-26 11:21:53 +00:00
this . log . debug ( 'Created new Reference' , this . refId , this . path ) ;
2017-03-02 11:40:08 +00:00
}
/ * *
*
* @ param bool
* @ returns { * }
* /
keepSynced ( bool : boolean ) {
2017-03-24 22:53:56 +00:00
const path = this . path ;
2017-03-02 11:40:08 +00:00
return promisify ( 'keepSynced' , FirebaseDatabase ) ( path , bool ) ;
}
/ * *
*
* @ param value
* @ returns { * }
* /
set ( value : any ) {
2017-03-24 22:53:56 +00:00
const path = this . path ;
2017-03-02 11:40:08 +00:00
const _value = this . _serializeAnyType ( value ) ;
return promisify ( 'set' , FirebaseDatabase ) ( path , _value ) ;
}
/ * *
*
* @ param val
* @ returns { * }
* /
update ( val : Object ) {
2017-03-24 22:53:56 +00:00
const path = this . path ;
2017-03-02 11:40:08 +00:00
const value = this . _serializeObject ( val ) ;
return promisify ( 'update' , FirebaseDatabase ) ( path , value ) ;
}
/ * *
*
* @ returns { * }
* /
remove ( ) {
2017-03-24 22:53:56 +00:00
return promisify ( 'remove' , FirebaseDatabase ) ( this . path ) ;
2017-03-02 11:40:08 +00:00
}
/ * *
*
* @ param value
* @ param onComplete
* @ returns { * }
* /
push ( value : any , onComplete : Function ) {
if ( value === null || value === undefined ) {
2017-03-24 22:53:56 +00:00
return new Reference ( this . database , ` ${ this . path } / ${ generatePushID ( this . database . serverTimeOffset ) } ` ) ;
2017-03-02 11:40:08 +00:00
}
2017-03-24 22:53:56 +00:00
const path = this . path ;
2017-03-02 11:40:08 +00:00
const _value = this . _serializeAnyType ( value ) ;
return promisify ( 'push' , FirebaseDatabase ) ( path , _value )
. then ( ( { ref } ) => {
2017-03-24 22:53:56 +00:00
const newRef = new Reference ( this . database , ref ) ;
2017-03-02 11:40:08 +00:00
if ( isFunction ( onComplete ) ) return onComplete ( null , newRef ) ;
return newRef ;
} ) . catch ( ( e ) => {
if ( isFunction ( onComplete ) ) return onComplete ( e , null ) ;
return e ;
} ) ;
}
2017-03-07 16:54:04 +00:00
/ * *
2017-05-09 07:09:03 +00:00
* iOS : Called once with the initial data at the specified location and then once each
* time the data changes . It won ' t trigger until the entire contents have been
* synchronized .
*
* Android : ( @ link https : //github.com/invertase/react-native-firebase/issues/92)
* - Array & number values : Called once with the initial data at the specified
* location and then twice each time the value changes .
* - Other data types : Called once with the initial data at the specified location
* and once each time the data type changes .
2017-03-07 16:54:04 +00:00
*
2017-05-06 13:33:55 +00:00
* @ callback onValueCallback
* @ param { ! DataSnapshot } dataSnapshot - Snapshot representing data at the location
2017-05-09 07:09:03 +00:00
* specified by the current ref . If location has no data , . val ( ) will return null .
2017-05-06 13:33:55 +00:00
* /
/ * *
* Called once for each initial child at the specified location and then again
* every time a new child is added .
*
* @ callback onChildAddedCallback
* @ param { ! DataSnapshot } dataSnapshot - Snapshot reflecting the data for the
* relevant child .
* @ param { ? ReferenceKey } previousChildKey - For ordering purposes , the key
* of the previous sibling child by sort order , or null if it is the first child .
* /
/ * *
* Called once every time a child is removed .
*
* A child will get removed when either :
* - remove ( ) is explicitly called on a child or one of its ancestors
* - set ( null ) is called on that child or one of its ancestors
* - a child has all of its children removed
* - there is a query in effect which now filters out the child ( because it ' s sort
* order changed or the max limit was hit )
*
* @ callback onChildRemovedCallback
* @ param { ! DataSnapshot } dataSnapshot - Snapshot reflecting the old data for
* the child that was removed .
* /
/ * *
* Called when a child ( or any of its descendants ) changes .
*
* A single child _changed event may represent multiple changes to the child .
*
* @ callback onChildChangedCallback
* @ param { ! DataSnapshot } dataSnapshot - Snapshot reflecting new child contents .
* @ param { ? ReferenceKey } previousChildKey - For ordering purposes , the key
* of the previous sibling child by sort order , or null if it is the first child .
* /
/ * *
* Called when a child ' s sort order changes , i . e . its position relative to its
* siblings changes .
*
* @ callback onChildMovedCallback
* @ param { ! DataSnapshot } dataSnapshot - Snapshot reflecting the data of the moved
* child .
* @ param { ? ReferenceKey } previousChildKey - For ordering purposes , the key
* of the previous sibling child by sort order , or null if it is the first child .
* /
/ * *
* @ typedef ( onValueCallback | onChildAddedCallback | onChildRemovedCallback | onChildChangedCallback | onChildMovedCallback ) ReferenceEventCallback
* /
/ * *
* Called if the event subscription is cancelled because the client does
* not have permission to read this data ( or has lost the permission to do so ) .
*
* @ callback onFailureCallback
* @ param { Error } error - Object indicating why the failure occurred
* /
/ * *
* Binds callback handlers to when data changes at the current ref ' s location .
* The primary method of reading data from a Database .
*
* Callbacks can be unbound using { @ link off } .
*
* Event Types :
*
* - value : { @ link onValueCallback } .
* - child _added : { @ link onChildAddedCallback }
* - child _removed : { @ link onChildRemovedCallback }
* - child _changed : { @ link onChildChangedCallback }
* - child _moved : { @ link onChildMovedCallback }
*
* @ param { ReferenceEventType } eventType - Type of event to attach a callback for .
* @ param { ReferenceEventCallback } successCallback - Function that will be called
* when the event occurs with the new data .
* @ param { onFailureCallback = } failureCallbackOrContext - Optional callback that is called
* if the event subscription fails . { @ link onFailureCallback }
* @ param { *= } context - Optional object to bind the callbacks to when calling them .
* @ returns { ReferenceEventCallback } callback function , unmodified ( unbound ) , for
* convenience if you want to pass an inline function to on ( ) and store it later for
* removing using off ( ) .
*
* { @ link https : //firebase.google.com/docs/reference/js/firebase.database.Reference#on}
2017-03-07 16:54:04 +00:00
* /
2017-05-06 13:33:55 +00:00
on ( eventType : string , successCallback : ( ) => any , failureCallbackOrContext : ( ) => any , context : any ) {
if ( ! eventType ) throw new Error ( 'Error: Query on failed: Was called with 0 arguments. Expects at least 2' ) ;
if ( ! ReferenceEventTypes [ eventType ] ) throw new Error ( 'Query.on failed: First argument must be a valid event type: "value", "child_added", "child_removed", "child_changed", or "child_moved".' ) ;
if ( ! successCallback ) throw new Error ( 'Query.on failed: Was called with 1 argument. Expects at least 2.' ) ;
if ( ! isFunction ( successCallback ) ) throw new Error ( 'Query.on failed: Second argument must be a valid function.' ) ;
if ( arguments . length > 2 && ! failureCallbackOrContext ) throw new Error ( 'Query.on failed: third argument must either be a cancel callback or a context object.' ) ;
this . log . debug ( 'adding reference.on' , this . refId , eventType ) ;
let _failureCallback ;
let _context ;
if ( context ) {
_context = context ;
_failureCallback = failureCallbackOrContext ;
} else {
if ( isFunction ( failureCallbackOrContext ) ) {
_failureCallback = failureCallbackOrContext ;
} else {
_context = failureCallbackOrContext ;
}
}
if ( _failureCallback ) {
_failureCallback = ( error ) => {
if ( error . message . startsWith ( 'FirebaseError: permission_denied' ) ) {
error . message = ` permission_denied at / ${ this . path } : Client doesn \' t have permission to access the desired data. `
}
failureCallbackOrContext ( error ) ;
}
}
let _successCallback ;
if ( _context ) {
_successCallback = successCallback . bind ( _context ) ;
} else {
_successCallback = successCallback ;
}
2017-04-26 11:21:53 +00:00
const listener = {
2017-05-30 11:46:28 +00:00
listenerId : Object . keys ( this . refListeners ) . length + 1 ,
2017-05-06 13:33:55 +00:00
eventName : eventType ,
successCallback : _successCallback ,
failureCallback : _failureCallback ,
2017-04-26 11:21:53 +00:00
} ;
2017-05-06 13:33:55 +00:00
2017-05-30 11:46:28 +00:00
this . refListeners [ listener . listenerId ] = listener ;
2017-04-26 11:21:53 +00:00
this . database . on ( this , listener ) ;
2017-03-24 22:53:56 +00:00
return successCallback ;
2017-03-02 11:40:08 +00:00
}
2017-03-07 16:54:04 +00:00
/ * *
*
2017-04-26 11:21:53 +00:00
* @ param eventName
2017-03-07 16:54:04 +00:00
* @ param successCallback
* @ param failureCallback
* @ param context TODO
* @ returns { Promise . < TResult > }
* /
2017-04-26 11:21:53 +00:00
once ( eventName : string = 'value' , successCallback : ( snapshot : Object ) => void , failureCallback : ( error : FirebaseError ) => void ) {
return promisify ( 'once' , FirebaseDatabase ) ( this . refId , this . path , this . query . getModifiers ( ) , eventName )
2017-03-02 11:40:08 +00:00
. then ( ( { snapshot } ) => new Snapshot ( this , snapshot ) )
. then ( ( snapshot ) => {
2017-03-07 16:54:04 +00:00
if ( isFunction ( successCallback ) ) successCallback ( snapshot ) ;
2017-03-02 11:40:08 +00:00
return snapshot ;
2017-03-07 16:54:04 +00:00
} )
. catch ( ( error ) => {
2017-03-24 22:53:56 +00:00
const firebaseError = this . database . _toFirebaseError ( error ) ;
2017-03-07 17:35:48 +00:00
if ( isFunction ( failureCallback ) ) return failureCallback ( firebaseError ) ;
2017-03-07 16:58:33 +00:00
return Promise . reject ( firebaseError ) ;
2017-03-02 11:40:08 +00:00
} ) ;
}
2017-03-07 17:35:48 +00:00
/ * *
2017-05-06 13:33:55 +00:00
* Detaches a callback attached with on ( ) .
2017-03-07 17:35:48 +00:00
*
2017-05-06 13:33:55 +00:00
* Calling off ( ) on a parent listener will not automatically remove listeners
* registered on child nodes .
*
* If on ( ) was called multiple times with the same eventType off ( ) must be
* called multiple times to completely remove it .
*
* If a callback is not specified , all callbacks for the specified eventType
* will be removed . If no eventType or callback is specified , all callbacks
* for the Reference will be removed .
*
* If a context is specified , it too is used as a filter parameter : a callback
* will only be detached if , when it was attached with on ( ) , the same event type ,
* callback function and context were provided .
*
* If no callbacks matching the parameters provided are found , no callbacks are
* detached .
*
* @ param { ( 'value' | 'child_added' | 'child_changed' | 'child_removed' | 'child_moved' ) = } eventType - Type of event to detach callback for .
* @ param { Function = } originalCallback - Original callback passed to on ( )
* @ param { *= } context - The context passed to on ( ) when the callback was bound
*
* { @ link https : //firebase.google.com/docs/reference/js/firebase.database.Reference#off}
2017-03-07 17:35:48 +00:00
* /
2017-05-06 13:33:55 +00:00
off ( eventType ? : string = '' , originalCallback ? : ( ) => any ) {
this . log . debug ( 'ref.off(): ' , this . refId , eventType ) ;
2017-04-28 09:27:29 +00:00
// $FlowFixMe
2017-05-30 11:46:28 +00:00
const listeners : Array < DatabaseListener > = Object . values ( this . refListeners ) ;
2017-04-26 11:21:53 +00:00
let listenersToRemove ;
2017-05-06 13:33:55 +00:00
if ( eventType && originalCallback ) {
2017-04-28 09:27:29 +00:00
listenersToRemove = listeners . filter ( ( listener ) => {
2017-05-06 13:33:55 +00:00
return listener . eventName === eventType && listener . successCallback === originalCallback ;
2017-04-26 11:21:53 +00:00
} ) ;
// Only remove a single listener as per the web spec
if ( listenersToRemove . length > 1 ) listenersToRemove = [ listenersToRemove [ 0 ] ] ;
2017-05-06 13:33:55 +00:00
} else if ( eventType ) {
2017-04-28 09:27:29 +00:00
listenersToRemove = listeners . filter ( ( listener ) => {
2017-05-06 13:33:55 +00:00
return listener . eventName === eventType ;
2017-04-26 11:21:53 +00:00
} ) ;
2017-05-06 13:33:55 +00:00
} else if ( originalCallback ) {
2017-04-28 09:27:29 +00:00
listenersToRemove = listeners . filter ( ( listener ) => {
2017-05-06 13:33:55 +00:00
return listener . successCallback === originalCallback ;
2017-04-26 11:21:53 +00:00
} ) ;
} else {
2017-04-28 09:27:29 +00:00
listenersToRemove = listeners ;
2017-04-26 11:21:53 +00:00
}
// Remove the listeners from the reference to prevent memory leaks
listenersToRemove . forEach ( ( listener ) => {
2017-05-30 11:46:28 +00:00
delete this . refListeners [ listener . listenerId ] ;
2017-04-26 11:21:53 +00:00
} ) ;
2017-05-30 11:46:28 +00:00
return this . database . off ( this . refId , listenersToRemove , Object . keys ( this . refListeners ) . length ) ;
2017-03-24 22:53:56 +00:00
}
/ * *
* Atomically modifies the data at this location .
* @ url https : //firebase.google.com/docs/reference/js/firebase.database.Reference#transaction
* @ param transactionUpdate
* @ param onComplete
* @ param applyLocally
* /
2017-05-10 16:37:03 +00:00
transaction (
transactionUpdate : Function ,
onComplete : ( error : ? Error , committed : boolean , snapshot : ? Snapshot ) => * ,
applyLocally : boolean = false
) {
if ( ! isFunction ( transactionUpdate ) ) {
return Promise . reject (
new Error ( 'Missing transactionUpdate function argument.' )
) ;
}
2017-03-24 22:53:56 +00:00
return new Promise ( ( resolve , reject ) => {
const onCompleteWrapper = ( error , committed , snapshotData ) => {
if ( error ) {
2017-04-04 16:58:20 +00:00
if ( typeof onComplete === 'function' ) {
onComplete ( error , committed , null ) ;
}
2017-03-24 22:53:56 +00:00
return reject ( error ) ;
}
const snapshot = new Snapshot ( this , snapshotData ) ;
2017-04-04 16:58:20 +00:00
if ( typeof onComplete === 'function' ) {
2017-03-24 22:53:56 +00:00
onComplete ( null , committed , snapshot ) ;
}
return resolve ( { committed , snapshot } ) ;
} ;
this . database . transaction . add ( this , transactionUpdate , onCompleteWrapper , applyLocally ) ;
} ) ;
2017-03-02 11:40:08 +00:00
}
/ * *
* MODIFIERS
* /
/ * *
*
* @ returns { Reference }
* /
orderByKey ( ) : Reference {
return this . orderBy ( 'orderByKey' ) ;
}
/ * *
*
* @ returns { Reference }
* /
orderByPriority ( ) : Reference {
return this . orderBy ( 'orderByPriority' ) ;
}
/ * *
*
* @ returns { Reference }
* /
orderByValue ( ) : Reference {
return this . orderBy ( 'orderByValue' ) ;
}
/ * *
*
* @ param key
* @ returns { Reference }
* /
orderByChild ( key : string ) : Reference {
return this . orderBy ( 'orderByChild' , key ) ;
}
/ * *
*
* @ param name
* @ param key
* @ returns { Reference }
* /
orderBy ( name : string , key ? : string ) : Reference {
2017-03-24 22:53:56 +00:00
const newRef = new Reference ( this . database , this . path , this . query . getModifiers ( ) ) ;
2017-04-26 11:21:53 +00:00
newRef . query . orderBy ( name , key ) ;
2017-03-02 11:40:08 +00:00
return newRef ;
}
/ * *
* LIMITS
* /
/ * *
*
* @ param limit
* @ returns { Reference }
* /
limitToLast ( limit : number ) : Reference {
return this . limit ( 'limitToLast' , limit ) ;
}
/ * *
*
* @ param limit
* @ returns { Reference }
* /
limitToFirst ( limit : number ) : Reference {
return this . limit ( 'limitToFirst' , limit ) ;
}
/ * *
*
* @ param name
* @ param limit
* @ returns { Reference }
* /
limit ( name : string , limit : number ) : Reference {
2017-03-24 22:53:56 +00:00
const newRef = new Reference ( this . database , this . path , this . query . getModifiers ( ) ) ;
2017-04-26 11:21:53 +00:00
newRef . query . limit ( name , limit ) ;
2017-03-02 11:40:08 +00:00
return newRef ;
}
/ * *
* FILTERS
* /
/ * *
*
* @ param value
* @ param key
* @ returns { Reference }
* /
equalTo ( value : any , key ? : string ) : Reference {
return this . filter ( 'equalTo' , value , key ) ;
}
/ * *
*
* @ param value
* @ param key
* @ returns { Reference }
* /
endAt ( value : any , key ? : string ) : Reference {
return this . filter ( 'endAt' , value , key ) ;
}
/ * *
*
* @ param value
* @ param key
* @ returns { Reference }
* /
startAt ( value : any , key ? : string ) : Reference {
return this . filter ( 'startAt' , value , key ) ;
}
/ * *
*
* @ param name
* @ param value
* @ param key
* @ returns { Reference }
* /
filter ( name : string , value : any , key ? : string ) : Reference {
2017-03-24 22:53:56 +00:00
const newRef = new Reference ( this . database , this . path , this . query . getModifiers ( ) ) ;
2017-04-26 11:21:53 +00:00
newRef . query . filter ( name , value , key ) ;
2017-03-02 11:40:08 +00:00
return newRef ;
}
2017-03-08 13:21:21 +00:00
/ * *
*
* @ returns { Disconnect }
* /
2017-03-02 11:40:08 +00:00
onDisconnect ( ) {
return new Disconnect ( this . path ) ;
}
2017-03-08 13:21:21 +00:00
/ * *
2017-05-06 13:33:55 +00:00
* Creates a Reference to a child of the current Reference , using a relative path .
* No validation is performed on the path to ensure it has a valid format .
* @ param { String } path relative to current ref ' s location
* @ returns { ! Reference } A new Reference to the path provided , relative to the current
* Reference
* { @ link https : //firebase.google.com/docs/reference/js/firebase.database.Reference#child}
2017-03-08 13:21:21 +00:00
* /
2017-03-02 11:40:08 +00:00
child ( path : string ) {
2017-03-24 22:53:56 +00:00
return new Reference ( this . database , ` ${ this . path } / ${ path } ` ) ;
2017-03-02 11:40:08 +00:00
}
2017-03-08 13:21:21 +00:00
/ * *
* Return the ref as a path string
* @ returns { string }
* /
2017-03-02 11:40:08 +00:00
toString ( ) : string {
2017-03-24 22:53:56 +00:00
return this . path ;
2017-03-02 11:40:08 +00:00
}
2017-04-22 16:59:04 +00:00
/ * *
* Returns whether another Reference represent the same location and are from the
* same instance of firebase . app . App - multiple firebase apps not currently supported .
* @ param { Reference } otherRef - Other reference to compare to this one
* @ return { Boolean } Whether otherReference is equal to this one
2017-05-06 13:33:55 +00:00
*
2017-04-22 16:59:04 +00:00
* { @ link https : //firebase.google.com/docs/reference/js/firebase.database.Reference#isEqual}
* /
isEqual ( otherRef : Reference ) : boolean {
return ! ! otherRef && otherRef . constructor === Reference && otherRef . key === this . key ;
}
2017-03-02 11:40:08 +00:00
/ * *
* GETTERS
* /
/ * *
2017-05-06 13:33:55 +00:00
* The parent location of a Reference , or null for the root Reference .
* @ type { Reference }
*
* { @ link https : //firebase.google.com/docs/reference/js/firebase.database.Reference#parent}
2017-03-02 11:40:08 +00:00
* /
get parent ( ) : Reference | null {
if ( this . path === '/' ) return null ;
2017-03-24 22:53:56 +00:00
return new Reference ( this . database , this . path . substring ( 0 , this . path . lastIndexOf ( '/' ) ) ) ;
2017-03-02 11:40:08 +00:00
}
2017-04-22 08:27:37 +00:00
/ * *
* A reference to itself
* @ type { ! Reference }
2017-05-06 13:33:55 +00:00
*
2017-04-22 08:27:37 +00:00
* { @ link https : //firebase.google.com/docs/reference/js/firebase.database.Reference#ref}
* /
get ref ( ) : Reference {
return this ;
}
2017-03-02 11:40:08 +00:00
/ * *
2017-05-06 13:33:55 +00:00
* Reference to the root of the database : '/'
* @ type { ! Reference }
*
* { @ link https : //firebase.google.com/docs/reference/js/firebase.database.Reference#root}
2017-03-02 11:40:08 +00:00
* /
get root ( ) : Reference {
2017-03-24 22:53:56 +00:00
return new Reference ( this . database , '/' ) ;
2017-03-02 11:40:08 +00:00
}
/ * *
* INTERNALS
* /
/ * *
*
* @ param obj
* @ returns { Object }
* @ private
* /
_serializeObject ( obj : Object ) {
if ( ! isObject ( obj ) ) return obj ;
// json stringify then parse it calls toString on Objects / Classes
// that support it i.e new Date() becomes a ISO string.
return tryJSONParse ( tryJSONStringify ( obj ) ) ;
}
/ * *
*
* @ param value
* @ returns { * }
* @ private
* /
_serializeAnyType ( value : any ) {
if ( isObject ( value ) ) {
return {
type : 'object' ,
value : this . _serializeObject ( value ) ,
} ;
}
return {
type : typeof value ,
value ,
} ;
}
}