Skip to content

Commit 0c0b1e4

Browse files
committed
feat(database): rename .key property to id to match Firestore
BREAKING CHANGE: the default `serialize()` option adds a non enumerable property named `id` that correspond to the DatabaseRef's `key`. It was previously added as a non-enumerable key named `.key`. if you want to keep the old behavior you can pass a global `serialize()` to the `rtdbPlugin` options: ```ts import { createApp } from 'vue' import { rtdbPlugin } from 'vuefire' const app = createApp() app.use(rtdbPlugin, { serialize }) ```
1 parent 5a73aeb commit 0c0b1e4

File tree

4 files changed

+62
-45
lines changed

4 files changed

+62
-45
lines changed

src/database/index.ts

+5-21
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ import {
1919
} from '../shared'
2020
import { rtdbUnbinds } from './optionsApi'
2121
import { bindAsArray, bindAsObject, _DatabaseRefOptions } from './subscribe'
22+
import {
23+
VueDatabaseDocumentData,
24+
VueDatabaseQueryData,
25+
_RefDatabase,
26+
} from './utils'
2227

2328
export { databasePlugin } from './optionsApi'
2429

@@ -180,24 +185,3 @@ export function useObject<T = unknown>(
180185

181186
export const unbind = (target: Ref, reset?: _DatabaseRefOptions['reset']) =>
182187
internalUnbind('', rtdbUnbinds.get(target), reset)
183-
184-
export interface _RefDatabase<T> extends _RefWithState<T, Error> {}
185-
186-
/**
187-
* Type used by default by the `serialize` option.
188-
*/
189-
export type VueDatabaseDocumentData<T = unknown> =
190-
| null
191-
| (T & {
192-
/**
193-
* id of the document
194-
*/
195-
readonly id: string
196-
})
197-
198-
/**
199-
* Same as VueDatabaseDocumentData but for a query.
200-
*/
201-
export type VueDatabaseQueryData<T = unknown> = Array<
202-
Exclude<VueDatabaseDocumentData<T>, null>
203-
>

src/database/utils.ts

+38-15
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
import type { DataSnapshot } from 'firebase/database'
2-
import { isObject } from '../shared'
2+
import { isObject, _RefWithState } from '../shared'
33

44
/**
55
* Convert firebase Database snapshot into a bindable data record.
66
*
77
* @param snapshot
88
* @return
99
*/
10-
export function createRecordFromDatabaseSnapshot(snapshot: DataSnapshot): any {
11-
const value = snapshot.val()
12-
const res = isObject(value)
10+
export function createRecordFromDatabaseSnapshot(
11+
snapshot: DataSnapshot
12+
): VueDatabaseDocumentData<unknown> {
13+
const value: unknown = snapshot.val()
14+
const res: unknown = isObject(value)
1315
? value
14-
: Object.defineProperty({}, '.value', { value })
15-
// if (isObject(value)) {
16-
// res = value
17-
// } else {
18-
// res = {}
19-
// Object.defineProperty(res, '.value', { value })
20-
// }
21-
22-
Object.defineProperty(res, '.key', { value: snapshot.key })
16+
: (Object.defineProperty({}, '.value', { value }) as unknown)
17+
// TODO: Transform the return type to be T directly (value different from object)
18+
// since we have a ref, we can set any value now
19+
20+
Object.defineProperty(res, 'id', { value: snapshot.key })
21+
// @ts-expect-error: id added just above
2322
return res
2423
}
2524

@@ -32,10 +31,34 @@ export type DatabaseSnapshotSerializer = typeof createRecordFromDatabaseSnapshot
3231
* @param key
3332
* @return the index where the key was found
3433
*/
35-
export function indexForKey(array: any[], key: string | null | number): number {
34+
export function indexForKey(
35+
array: VueDatabaseQueryData,
36+
key: string | null | number
37+
): number {
3638
for (let i = 0; i < array.length; i++) {
37-
if (array[i]['.key'] === key) return i
39+
if (array[i].id === key) return i
3840
}
3941

4042
return -1
4143
}
44+
45+
export interface _RefDatabase<T> extends _RefWithState<T, Error> {}
46+
47+
/**
48+
* Type used by default by the `serialize` option.
49+
*/
50+
export type VueDatabaseDocumentData<T = unknown> =
51+
| null
52+
| (T & {
53+
/**
54+
* id of the document
55+
*/
56+
readonly id: string
57+
})
58+
59+
/**
60+
* Same as VueDatabaseDocumentData but for a query.
61+
*/
62+
export type VueDatabaseQueryData<T = unknown> = Array<
63+
Exclude<VueDatabaseDocumentData<T>, null>
64+
>

src/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ export { useList, useObject } from './database'
22
export type {
33
UseListOptions,
44
UseObjectOptions,
5-
_RefDatabase,
65
UseDatabaseRefOptions,
6+
} from './database'
7+
export type {
8+
DatabaseSnapshotSerializer,
9+
_RefDatabase,
710
VueDatabaseDocumentData,
811
VueDatabaseQueryData,
9-
} from './database'
12+
} from './database/utils'
1013

1114
export { databasePlugin } from './database/optionsApi'
1215
export type { DatabasePluginOptions } from './database/optionsApi'

tests/database/options.spec.ts

+14-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { defineComponent } from 'vue'
22
import { mount } from '@vue/test-utils'
33
import { describe, expect, it, vi } from 'vitest'
4-
import { databasePlugin, DatabasePluginOptions } from '../../src'
4+
import {
5+
databasePlugin,
6+
DatabasePluginOptions,
7+
DatabaseSnapshotSerializer,
8+
} from '../../src'
59
import { setupDatabaseRefs } from '../utils'
610
import { push } from 'firebase/database'
711

@@ -30,7 +34,7 @@ describe('RTDB: plugin options', () => {
3034

3135
it('calls custom serialize function with a ref', async () => {
3236
const pluginOptions: DatabasePluginOptions = {
33-
serialize: vi.fn(() => ({ foo: 'bar' })),
37+
serialize: vi.fn(() => ({ id: '2', foo: 'bar' })),
3438
}
3539
const { vm } = mount(
3640
{
@@ -55,12 +59,12 @@ describe('RTDB: plugin options', () => {
5559
expect(pluginOptions.serialize).toHaveBeenCalledWith(
5660
expect.objectContaining({ val: expect.any(Function) })
5761
)
58-
expect(vm.items).toEqual([{ foo: 'bar' }])
62+
expect(vm.items).toEqual([{ foo: 'bar', id: '2' }])
5963
})
6064

6165
it('can override serialize with local option', async () => {
62-
const pluginOptions = {
63-
serialize: vi.fn(() => ({ foo: 'bar' })),
66+
const pluginOptions: DatabasePluginOptions = {
67+
serialize: vi.fn(() => ({ id: '2', foo: 'bar' })),
6468
}
6569

6670
const items = databaseRef()
@@ -76,7 +80,10 @@ describe('RTDB: plugin options', () => {
7680
}
7781
)
7882

79-
const spy = vi.fn(() => ({ bar: 'bar' }))
83+
const spy: DatabaseSnapshotSerializer = vi.fn(() => ({
84+
id: '3',
85+
bar: 'bar',
86+
}))
8087

8188
vm.$rtdbBind('items', items, { serialize: spy })
8289
await push(items, { text: 'foo' })
@@ -86,6 +93,6 @@ describe('RTDB: plugin options', () => {
8693
expect(spy).toHaveBeenCalledWith(
8794
expect.objectContaining({ val: expect.any(Function) })
8895
)
89-
expect(vm.items).toEqual([{ bar: 'bar' }])
96+
expect(vm.items).toEqual([{ bar: 'bar', id: '3' }])
9097
})
9198
})

0 commit comments

Comments
 (0)