Skip to content

Commit 5f63a3c

Browse files
committed
feat(bind): automatically bind refs on documents
1 parent 3fa5d8a commit 5f63a3c

File tree

4 files changed

+78
-6
lines changed

4 files changed

+78
-6
lines changed

src/index.js

+48-3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,46 @@ function bindCollection ({
3838
}, reject)
3939
}
4040

41+
function updateDataFromDocumentSnapshot ({ snapshot, obj, key, subs, depth = 0 }) {
42+
// TODO extract refs
43+
const [data, refs] = extractRefs(snapshot)
44+
obj[key] = data
45+
// TODO check if no ref is missing
46+
Object.keys(refs).forEach(refKey => {
47+
// check if already bound to the same ref -> skip
48+
const sub = subs[refKey]
49+
const ref = refs[refKey]
50+
if (sub && sub.path !== ref.path) {
51+
sub.unbind()
52+
}
53+
// maybe wrap the unbind function to call unbind on every child
54+
subs[refKey] = {
55+
unbind: subscribeToDocument({
56+
ref,
57+
obj: obj[key],
58+
key: refKey,
59+
depth: depth + 1
60+
}),
61+
path: ref.path
62+
}
63+
// unbind currently bound ref
64+
// bind ref
65+
// save unbind callback
66+
// probably save key or something as well
67+
})
68+
}
69+
70+
function subscribeToDocument ({ ref, obj, key, depth }) {
71+
// TODO max depth param, default to 1?
72+
if (depth > 3) throw new Error('more than 5 nested refs')
73+
const subs = Object.create(null)
74+
return ref.onSnapshot(doc => {
75+
if (doc.exists) {
76+
updateDataFromDocumentSnapshot({ snapshot: createSnapshot(doc), obj, key, subs, depth })
77+
}
78+
})
79+
}
80+
4181
function bindDocument ({
4282
vm,
4383
key,
@@ -50,12 +90,17 @@ function bindDocument ({
5090
// const boundRefs = Object.create(null)
5191

5292
let ready
93+
const subs = Object.create(null)
5394
return document.onSnapshot(doc => {
54-
// TODO extract refs
5595
if (doc.exists) {
56-
const [data] = extractRefs(createSnapshot(doc))
57-
vm[key] = data
96+
updateDataFromDocumentSnapshot({
97+
snapshot: createSnapshot(doc),
98+
obj: vm,
99+
key,
100+
subs
101+
})
58102
}
103+
// TODO should resolve be called when all refs are bound?
59104
if (!ready) {
60105
ready = true
61106
resolve(vm[key])

src/utils.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function extractRefs (doc) {
99
return Object.keys(doc).reduce((tot, key) => {
1010
const ref = doc[key]
1111
if (typeof ref.isEqual === 'function') {
12-
tot[0][key] = null
12+
tot[0][key] = ref.path
1313
// TODO handle subpathes?
1414
tot[1][key] = ref
1515
} else {

test/bind.spec.js

+18
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Vuefire from '../src'
44
import {
55
db,
66
tick,
7+
delay,
78
Vue
89
} from './helpers'
910

@@ -79,3 +80,20 @@ test('unbinds previously bound refs', async t => {
7980
t.is(vm.$firestoreRefs.item, doc2)
8081
t.deepEqual(vm.item, { bar: 'bar' })
8182
})
83+
84+
test('binds refs on documents', async t => {
85+
const { vm, document, collection } = t.context
86+
// create an empty doc and update using the ref instead of plain data
87+
const a = collection.doc()
88+
a.update({ foo: 'foo' })
89+
await document.update({ ref: a })
90+
await vm.$bind('item', document)
91+
92+
// XXX dirty hack until $bind resolves when all refs are bound
93+
// NOTE should add option for it waitForRefs: true (by default)
94+
await delay(5)
95+
96+
t.deepEqual(vm.item, {
97+
ref: { foo: 'foo' }
98+
})
99+
})

test/helpers/mock.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,19 @@ class DocumentReference {
5252
}
5353
}
5454

55+
get path () {
56+
return `${this.collection.name}/${this.id.v}`
57+
}
58+
5559
async delete () {
5660
this.exists = false
5761
return this.collection._remove(this.id)
5862
}
5963

64+
isEqual (ref) {
65+
return this.id.v === ref.id.v
66+
}
67+
6068
async update (data) {
6169
Object.assign(this.data, data)
6270
this.exists = true
@@ -66,8 +74,9 @@ class DocumentReference {
6674
}
6775

6876
class CollectionReference {
69-
constructor () {
77+
constructor (name) {
7078
this.data = {}
79+
this.name = name
7180
this.cb = this.onError = noop
7281
}
7382

@@ -154,6 +163,6 @@ export const db = {
154163
collection (name) {
155164
// create a collection if no name provided
156165
name = name || `random__${this.n++}`
157-
return (db[name] = db[name] || new CollectionReference())
166+
return (db[name] = db[name] || new CollectionReference(name))
158167
}
159168
}

0 commit comments

Comments
 (0)