2
2
* @flow
3
3
*/
4
4
import { 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
+
9
6
import 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' ;
10
11
11
12
const FirestackDatabase = NativeModules . FirestackDatabase ;
12
13
@@ -26,29 +27,12 @@ export default class Reference extends ReferenceBase {
26
27
super ( db . firestack , path ) ;
27
28
28
29
this . db = db ;
29
- this . query = new Query ( this , path , existingModifiers ) ;
30
- this . uid = uid ++ ; // uuid.v4();
30
+ this . uid = uid += 1 ;
31
31
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 ) ;
39
33
this . log . debug ( 'Created new Reference' , this . dbPath ( ) , this . uid ) ;
40
34
}
41
35
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
-
52
36
child ( ...paths : Array < string > ) {
53
37
return new Reference ( this . db , this . path . concat ( paths ) ) ;
54
38
}
@@ -59,38 +43,53 @@ export default class Reference extends ReferenceBase {
59
43
}
60
44
61
45
// 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 ( ) {
63
48
const path = this . dbPath ( ) ;
64
49
const modifiers = this . query . getModifiers ( ) ;
65
50
const modifiersString = this . query . getModifiersString ( ) ;
66
51
return promisify ( 'onOnce' , FirestackDatabase ) ( path , modifiersString , modifiers , 'value' ) ;
67
52
}
68
53
69
- setAt ( val : any ) {
54
+ set ( value : any ) {
70
55
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 ) ;
73
58
}
74
59
75
- updateAt ( val : any ) {
60
+ update ( val : Object ) {
76
61
const path = this . dbPath ( ) ;
77
- const value = this . _serializeValue ( val ) ;
62
+ const value = this . _serializeObject ( val ) ;
78
63
return promisify ( 'update' , FirestackDatabase ) ( path , value ) ;
79
64
}
80
65
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 ( ) ) ;
85
68
}
86
69
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
+
88
83
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 )
91
86
. 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 ;
94
93
} ) ;
95
94
}
96
95
@@ -100,7 +99,7 @@ export default class Reference extends ReferenceBase {
100
99
const modifiersString = this . query . getModifiersString ( ) ;
101
100
this . log . debug ( 'adding reference.on' , path , modifiersString , evt ) ;
102
101
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 ) => {
104
103
this . listeners [ evt ] = subscriptions ;
105
104
} ) ;
106
105
} ) ;
@@ -111,12 +110,11 @@ export default class Reference extends ReferenceBase {
111
110
const modifiers = this . query . getModifiers ( ) ;
112
111
const modifiersString = this . query . getModifiersString ( ) ;
113
112
return this . db . storeRef ( this . uid , this ) . then ( ( ) => {
113
+ // todo use event emitter - not callbacks
114
114
return promisify ( 'onOnce' , FirestackDatabase ) ( path , modifiersString , modifiers , evt )
115
115
. 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 ) ;
120
118
return snapshot ;
121
119
} ) ;
122
120
} ) ;
@@ -128,49 +126,50 @@ export default class Reference extends ReferenceBase {
128
126
const modifiersString = this . query . getModifiersString ( ) ;
129
127
this . log . debug ( 'ref.off(): ' , path , modifiers , evt ) ;
130
128
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?
132
131
// delete this.listeners[eventName];
133
132
// this.listeners[evt] = subscriptions;
134
133
} ) ;
135
134
} ) ;
136
135
}
137
136
138
137
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 ) ) {
155
163
return {
156
- ... sum ,
157
- [ key ] : val ,
164
+ type : 'object' ,
165
+ value : this . _serializeObject ( value ) ,
158
166
} ;
159
- } , { } ) ;
160
- }
167
+ }
161
168
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
+ } ;
174
173
}
175
174
176
175
// Modifiers
@@ -242,24 +241,36 @@ export default class Reference extends ReferenceBase {
242
241
}
243
242
244
243
// attributes
245
- get fullPath ( ) : string {
244
+ toString ( ) : string {
246
245
return this . dbPath ( ) ;
247
246
}
248
247
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 ( '/' ) : '/' ) ;
252
251
253
- dbPath ( ) : string {
254
- let path = this . path ;
255
- let pathStr = ( path . length > 0 ? path . join ( '/' ) : '/' ) ;
256
252
if ( pathStr [ 0 ] !== '/' ) {
257
- pathStr = `/ ${pathStr } `;
253
+ return `/${ pathStr } ` ;
258
254
}
255
+
259
256
return pathStr ;
260
257
}
261
258
262
259
get namespace ( ) : string {
263
260
return 'firestack :dbRef ';
264
261
}
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
+ }
265
276
}
0 commit comments