22 * @flow
33 */
44import { NativeModules } from 'react-native' ;
5- import { promisify } from './../../utils' ;
6- import { ReferenceBase } from './../base' ;
7- import Snapshot from './snapshot.js' ;
8- import Disconnect from './disconnect.js' ;
5+
96import Query from './query.js' ;
7+ import Snapshot from './snapshot' ;
8+ import Disconnect from './disconnect' ;
9+ import { ReferenceBase } from './../base' ;
10+ import { promisify , isFunction , isObject , tryJSONParse , tryJSONStringify , generatePushID } from './../../utils' ;
1011
1112const FirestackDatabase = NativeModules . FirestackDatabase ;
1213
@@ -26,29 +27,12 @@ export default class Reference extends ReferenceBase {
2627 super ( db . firestack , path ) ;
2728
2829 this . db = db ;
29- this . query = new Query ( this , path , existingModifiers ) ;
30- this . uid = uid ++ ; // uuid.v4();
30+ this . uid = uid += 1 ;
3131 this . listeners = { } ;
32-
33- // Aliases
34- this . get = this . getAt ;
35- this . set = this . setAt ;
36- this . update = this . updateAt ;
37- this . remove = this . removeAt ;
38-
32+ this . query = new Query ( this , path , existingModifiers ) ;
3933 this . log . debug ( 'Created new Reference' , this . dbPath ( ) , this . uid ) ;
4034 }
4135
42- // Parent roots
43- parent ( ) {
44- const parentPaths = this . path . slice ( 0 , - 1 ) ;
45- return new Reference ( this . db , parentPaths ) ;
46- }
47-
48- root ( ) {
49- return new Reference ( this . db , [ ] ) ;
50- }
51-
5236 child ( ...paths : Array < string > ) {
5337 return new Reference ( this . db , this . path . concat ( paths ) ) ;
5438 }
@@ -59,38 +43,53 @@ export default class Reference extends ReferenceBase {
5943 }
6044
6145 // Get the value of a ref either with a key
62- getAt ( ) {
46+ // todo - where is this on the FB JS api - seems just like another random function
47+ get ( ) {
6348 const path = this . dbPath ( ) ;
6449 const modifiers = this . query . getModifiers ( ) ;
6550 const modifiersString = this . query . getModifiersString ( ) ;
6651 return promisify ( 'onOnce' , FirestackDatabase ) ( path , modifiersString , modifiers , 'value' ) ;
6752 }
6853
69- setAt ( val : any ) {
54+ set ( value : any ) {
7055 const path = this . dbPath ( ) ;
71- const value = this . _serializeValue ( val ) ;
72- return promisify ( 'set' , FirestackDatabase ) ( path , value ) ;
56+ const _value = this . _serializeAnyType ( value ) ;
57+ return promisify ( 'set' , FirestackDatabase ) ( path , _value ) ;
7358 }
7459
75- updateAt ( val : any ) {
60+ update ( val : Object ) {
7661 const path = this . dbPath ( ) ;
77- const value = this . _serializeValue ( val ) ;
62+ const value = this . _serializeObject ( val ) ;
7863 return promisify ( 'update' , FirestackDatabase ) ( path , value ) ;
7964 }
8065
81- // TODO - what is key even for here?
82- removeAt ( key : string ) {
83- const path = this . dbPath ( ) ;
84- return promisify ( 'remove' , FirestackDatabase ) ( path ) ;
66+ remove ( ) {
67+ return promisify ( 'remove' , FirestackDatabase ) ( this . dbPath ( ) ) ;
8568 }
8669
87- push ( val : any = { } ) {
70+ /**
71+ *
72+ * @param value
73+ * @param onComplete
74+ * @returns {* }
75+ */
76+ push ( value : any , onComplete : Function ) {
77+ if ( value === null || value === undefined ) {
78+ // todo add server timestamp to push id call.
79+ const _paths = this . path . concat ( [ generatePushID ( ) ] ) ;
80+ return new Reference ( this . db , _paths ) ;
81+ }
82+
8883 const path = this . dbPath ( ) ;
89- const value = this . _serializeValue ( val ) ;
90- return promisify ( 'push' , FirestackDatabase ) ( path , value )
84+ const _value = this . _serializeAnyType ( value ) ;
85+ return promisify ( 'push' , FirestackDatabase ) ( path , _value )
9186 . then ( ( { ref } ) => {
92- const separator = '/' ;
93- return new Reference ( this . db , ref . split ( separator ) ) ;
87+ const newRef = new Reference ( this . db , ref . split ( '/' ) ) ;
88+ if ( isFunction ( onComplete ) ) return onComplete ( null , newRef ) ;
89+ return newRef ;
90+ } ) . catch ( ( e ) => {
91+ if ( isFunction ( onComplete ) ) return onComplete ( e , null ) ;
92+ return e ;
9493 } ) ;
9594 }
9695
@@ -100,7 +99,7 @@ export default class Reference extends ReferenceBase {
10099 const modifiersString = this . query . getModifiersString ( ) ;
101100 this . log . debug ( 'adding reference.on' , path , modifiersString , evt ) ;
102101 return this . db . storeRef ( this . uid , this ) . then ( ( ) => {
103- return this . db . on ( this . uid , path , modifiersString , modifiers , evt , cb ) . then ( subscriptions => {
102+ return this . db . on ( this . uid , path , modifiersString , modifiers , evt , cb ) . then ( ( subscriptions ) => {
104103 this . listeners [ evt ] = subscriptions ;
105104 } ) ;
106105 } ) ;
@@ -111,12 +110,11 @@ export default class Reference extends ReferenceBase {
111110 const modifiers = this . query . getModifiers ( ) ;
112111 const modifiersString = this . query . getModifiersString ( ) ;
113112 return this . db . storeRef ( this . uid , this ) . then ( ( ) => {
113+ // todo use event emitter - not callbacks
114114 return promisify ( 'onOnce' , FirestackDatabase ) ( path , modifiersString , modifiers , evt )
115115 . then ( ( { snapshot } ) => new Snapshot ( this , snapshot ) )
116- . then ( snapshot => {
117- if ( cb && typeof cb === 'function' ) {
118- cb ( snapshot ) ;
119- }
116+ . then ( ( snapshot ) => {
117+ if ( isFunction ( cb ) ) cb ( snapshot ) ;
120118 return snapshot ;
121119 } ) ;
122120 } ) ;
@@ -128,49 +126,50 @@ export default class Reference extends ReferenceBase {
128126 const modifiersString = this . query . getModifiersString ( ) ;
129127 this . log . debug ( 'ref.off(): ' , path , modifiers , evt ) ;
130128 return this . db . unstoreRef ( this . uid ) . then ( ( ) => {
131- return this . db . off ( this . uid , path , modifiersString , modifiers , evt , origCB ) . then ( subscriptions => {
129+ return this . db . off ( this . uid , path , modifiersString , modifiers , evt , origCB ) . then ( ( ) => {
130+ // todo urm - whats this?
132131 // delete this.listeners[eventName];
133132 // this.listeners[evt] = subscriptions;
134133 } ) ;
135134 } ) ;
136135 }
137136
138137 cleanup ( ) {
139- let promises = Object . keys ( this . listeners )
140- . map ( key => this . off ( key ) ) ;
141- return Promise . all ( promises ) ;
142- }
143-
144- // Sanitize value
145- // As Firebase cannot store date objects.
146- _serializeValue ( obj : Object = { } ) {
147- if ( ! obj ) {
148- return obj ;
149- }
150- return Object . keys ( obj ) . reduce ( ( sum , key ) => {
151- let val = obj [ key ] ;
152- if ( val instanceof Date ) {
153- val = val . toISOString ( ) ;
154- }
138+ return Promise . all ( Object . keys ( this . listeners ) . map ( key => this . off ( key ) ) ) ;
139+ }
140+
141+ /**
142+ *
143+ * @param obj
144+ * @returns {Object }
145+ * @private
146+ */
147+ _serializeObject ( obj : Object ) {
148+ if ( ! isObject ( obj ) ) return obj ;
149+
150+ // json stringify then parse it calls toString on Objects / Classes
151+ // that support it i.e new Date() becomes a ISO string.
152+ return tryJSONParse ( tryJSONStringify ( obj ) ) ;
153+ }
154+
155+ /**
156+ *
157+ * @param value
158+ * @returns {* }
159+ * @private
160+ */
161+ _serializeAnyType ( value : any ) {
162+ if ( isObject ( value ) ) {
155163 return {
156- ... sum ,
157- [ key ] : val ,
164+ type : 'object' ,
165+ value : this . _serializeObject ( value ) ,
158166 } ;
159- } , { } ) ;
160- }
167+ }
161168
162- // TODO this function isn't used anywhere - why is it here?
163- _deserializeValue ( obj : Object = { } ) {
164- return Object . keys ( obj ) . reduce ( ( sum , key ) => {
165- let val = obj [ key ] ;
166- if ( val instanceof Date ) {
167- val = val . getTime ( ) ;
168- }
169- return {
170- ...sum ,
171- [ key ] : val ,
172- } ;
173- } , { } ) ;
169+ return {
170+ type : typeof value ,
171+ value ,
172+ } ;
174173 }
175174
176175 // Modifiers
@@ -242,24 +241,36 @@ export default class Reference extends ReferenceBase {
242241 }
243242
244243 // attributes
245- get fullPath ( ) : string {
244+ toString ( ) : string {
246245 return this . dbPath ( ) ;
247246 }
248247
249- get name ( ) : string {
250- return this . path . splice ( - 1 ) ;
251- }
248+ dbPath ( paths ?: Array < string > ) : string {
249+ const path = paths || this . path ;
250+ const pathStr = ( path . length > 0 ? path . join ( '/' ) : '/' ) ;
252251
253- dbPath ( ) : string {
254- let path = this . path ;
255- let pathStr = ( path . length > 0 ? path . join ( '/' ) : '/' ) ;
256252 if ( pathStr [ 0 ] !== '/' ) {
257- pathStr = `/ ${pathStr } `;
253+ return `/${ pathStr } ` ;
258254 }
255+
259256 return pathStr ;
260257 }
261258
262259 get namespace ( ) : string {
263260 return 'firestack :dbRef ';
264261 }
262+
263+ get key ( ) : string | null {
264+ if ( ! this . path . length ) return null ;
265+ return this . path . slice ( this . path . length - 1 , this . path . length ) [ 0 ] ;
266+ }
267+
268+ get parent ( ) : Reference | null {
269+ if ( ! this . path . length || this . path . length === 1 ) return null ;
270+ return new Reference ( this . db , this . path . slice ( 0 , - 1 ) ) ;
271+ }
272+
273+ get root ( ) : Reference {
274+ return new Reference ( this . db , [ ] ) ;
275+ }
265276}
0 commit comments