Skip to content

Commit fe78629

Browse files
committed
fix(firestore): apply converter to nested refs
Fix #1263
1 parent b179d22 commit fe78629

File tree

5 files changed

+63
-25
lines changed

5 files changed

+63
-25
lines changed

src/firestore/bind.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export interface FirestoreRefOptions extends _DataSourceOptions {
5555
* Type of the global options for firestore refs. Some values cannot be `undefined`.
5656
* @internal
5757
*/
58-
interface _FirestoreRefOptionsWithDefaults extends FirestoreRefOptions {
58+
export interface _FirestoreRefOptionsWithDefaults extends FirestoreRefOptions {
5959
/**
6060
* @defaultValue `false`
6161
*/
@@ -121,11 +121,12 @@ function updateDataFromDocumentSnapshot<T>(
121121
reject: _ResolveRejectFn
122122
) {
123123
const [data, refs] = extractRefs(
124-
// @ts-expect-error: FIXME: use better types
125124
// Pass snapshot options
125+
// @ts-expect-error: FIXME: use better types
126126
snapshot.data(options.snapshotOptions),
127127
walkGet(target, path),
128-
subs
128+
subs,
129+
options
129130
)
130131
ops.set(target, path, data)
131132
subscribeToRefs(
@@ -319,7 +320,8 @@ export function bindCollection<T = unknown>(
319320
// @ts-expect-error: FIXME: wrong cast, needs better types
320321
doc.data(snapshotOptions),
321322
undefined,
322-
subs
323+
subs,
324+
options
323325
)
324326
ops.add(unref(arrayRef), newIndex, data)
325327
subscribeToRefs(
@@ -342,7 +344,8 @@ export function bindCollection<T = unknown>(
342344
// @ts-expect-error: FIXME: Better types
343345
doc.data(snapshotOptions),
344346
oldData,
345-
subs
347+
subs,
348+
options
346349
)
347350
// only move things around after extracting refs
348351
// only move things around after extracting refs

src/firestore/useFirestoreRef.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
CollectionReference,
55
FirestoreError,
66
DocumentData,
7+
FirestoreDataConverter,
78
} from 'firebase/firestore'
89
import {
910
unref,
@@ -38,13 +39,14 @@ import {
3839
bindDocument,
3940
firestoreOptionsDefaults,
4041
FirestoreRefOptions,
42+
_FirestoreRefOptionsWithDefaults,
4143
} from './bind'
4244

4345
export interface _UseFirestoreRefOptions extends FirestoreRefOptions {
4446
/**
4547
* @deprecated: use `.withConverter()` instead
4648
*/
47-
converter?: any
49+
converter?: FirestoreDataConverter<unknown>
4850
}
4951

5052
/**

src/firestore/utils.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
} from 'firebase/firestore'
1010
import { isObject, isDocumentRef, TODO, isPOJO } from '../shared'
1111
import { VueFirestoreDocumentData } from '.'
12+
import type { _UseFirestoreRefOptions } from './useFirestoreRef'
13+
import { _FirestoreRefOptionsWithDefaults } from './bind'
1214

1315
export type FirestoreReference = Query | DocumentReference | CollectionReference
1416

@@ -40,7 +42,8 @@ export function extractRefs(
4042
// TODO: should be unknown instead of DocumentData
4143
doc: DocumentData,
4244
oldDoc: DocumentData | void,
43-
subs: Record<string, { path: string; data: () => DocumentData | null }>
45+
subs: Record<string, { path: string; data: () => DocumentData | null }>,
46+
options: _FirestoreRefOptionsWithDefaults
4447
): [DocumentData, Record<string, DocumentReference>] {
4548
if (!isPOJO(doc)) return [doc, {}]
4649

@@ -98,7 +101,11 @@ export function extractRefs(
98101
// https://github.com/vuejs/vuefire/pull/1223
99102
refSubKey in subs ? oldDoc[key] : ref.path
100103
// TODO: handle subpathes?
101-
refs[refSubKey] = ref
104+
refs[refSubKey] = ref.converter
105+
? ref
106+
: ref.withConverter(
107+
options.converter as FirestoreDataConverter<DocumentData>
108+
)
102109
} else if (Array.isArray(ref)) {
103110
data[key] = Array(ref.length)
104111
// fill existing refs into data but leave the rest empty

tests/firestore/refs-in-documents.spec.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
} from 'firebase/firestore'
88
import { setupFirestoreRefs, sleep } from '../utils'
99
import { unref } from 'vue'
10-
import { _RefFirestore } from '../../src/firestore'
10+
import { VueFirestoreDocumentData, _RefFirestore } from '../../src/firestore'
1111
import {
1212
UseDocumentOptions,
1313
VueFirestoreQueryData,
@@ -26,7 +26,7 @@ describe('Firestore refs in documents', async () => {
2626
options?: UseDocumentOptions
2727
ref?: _MaybeRef<DocumentReference<T>>
2828
} = {}) {
29-
let data!: _RefFirestore<VueFirestoreQueryData<T>>
29+
let data!: _RefFirestore<VueFirestoreDocumentData<T>>
3030

3131
const wrapper = mount({
3232
template: 'no',
@@ -116,6 +116,18 @@ describe('Firestore refs in documents', async () => {
116116
})
117117
})
118118

119+
it('refs are also serialized with the converter', async () => {
120+
const docRef = await addDoc(listOfRefs, { a: aRef })
121+
const { data, pending, promise } = factory({ ref: docRef })
122+
123+
await promise.value
124+
// NOTE: why does toEqual fail here?
125+
expect(data.value).toMatchObject({
126+
id: docRef.id,
127+
a: { name: 'a', id: aRef.id },
128+
})
129+
})
130+
119131
it('unsubscribes from a ref if it is replaced', async () => {
120132
const docRef = await addDoc(listOfRefs, { a: aRef })
121133
const { data, pending, promise } = factory({ ref: docRef })

tests/firestore/utils.spec.ts

+29-15
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
extractRefs,
55
firestoreDefaultConverter,
66
} from '../../src/firestore/utils'
7+
import { globalFirestoreOptions } from '../../src'
78
import { setupFirestoreRefs } from '../utils'
89

910
describe('Firestore and Database utils', () => {
@@ -56,11 +57,12 @@ describe('Firestore and Database utils', () => {
5657
ref: docRef,
5758
},
5859
undefined,
59-
{}
60+
{},
61+
globalFirestoreOptions
6062
)
6163
expect(noRefsDoc.ref).toBe(docRef.path)
6264
expect(refs).toEqual({
63-
ref: docRef,
65+
ref: expect.objectContaining({ id: docRef.id }),
6466
})
6567
})
6668

@@ -72,7 +74,8 @@ describe('Firestore and Database utils', () => {
7274
bar: d,
7375
},
7476
undefined,
75-
{}
77+
{},
78+
globalFirestoreOptions
7679
)
7780
expect(doc.foo).toBe(1)
7881
expect(doc.bar).toBe(d)
@@ -87,7 +90,8 @@ describe('Firestore and Database utils', () => {
8790
bar: d,
8891
},
8992
undefined,
90-
{}
93+
{},
94+
globalFirestoreOptions
9195
)
9296
expect(doc.foo).toBe(1)
9397
expect(doc.bar).toBe(d)
@@ -102,7 +106,8 @@ describe('Firestore and Database utils', () => {
102106
bar: d,
103107
},
104108
undefined,
105-
{}
109+
{},
110+
globalFirestoreOptions
106111
)
107112
expect(doc.foo).toBe(1)
108113
expect(doc.bar).toBe(d)
@@ -117,11 +122,12 @@ describe('Firestore and Database utils', () => {
117122
},
118123
},
119124
undefined,
120-
{}
125+
{},
126+
globalFirestoreOptions
121127
)
122128
expect(noRefsDoc.obj.ref).toBe(docRef.path)
123129
expect(refs).toEqual({
124-
'obj.ref': docRef,
130+
'obj.ref': expect.objectContaining({ id: docRef.id }),
125131
})
126132
})
127133

@@ -134,7 +140,8 @@ describe('Firestore and Database utils', () => {
134140
},
135141
},
136142
undefined,
137-
{}
143+
{},
144+
globalFirestoreOptions
138145
)
139146
expect(noRefsDoc).toEqual({
140147
a: null,
@@ -155,11 +162,12 @@ describe('Firestore and Database utils', () => {
155162
},
156163
},
157164
undefined,
158-
{}
165+
{},
166+
globalFirestoreOptions
159167
)
160168
expect(noRefsDoc.obj.nested.ref).toBe(docRef.path)
161169
expect(refs).toEqual({
162-
'obj.nested.ref': docRef,
170+
'obj.nested.ref': expect.objectContaining({ id: docRef.id }),
163171
})
164172
})
165173

@@ -170,15 +178,16 @@ describe('Firestore and Database utils', () => {
170178
arr: [docRef, docRef2, docRef],
171179
},
172180
undefined,
173-
{}
181+
{},
182+
globalFirestoreOptions
174183
)
175184
expect(noRefsDoc.arr[0]).toBe(docRef.path)
176185
expect(noRefsDoc.arr[1]).toBe(docRef2.path)
177186
expect(noRefsDoc.arr[2]).toBe(docRef.path)
178187
expect(refs).toEqual({
179-
'arr.0': docRef,
180-
'arr.1': docRef2,
181-
'arr.2': docRef,
188+
'arr.0': expect.objectContaining({ id: docRef.id }),
189+
'arr.1': expect.objectContaining({ id: docRef2.id }),
190+
'arr.2': expect.objectContaining({ id: docRef.id }),
182191
})
183192
})
184193

@@ -188,7 +197,12 @@ describe('Firestore and Database utils', () => {
188197
value: 'foo',
189198
enumerable: false,
190199
})
191-
const [noRefsDoc, refs] = extractRefs(obj, undefined, {})
200+
const [noRefsDoc, refs] = extractRefs(
201+
obj,
202+
undefined,
203+
{},
204+
globalFirestoreOptions
205+
)
192206
expect(Object.getOwnPropertyDescriptor(noRefsDoc, 'bar')).toEqual({
193207
value: 'foo',
194208
enumerable: false,

0 commit comments

Comments
 (0)