@@ -2,24 +2,27 @@ import {
22 createRecordFromDatabaseSnapshot ,
33 indexForKey ,
44 DatabaseSnapshotSerializer ,
5+ VueDatabaseQueryData ,
56} from './utils'
67import {
78 noop ,
89 OperationsType ,
910 ResetOption ,
1011 TODO ,
1112 _DataSourceOptions ,
13+ _MaybeRef ,
1214 _ResolveRejectFn ,
1315} from '../shared'
1416import { ref , Ref , unref } from 'vue-demi'
15- import type { Query , DatabaseReference } from 'firebase/database'
1617import {
1718 onValue ,
1819 onChildAdded ,
1920 onChildChanged ,
2021 onChildMoved ,
2122 onChildRemoved ,
23+ get ,
2224} from 'firebase/database'
25+ import type { Query , DatabaseReference , DataSnapshot } from 'firebase/database'
2326
2427/**
2528 * Global option type when binding one database reference
@@ -68,28 +71,30 @@ export function bindAsObject(
6871 document : DatabaseReference | Query ,
6972 resolve : _ResolveRejectFn ,
7073 reject : _ResolveRejectFn ,
71- ops : OperationsType ,
72- extraOptions : _DatabaseRefOptions = DEFAULT_OPTIONS
74+ extraOptions ?: _DatabaseRefOptions
7375) {
74- const key = 'value'
7576 const options = Object . assign ( { } , DEFAULT_OPTIONS , extraOptions )
7677
77- const unsubscribe = onValue (
78- document ,
79- ( snapshot ) => {
80- const value = options . serialize ( snapshot )
81- ops . set ( target , key , value )
82- // resolve the promise
83- resolve ( value )
84- } ,
85- reject
86- )
78+ let unsubscribe = noop
79+
80+ function onValueCallback ( snapshot : DataSnapshot ) {
81+ const value = options . serialize ( snapshot )
82+ target . value = value
83+ // resolve the promise
84+ resolve ( value )
85+ }
86+
87+ if ( options . once ) {
88+ get ( document ) . then ( onValueCallback ) . catch ( reject )
89+ } else {
90+ unsubscribe = onValue ( document , onValueCallback , reject )
91+ }
8792
8893 return ( reset ?: ResetOption ) => {
8994 unsubscribe ( )
9095 if ( reset !== false ) {
9196 const value = typeof reset === 'function' ? reset ( ) : null
92- ops . set ( target , key , value )
97+ target . value = value
9398 }
9499 }
95100}
@@ -101,85 +106,112 @@ export function bindAsObject(
101106 * @returns a function to be called to stop listening for changes
102107 */
103108export function bindAsArray (
104- target : Ref < TODO > ,
109+ target : Ref < ReturnType < DatabaseSnapshotSerializer > [ ] > ,
105110 collection : DatabaseReference | Query ,
106111 resolve : _ResolveRejectFn ,
107112 reject : _ResolveRejectFn ,
108- ops : OperationsType ,
109- extraOptions : _DatabaseRefOptions = DEFAULT_OPTIONS
113+ extraOptions ?: _DatabaseRefOptions
110114) {
111115 const options = Object . assign ( { } , DEFAULT_OPTIONS , extraOptions )
112- const key = 'value'
113-
114- if ( ! options . wait ) ops . set ( target , key , [ ] )
115- let arrayRef = ref ( options . wait ? [ ] : target [ key ] )
116-
117- const removeChildAddedListener = onChildAdded (
118- collection ,
119- ( snapshot , prevKey ) => {
120- const array = unref ( arrayRef )
121- const index = prevKey ? indexForKey ( array , prevKey ) + 1 : 0
122- ops . add ( array , index , options . serialize ( snapshot ) )
123- } ,
124- reject
125- )
126-
127- const removeChildRemovedListener = onChildRemoved (
128- collection ,
129-
130- ( snapshot ) => {
131- const array = unref ( arrayRef )
132- ops . remove ( array , indexForKey ( array , snapshot . key ) )
133- } ,
134- reject
135- )
136-
137- const removeChildChangedListener = onChildChanged (
138- collection ,
139- ( snapshot ) => {
140- const array = unref ( arrayRef )
141- ops . set (
142- array ,
143- indexForKey ( array , snapshot . key ) ,
144- options . serialize ( snapshot )
145- )
146- } ,
147- reject
148- )
149-
150- const removeChildMovedListener = onChildMoved (
151- collection ,
152- ( snapshot , prevKey ) => {
153- const array = unref ( arrayRef )
154- const index = indexForKey ( array , snapshot . key )
155- const oldRecord = ops . remove ( array , index ) [ 0 ]
156- const newIndex = prevKey ? indexForKey ( array , prevKey ) + 1 : 0
157- ops . add ( array , newIndex , oldRecord )
158- } ,
159- reject
160- )
161116
117+ let arrayRef : _MaybeRef < ReturnType < DatabaseSnapshotSerializer > [ ] > =
118+ options . wait ? [ ] : target
119+ // by default we wait, if not, set the value to an empty array so it can be populated correctly
120+ if ( ! options . wait ) {
121+ target . value = [ ]
122+ }
123+
124+ // setup the callbacks to noop for options.once
125+ let removeChildAddedListener = noop
126+ let removeChildChangedListener = noop
127+ let removeChildRemovedListener = noop
128+ let removeChildMovedListener = noop
162129 // in case the removeValueListener() is called before onValue returns
163130 let removeValueListener = noop
164- removeValueListener = onValue (
165- collection ,
166- ( data ) => {
167- const array = unref ( arrayRef )
168- if ( options . wait ) ops . set ( target , key , array )
169- resolve ( data )
170- removeValueListener ( )
171- } ,
172- reject
173- )
131+
132+ if ( options . once ) {
133+ get ( collection )
134+ . then ( ( data ) => {
135+ const array : ReturnType < DatabaseSnapshotSerializer > [ ] = [ ]
136+ data . forEach ( ( snapshot ) => {
137+ array . push ( options . serialize ( snapshot ) )
138+ } )
139+ resolve ( ( target . value = array ) )
140+ } )
141+ . catch ( reject )
142+ } else {
143+ removeChildAddedListener = onChildAdded (
144+ collection ,
145+ ( snapshot , prevKey ) => {
146+ const array = unref ( arrayRef )
147+ const index = prevKey ? indexForKey ( array , prevKey ) + 1 : 0
148+ array . splice ( index , 0 , options . serialize ( snapshot ) )
149+ } ,
150+ reject
151+ )
152+
153+ removeChildRemovedListener = onChildRemoved (
154+ collection ,
155+
156+ ( snapshot ) => {
157+ const array = unref ( arrayRef )
158+ array . splice ( indexForKey ( array , snapshot . key ) , 1 )
159+ } ,
160+ reject
161+ )
162+
163+ removeChildChangedListener = onChildChanged (
164+ collection ,
165+ ( snapshot ) => {
166+ const array = unref ( arrayRef )
167+ array . splice (
168+ indexForKey ( array , snapshot . key ) ,
169+ 1 ,
170+ options . serialize ( snapshot )
171+ )
172+ } ,
173+ reject
174+ )
175+
176+ removeChildMovedListener = onChildMoved (
177+ collection ,
178+ ( snapshot , prevKey ) => {
179+ const array = unref ( arrayRef )
180+ const index = indexForKey ( array , snapshot . key )
181+ const oldRecord = array . splice ( index , 1 ) [ 0 ]
182+ const newIndex = prevKey ? indexForKey ( array , prevKey ) + 1 : 0
183+ array . splice ( newIndex , 0 , oldRecord )
184+ } ,
185+ reject
186+ )
187+
188+ // we use this to know when the initial data has been loaded
189+ removeValueListener = onValue (
190+ collection ,
191+ ( ) => {
192+ const array = unref ( arrayRef )
193+ if ( options . wait ) {
194+ target . value = array
195+ // switch to the target so all changes happen into the target
196+ arrayRef = target
197+ }
198+ resolve ( array )
199+ removeValueListener ( )
200+ } ,
201+ reject
202+ )
203+ }
174204
175205 return ( reset ?: ResetOption ) => {
206+ removeValueListener ( )
176207 removeChildAddedListener ( )
177208 removeChildRemovedListener ( )
178209 removeChildChangedListener ( )
179210 removeChildMovedListener ( )
180211 if ( reset !== false ) {
181212 const value = typeof reset === 'function' ? reset ( ) : [ ]
182- ops . set ( target , key , value )
213+ // we trust the user to return an array
214+ target . value = value as any
183215 }
184216 }
185217}
0 commit comments