-
-
Notifications
You must be signed in to change notification settings - Fork 323
/
rtdb.ts
128 lines (118 loc) · 3.21 KB
/
rtdb.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import { VUEXFIRE_SET_VALUE, VUEXFIRE_ARRAY_ADD, VUEXFIRE_ARRAY_REMOVE } from './mutations-types'
import {
rtdbBindAsArray,
rtdbBindAsObject,
OperationsType,
RTDBOptions,
rtdbOptions,
} from '@posva/vuefire-core'
import { database } from 'firebase'
import { CommitFunction } from './shared'
import { Action, ActionContext } from 'vuex'
const commitOptions = { root: true }
export { rtdbOptions }
// Firebase binding
const subscriptions = new WeakMap()
interface FirebaseActionContext<S, R> extends ActionContext<S, R> {
bindFirebaseRef(
key: string,
reference: database.Reference | database.Query,
options?: RTDBOptions
): Promise<database.DataSnapshot>
unbindFirebaseRef(key: string, reset?: RTDBOptions['reset']): void
}
function bind(
state: Record<string, any>,
commit: CommitFunction,
key: string,
ref: database.Reference | database.Query,
ops: OperationsType,
options: RTDBOptions
): Promise<database.DataSnapshot> {
// TODO check ref is valid
// TODO check defined in state
let sub = subscriptions.get(commit)
if (!sub) {
sub = Object.create(null)
subscriptions.set(commit, sub)
}
// unbind if ref is already bound
if (key in sub) {
unbind(commit, key, options && options.reset)
}
return new Promise((resolve, reject) => {
sub[key] = Array.isArray(state[key])
? rtdbBindAsArray(
{
vm: state,
key,
collection: ref,
ops,
resolve,
reject,
},
options
)
: rtdbBindAsObject(
{
vm: state,
key,
document: ref,
ops,
resolve,
reject,
},
options
)
})
}
function unbind(commit: CommitFunction, key: string, reset?: RTDBOptions['reset']) {
const sub = subscriptions.get(commit)
if (!sub || !sub[key]) return
// TODO dev check before
sub[key](reset)
delete sub[key]
}
export function firebaseAction<S, R>(
action: (context: FirebaseActionContext<S, R>, payload: any) => any
): Action<S, R> {
return function firebaseEnhancedActionFn(context, payload) {
// get the local state and commit. These may be bound to a module
const { state, commit } = context
const ops: OperationsType = {
set: (target, path, data) => {
commit(
VUEXFIRE_SET_VALUE,
{
path,
target,
data,
},
commitOptions
)
return data
},
add: (target, newIndex, data) =>
commit(VUEXFIRE_ARRAY_ADD, { target, newIndex, data }, commitOptions),
remove: (target, oldIndex) => {
const data = target[oldIndex]
commit(VUEXFIRE_ARRAY_REMOVE, { target, oldIndex }, commitOptions)
return [data]
},
}
return action.call(
this,
{
...context,
bindFirebaseRef: (
key: string,
ref: database.Reference | database.Query,
options?: RTDBOptions
) => bind(state, commit, key, ref, ops, Object.assign({}, rtdbOptions, options)),
unbindFirebaseRef: (key: string, reset?: RTDBOptions['reset']) =>
unbind(commit, key, reset),
},
payload
)
}
}