Skip to content

Commit 1ccbf0d

Browse files
committed
refactor: working version firestore
1 parent a1e6aee commit 1ccbf0d

File tree

4 files changed

+92
-47
lines changed

4 files changed

+92
-47
lines changed

src/core.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export { walkSet, OperationsType, ResetOption } from './shared'
2-
export * from './rtdb/index'
3-
export * from './firestore/index'
2+
export * from './rtdb'
3+
export * from './firestore'

src/firestore/index.ts

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createSnapshot, extractRefs, FirestoreSerializer } from './utils'
22
import { walkGet, callOnceWithArg, OperationsType } from '../shared'
33
import { firestore } from 'firebase'
4+
import { ref, Ref, unref } from 'vue'
45

56
export interface FirestoreOptions {
67
maxRefDepth?: number
@@ -34,7 +35,7 @@ function unsubscribeAll(subs: Record<string, FirestoreSubscription>) {
3435

3536
function updateDataFromDocumentSnapshot(
3637
options: Required<FirestoreOptions>,
37-
target: CommonBindOptionsParameter['vm'],
38+
target: CommonBindOptionsParameter['target'],
3839
path: string,
3940
snapshot: firestore.DocumentSnapshot,
4041
subs: Record<string, FirestoreSubscription>,
@@ -52,7 +53,7 @@ function updateDataFromDocumentSnapshot(
5253
}
5354

5455
interface SubscribeToDocumentParamater {
55-
target: CommonBindOptionsParameter['vm']
56+
target: CommonBindOptionsParameter['target']
5657
path: string
5758
depth: number
5859
resolve: () => void
@@ -104,7 +105,7 @@ function subscribeToDocument(
104105
// updateDataFromDocumentSnapshot which may call subscribeToRefs as well
105106
function subscribeToRefs(
106107
options: Required<FirestoreOptions>,
107-
target: CommonBindOptionsParameter['vm'],
108+
target: CommonBindOptionsParameter['target'],
108109
path: string | number,
109110
subs: Record<string, FirestoreSubscription>,
110111
refs: Record<string, firestore.DocumentReference>,
@@ -165,27 +166,29 @@ function subscribeToRefs(
165166
}
166167

167168
interface CommonBindOptionsParameter {
168-
vm: Record<string, any>
169-
key: string
169+
// vm: Record<string, any>
170+
target: Ref<any>
171+
// key: string
170172
// Override this property in necessary functions
171173
resolve: (value: any) => void
172174
reject: (error: any) => void
173175
ops: OperationsType
174176
}
175177

176-
interface BindCollectionParamater extends CommonBindOptionsParameter {
178+
interface BindCollectionParameter extends CommonBindOptionsParameter {
177179
collection: firestore.CollectionReference | firestore.Query
178180
}
179181

180182
// TODO: refactor without using an object to improve size like the other functions
181183

182184
export function bindCollection(
183-
{ vm, key, collection, ops, resolve, reject }: BindCollectionParamater,
185+
{ target, collection, ops, resolve, reject }: BindCollectionParameter,
184186
extraOptions: FirestoreOptions = DEFAULT_OPTIONS
185187
) {
186188
const options = Object.assign({}, DEFAULT_OPTIONS, extraOptions) // fill default values
187-
// TODO support pathes? nested.obj.list (walkSet)
188-
const array = options.wait ? [] : ops.set(vm, key, [])
189+
const key = 'value'
190+
if (!options.wait) ops.set(target, key, [])
191+
let arrayRef = ref(options.wait ? [] : target[key])
189192
const originalResolve = resolve
190193
let isResolved: boolean
191194

@@ -198,11 +201,11 @@ export function bindCollection(
198201
arraySubs.splice(newIndex, 0, Object.create(null))
199202
const subs = arraySubs[newIndex]
200203
const [data, refs] = extractRefs(options.serialize(doc), undefined, subs)
201-
ops.add(array, newIndex, data)
204+
ops.add(unref(arrayRef), newIndex, data)
202205
subscribeToRefs(
203206
options,
204-
array,
205-
newIndex,
207+
arrayRef,
208+
`${key}.${newIndex}`,
206209
subs,
207210
refs,
208211
ops,
@@ -211,6 +214,7 @@ export function bindCollection(
211214
)
212215
},
213216
modified: ({ oldIndex, newIndex, doc }: firestore.DocumentChange) => {
217+
const array = unref(arrayRef)
214218
const subs = arraySubs[oldIndex]
215219
const oldData = array[oldIndex]
216220
const [data, refs] = extractRefs(options.serialize(doc), oldData, subs)
@@ -219,9 +223,19 @@ export function bindCollection(
219223
arraySubs.splice(newIndex, 0, subs)
220224
ops.remove(array, oldIndex)
221225
ops.add(array, newIndex, data)
222-
subscribeToRefs(options, array, newIndex, subs, refs, ops, 0, resolve)
226+
subscribeToRefs(
227+
options,
228+
arrayRef,
229+
`${key}.${newIndex}`,
230+
subs,
231+
refs,
232+
ops,
233+
0,
234+
resolve
235+
)
223236
},
224237
removed: ({ oldIndex }: firestore.DocumentChange) => {
238+
const array = unref(arrayRef)
225239
ops.remove(array, oldIndex)
226240
unsubscribeAll(arraySubs.splice(oldIndex, 1)[0])
227241
},
@@ -255,8 +269,12 @@ export function bindCollection(
255269
if (id in validDocs) {
256270
if (++count >= expectedItems) {
257271
// if wait is true, finally set the array
258-
if (options.wait) ops.set(vm, key, array)
259-
originalResolve(vm[key])
272+
if (options.wait) {
273+
ops.set(target, key, unref(arrayRef))
274+
// use the proxy object
275+
// arrayRef = target.value
276+
}
277+
originalResolve(unref(arrayRef))
260278
// reset resolve to noop
261279
resolve = () => {}
262280
}
@@ -271,22 +289,26 @@ export function bindCollection(
271289
// since this can only happen once, there is no need to guard against it
272290
// being called multiple times
273291
if (!docChanges.length) {
274-
if (options.wait) ops.set(vm, key, array)
275-
resolve(array)
292+
if (options.wait) {
293+
ops.set(target, key, unref(arrayRef))
294+
// use the proxy object
295+
// arrayRef = target.value
296+
}
297+
resolve(unref(arrayRef))
276298
}
277299
}, reject)
278300

279301
return (reset?: FirestoreOptions['reset']) => {
280302
unbind()
281303
if (reset !== false) {
282304
const value = typeof reset === 'function' ? reset() : []
283-
ops.set(vm, key, value)
305+
ops.set(target, key, value)
284306
}
285307
arraySubs.forEach(unsubscribeAll)
286308
}
287309
}
288310

289-
interface BindDocumentParamater extends CommonBindOptionsParameter {
311+
interface BindDocumentParameter extends CommonBindOptionsParameter {
290312
document: firestore.DocumentReference
291313
}
292314

@@ -296,22 +318,23 @@ interface BindDocumentParamater extends CommonBindOptionsParameter {
296318
* @param extraOptions
297319
*/
298320
export function bindDocument(
299-
{ vm, key, document, resolve, reject, ops }: BindDocumentParamater,
321+
{ target, document, resolve, reject, ops }: BindDocumentParameter,
300322
extraOptions: FirestoreOptions = DEFAULT_OPTIONS
301323
) {
302324
const options = Object.assign({}, DEFAULT_OPTIONS, extraOptions) // fill default values
325+
const key = 'value'
303326
// TODO: warning check if key exists?
304327
// const boundRefs = Object.create(null)
305328

306329
const subs = Object.create(null)
307330
// bind here the function so it can be resolved anywhere
308331
// this is specially useful for refs
309-
resolve = callOnceWithArg(resolve, () => walkGet(vm, key))
332+
resolve = callOnceWithArg(resolve, () => walkGet(target, key))
310333
const unbind = document.onSnapshot((snapshot) => {
311334
if (snapshot.exists) {
312335
updateDataFromDocumentSnapshot(
313336
options,
314-
vm,
337+
target,
315338
key,
316339
snapshot,
317340
subs,
@@ -320,7 +343,7 @@ export function bindDocument(
320343
resolve
321344
)
322345
} else {
323-
ops.set(vm, key, null)
346+
ops.set(target, key, null)
324347
resolve(null)
325348
}
326349
}, reject)
@@ -329,7 +352,7 @@ export function bindDocument(
329352
unbind()
330353
if (reset !== false) {
331354
const value = typeof reset === 'function' ? reset() : null
332-
ops.set(vm, key, value)
355+
ops.set(target, key, value)
333356
}
334357
unsubscribeAll(subs)
335358
}

src/vuefire/firestore.ts

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ import {
77
OperationsType,
88
} from '../core'
99
import { firestore } from 'firebase'
10-
import { ComponentPublicInstance, onBeforeUnmount, Plugin, Ref } from 'vue'
10+
import {
11+
ComponentPublicInstance,
12+
getCurrentInstance,
13+
onBeforeUnmount,
14+
Plugin,
15+
Ref,
16+
toRef,
17+
} from 'vue'
1118

1219
export const ops: OperationsType = {
1320
set: (target, key, value) => walkSet(target, key, value),
@@ -21,22 +28,20 @@ const firestoreUnbinds = new WeakMap<
2128
>()
2229

2330
function internalBind(
24-
vm: Record<string, any>,
25-
key: string,
31+
target: Ref<any>,
2632
ref:
2733
| firestore.CollectionReference
2834
| firestore.Query
2935
| firestore.DocumentReference,
3036
ops: OperationsType,
31-
options: FirestoreOptions
37+
options?: FirestoreOptions
3238
) {
3339
return new Promise((resolve, reject) => {
3440
let unbind
3541
if ('where' in ref) {
3642
unbind = bindCollection(
3743
{
38-
vm,
39-
key,
44+
target,
4045
ops,
4146
collection: ref,
4247
resolve,
@@ -47,8 +52,7 @@ function internalBind(
4752
} else {
4853
unbind = bindDocument(
4954
{
50-
vm,
51-
key,
55+
target,
5256
ops,
5357
document: ref,
5458
resolve,
@@ -57,16 +61,19 @@ function internalBind(
5761
options
5862
)
5963
}
60-
if (!firestoreUnbinds.has(vm)) {
61-
firestoreUnbinds.set(vm, {})
64+
if (!firestoreUnbinds.has(target)) {
65+
firestoreUnbinds.set(target, {})
6266
}
63-
const unbinds = firestoreUnbinds.get(vm)!
67+
const unbinds = firestoreUnbinds.get(target)!
68+
// TODO: remove and refactor the firestoreUnbinds
69+
const key = 'value'
6470
unbinds[key] = unbind
6571
})
6672
}
6773

6874
export function internalUnbind(
6975
target: object,
76+
// TODO: can go during the refactor
7077
key: string,
7178
reset?: FirestoreOptions['reset']
7279
) {
@@ -156,8 +163,9 @@ export const firestorePlugin: Plugin = function firestorePlugin(
156163
app,
157164
pluginOptions: PluginOptions = defaultOptions
158165
) {
159-
const strategies = app.config.optionMergeStrategies
160-
strategies.firestore = strategies.provide
166+
// const strategies = app.config.optionMergeStrategies
167+
// TODO: implement
168+
// strategies.firestore =
161169

162170
const globalOptions = Object.assign({}, defaultOptions, pluginOptions)
163171
const { bindName, unbindName } = globalOptions
@@ -203,14 +211,19 @@ export const firestorePlugin: Plugin = function firestorePlugin(
203211
// : options.reset
204212
// )
205213
}
206-
const promise = internalBind(this, key, ref, ops, options)
214+
const promise = internalBind(
215+
toRef(this.$data as any, key),
216+
ref,
217+
ops,
218+
options
219+
)
207220
// @ts-ignore we are allowed to write it
208221
this.$firestoreRefs[key] = ref
209222
return promise
210223
}
211224

212225
app.mixin({
213-
beforeMount(this: ComponentPublicInstance) {
226+
beforeCreate(this: ComponentPublicInstance) {
214227
this.$firestoreRefs = Object.create(null)
215228
},
216229
created(this: ComponentPublicInstance) {
@@ -249,13 +262,21 @@ export function bind(
249262
| firestore.CollectionReference
250263
| firestore.Query
251264
| firestore.DocumentReference,
252-
options: FirestoreOptions
265+
options?: FirestoreOptions
253266
) {
254-
const promise = internalBind(target, 'value', ref, ops, options)
267+
const promise = internalBind(target, ref, ops, options)
255268

256-
onBeforeUnmount(() => {
257-
unbind(target)
258-
})
269+
// TODO: SSR serialize the values for Nuxt to expose them later and use them
270+
// as initial values while specifying a wait: true to only swap objects once
271+
// Firebase has done its initial sync. Also, on server, you don't need to
272+
// create sync, you can read only once the whole thing so maybe internalBind
273+
// should take an option like once: true to not setting up any listener
274+
275+
if (getCurrentInstance()) {
276+
onBeforeUnmount(() => {
277+
unbind(target, options && options.reset)
278+
})
279+
}
259280

260281
return promise
261282
}

src/vuefire/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
export * from './rtdb'
1+
// TODO: add binds
2+
// export { rtdbPlugin } from './rtdb'
23
export {
34
firestorePlugin,
45
bind as firestoreBind,

0 commit comments

Comments
 (0)