@rpcbase/client 0.198.0 → 0.205.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AppProvider/{index.js → index.tsx} +9 -3
- package/auth/components/ForgotPassword/index.js +1 -1
- package/auth/components/SetNewPassword/index.js +1 -1
- package/auth/components/SignIn/{SignInEmailForm.js → SignInEmailForm.tsx} +4 -5
- package/auth/components/SignOut/index.js +2 -2
- package/auth/components/SignUp/{SignUpEmailForm.js → SignUpEmailForm.tsx} +1 -2
- package/auth/index.js +1 -1
- package/auth/signOut.js +11 -4
- package/firebase/index.js +1 -1
- package/firebase/sw.js +1 -1
- package/helpers/useStoredValue/batchedGetStoredValues.js +1 -1
- package/helpers/useStoredValue/setStoredValues.js +1 -1
- package/i18n/index.js +16 -6
- package/package.json +9 -9
- package/rpc.js +8 -5
- package/rr-trace/index.js +1 -1
- package/rr-trace/write_session_data.js +1 -1
- package/rts/getUseQuery/index.js +200 -178
- package/rts/rts.js +12 -12
- package/rts/signout.ts +8 -0
- package/rts/store/get_collection.js +17 -7
- package/rts/store/index.js +7 -7
- package/rts/store/update_docs.js +5 -4
- package/ui/Modal/ModalForm/index.js +1 -1
package/rts/getUseQuery/index.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/* @flow */
|
|
2
2
|
import {Platform} from "react-native"
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useState,
|
|
7
|
+
useMemo,
|
|
8
|
+
useId,
|
|
9
|
+
useRef,
|
|
10
|
+
} from "react"
|
|
4
11
|
import debug from "debug"
|
|
5
12
|
import _omit from "lodash/omit"
|
|
6
13
|
import LZString from "lz-string"
|
|
@@ -16,198 +23,213 @@ import useData from "./useData"
|
|
|
16
23
|
|
|
17
24
|
const log = debug("rb:rts:useQuery")
|
|
18
25
|
|
|
26
|
+
const getUseQuery =
|
|
27
|
+
(register_query) =>
|
|
28
|
+
(model_name, query = {}, options = {}) => {
|
|
29
|
+
const id = useId()
|
|
30
|
+
|
|
31
|
+
// TODO: should the uid be gone here ? it's part of the auth layer, not this here
|
|
32
|
+
// TODO: retrieve this from future AuthContext in client
|
|
33
|
+
const uid = useMemo(() => {
|
|
34
|
+
// TODO: why is there a options.userId here?? (it was for mobile we need to unify this)
|
|
35
|
+
const _uid = Platform.OS === "web" ? getUid() : options.userId
|
|
36
|
+
return _uid
|
|
37
|
+
}, [])
|
|
38
|
+
|
|
39
|
+
// used to track if data was loaded synchronously (no need to show any loader)
|
|
40
|
+
const hasInitiallySetFromStorage = useRef(false)
|
|
41
|
+
const hasFirstReply = useRef(false)
|
|
42
|
+
const hasNetworkReply = useRef(false)
|
|
43
|
+
const lastDocRef = useRef(null)
|
|
44
|
+
// const [page, setPage] = useState(0)
|
|
45
|
+
|
|
46
|
+
const {
|
|
47
|
+
key = "",
|
|
48
|
+
projection = {},
|
|
49
|
+
sort = {},
|
|
50
|
+
useStorage = false,
|
|
51
|
+
} = options
|
|
52
|
+
|
|
53
|
+
const storageKey = useMemo(() => {
|
|
54
|
+
return `${uid}${key ? `.${key}` : ""}.${model_name}.${JSON.stringify(query)}.${JSON.stringify(projection)}.${JSON.stringify(sort)}`
|
|
55
|
+
}, [uid, key, model_name, query, projection, sort])
|
|
56
|
+
|
|
57
|
+
const [source, setSource] = useState()
|
|
58
|
+
|
|
59
|
+
const dataRef = useRef(null)
|
|
60
|
+
const [data, setData] = useData({
|
|
61
|
+
useStorage,
|
|
62
|
+
storageKey,
|
|
63
|
+
hasInitiallySetFromStorage,
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const [error, setError] = useState()
|
|
67
|
+
|
|
68
|
+
const [loading, setLoading] = useState(() => {
|
|
69
|
+
if (hasInitiallySetFromStorage.current) {
|
|
70
|
+
return false
|
|
71
|
+
}
|
|
72
|
+
return true
|
|
73
|
+
})
|
|
19
74
|
|
|
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
|
-
useStorage = false,
|
|
47
|
-
} = options
|
|
48
|
-
|
|
49
|
-
const storageKey = useMemo(() => {
|
|
50
|
-
return `${uid}${key ? `.${key}` : ""}.${model_name}.${JSON.stringify(query)}.${JSON.stringify(projection)}.${JSON.stringify(sort)}`
|
|
51
|
-
}, [uid, key, model_name, query, projection, sort])
|
|
52
|
-
|
|
53
|
-
const [source, setSource] = useState()
|
|
54
|
-
|
|
55
|
-
const dataRef = useRef(null)
|
|
56
|
-
const [data, setData] = useData({useStorage, storageKey, hasInitiallySetFromStorage})
|
|
57
|
-
|
|
58
|
-
const [error, setError] = useState()
|
|
59
|
-
|
|
60
|
-
const [loading, setLoading] = useState(() => {
|
|
61
|
-
if (hasInitiallySetFromStorage.current) {
|
|
62
|
-
return false
|
|
63
|
-
}
|
|
64
|
-
return true
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
if (options.debug) {
|
|
69
|
-
console.log("use query", model_name, query, options)
|
|
70
|
-
}
|
|
71
|
-
}, [model_name, query, options])
|
|
72
|
-
|
|
73
|
-
const applyNewData = (newData, context) => {
|
|
74
|
-
setData(newData)
|
|
75
|
-
// set data in a ref so that it doesn't force re-rendering ie: unsubscribe / resubscribe
|
|
76
|
-
dataRef.current = newData
|
|
77
|
-
|
|
78
|
-
// useStorage currently used as a fast local cache, indexedDB
|
|
79
|
-
// we only save network queries
|
|
80
|
-
// TODO: use localstorage in react native and pouchdb everywhere
|
|
81
|
-
if (useStorage && context.source === "network") {
|
|
82
|
-
if (Platform.OS === "web") {
|
|
83
|
-
localStorage.setItem(storageKey, LZString.compressToUTF16(JSON.stringify(newData)))
|
|
84
|
-
} else {
|
|
85
|
-
// TODO: this is done in pouchDB nOW ?????
|
|
86
|
-
// TODO: RN MMKV
|
|
87
|
-
console.log("mmkv NYI")
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (newData?.length > 0) {
|
|
92
|
-
lastDocRef.current = newData[newData.length - 1]
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const applyContext = (newContext) => {
|
|
97
|
-
if (newContext.source !== source) {
|
|
98
|
-
setSource(newContext.source)
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
useEffect(() => {
|
|
103
|
-
const queryKey = key || id
|
|
104
|
-
|
|
105
|
-
if (!model_name) {
|
|
106
|
-
console.warn("attempting to register query with empty collection, skipping")
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (options.debug ) {
|
|
111
|
-
console.log("register query", model_name, query, options)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const start = Date.now()
|
|
115
|
-
|
|
116
|
-
log("will register query", model_name, query)
|
|
117
|
-
|
|
118
|
-
const unsubscribe = register_query(model_name, query, {...options, key: queryKey}, (err, queryResult, context) => {
|
|
119
|
-
log("callback answer with context", context, queryResult?.length)
|
|
120
|
-
|
|
121
|
-
// believe it or not, the network can be faster than indexeddb...
|
|
122
|
-
if (context.source === "cache" && hasNetworkReply.current) {
|
|
123
|
-
log("skipping cache arriving later than network")
|
|
124
|
-
return
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// mark if we received from network
|
|
128
|
-
if (context.source === "network" && !hasNetworkReply.current) {
|
|
129
|
-
hasNetworkReply.current = true
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (options.debug) {
|
|
133
|
-
console.log("query took", Date.now() - start, model_name, query)
|
|
134
|
-
}
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (options.debug) {
|
|
77
|
+
console.log("use query", model_name, query, options)
|
|
78
|
+
}
|
|
79
|
+
}, [model_name, query, options])
|
|
80
|
+
|
|
81
|
+
const applyNewData = (newData, context) => {
|
|
82
|
+
setData(newData)
|
|
83
|
+
// set data in a ref so that it doesn't force re-rendering ie: unsubscribe / resubscribe
|
|
84
|
+
dataRef.current = newData
|
|
85
|
+
|
|
86
|
+
// useStorage currently used as a fast local cache, indexedDB
|
|
87
|
+
// we only save network queries
|
|
88
|
+
// TODO: use localstorage in react native and pouchdb everywhere
|
|
89
|
+
if (useStorage && context.source === "network") {
|
|
90
|
+
if (Platform.OS === "web") {
|
|
91
|
+
localStorage.setItem(
|
|
92
|
+
storageKey,
|
|
93
|
+
LZString.compressToUTF16(JSON.stringify(newData)),
|
|
94
|
+
)
|
|
95
|
+
} else {
|
|
96
|
+
// TODO: this is done in pouchDB nOW ?????
|
|
97
|
+
// TODO: RN MMKV
|
|
98
|
+
console.log("mmkv NYI")
|
|
99
|
+
}
|
|
100
|
+
}
|
|
135
101
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return
|
|
102
|
+
if (newData?.length > 0) {
|
|
103
|
+
lastDocRef.current = newData[newData.length - 1]
|
|
104
|
+
}
|
|
140
105
|
}
|
|
141
106
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
let newData
|
|
148
|
-
if (Array.isArray(queryResult)) {
|
|
149
|
-
newData = queryResult.map((o) => _omit(o, "__txn_id"))
|
|
150
|
-
} else {
|
|
151
|
-
newData = _omit(queryResult, "__txn_id")
|
|
107
|
+
const applyContext = (newContext) => {
|
|
108
|
+
if (newContext.source !== source) {
|
|
109
|
+
setSource(newContext.source)
|
|
110
|
+
}
|
|
152
111
|
}
|
|
153
112
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
hasFirstReply.current = true
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
const queryKey = key || id
|
|
157
115
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
116
|
+
if (!model_name) {
|
|
117
|
+
console.warn(
|
|
118
|
+
"attempting to register query with empty collection, skipping",
|
|
119
|
+
)
|
|
161
120
|
return
|
|
162
121
|
}
|
|
163
122
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// TODO: this should be handled by the consumer with the context (cache or network)
|
|
170
|
-
if (context.is_local && options.skipLocal && hasFirstReply.current) {
|
|
171
|
-
log("skipping local update", key)
|
|
172
|
-
return
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (__DEV__ && isEqual(data, newData) && !isEqualValues(data, newData)) {
|
|
176
|
-
alert("EQUALITY MISMATCH THIS SHOULD NOT HAPPEN!", data, newData)
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (!isEqualValues(dataRef.current, newData)) {
|
|
180
|
-
applyContext(context)
|
|
181
|
-
applyNewData(newData, context)
|
|
182
|
-
} else {
|
|
183
|
-
applyContext(context)
|
|
184
|
-
}
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
return () => {
|
|
188
|
-
log && log("useQuery cleanup unsubscribe()")
|
|
189
|
-
typeof unsubscribe === "function" && unsubscribe()
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// WARNING: do not change the hooks dependencies param or you risk creating infinite loops as it unsubscribes on cleanup
|
|
193
|
-
// TODO: this isnt right we need to update on options change too
|
|
194
|
-
}, [JSON.stringify(query), key])
|
|
195
|
-
|
|
123
|
+
if (options.debug) {
|
|
124
|
+
console.log("register query", model_name, query, options)
|
|
125
|
+
}
|
|
196
126
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
127
|
+
const start = Date.now()
|
|
128
|
+
|
|
129
|
+
log("will register query", model_name, query)
|
|
130
|
+
|
|
131
|
+
const unsubscribe = register_query(
|
|
132
|
+
model_name,
|
|
133
|
+
query,
|
|
134
|
+
{...options, key: queryKey, uid},
|
|
135
|
+
(err, queryResult, context) => {
|
|
136
|
+
log("callback answer with context", context, queryResult?.length)
|
|
137
|
+
|
|
138
|
+
// believe it or not, the network can be faster than indexeddb...
|
|
139
|
+
if (context.source === "cache" && hasNetworkReply.current) {
|
|
140
|
+
log("skipping cache arriving later than network")
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// mark if we received from network
|
|
145
|
+
if (context.source === "network" && !hasNetworkReply.current) {
|
|
146
|
+
hasNetworkReply.current = true
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (options.debug) {
|
|
150
|
+
console.log("query took", Date.now() - start, model_name, query)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
setLoading(false)
|
|
154
|
+
if (err) {
|
|
155
|
+
setError(err)
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
log("query callback", model_name, queryKey, JSON.stringify(query))
|
|
160
|
+
|
|
161
|
+
// return if no data (this should be handled already)
|
|
162
|
+
if (!queryResult) return
|
|
163
|
+
|
|
164
|
+
let newData
|
|
165
|
+
if (Array.isArray(queryResult)) {
|
|
166
|
+
newData = queryResult.map((o) => _omit(o, "__txn_id"))
|
|
167
|
+
} else {
|
|
168
|
+
newData = _omit(queryResult, "__txn_id")
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// we return once in any case
|
|
172
|
+
if (!hasFirstReply.current) {
|
|
173
|
+
hasFirstReply.current = true
|
|
174
|
+
|
|
175
|
+
// skip if we already have the data
|
|
176
|
+
if (isEqualValues(data, newData)) {
|
|
177
|
+
applyContext(context)
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
applyContext(context)
|
|
182
|
+
applyNewData(newData, context)
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// TODO: this should be handled by the consumer with the context (cache or network)
|
|
187
|
+
if (context.is_local && options.skipLocal && hasFirstReply.current) {
|
|
188
|
+
log("skipping local update", key)
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (
|
|
193
|
+
__DEV__ &&
|
|
194
|
+
isEqual(data, newData) &&
|
|
195
|
+
!isEqualValues(data, newData)
|
|
196
|
+
) {
|
|
197
|
+
alert("EQUALITY MISMATCH THIS SHOULD NOT HAPPEN!", data, newData)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!isEqualValues(dataRef.current, newData)) {
|
|
201
|
+
applyContext(context)
|
|
202
|
+
applyNewData(newData, context)
|
|
203
|
+
} else {
|
|
204
|
+
applyContext(context)
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
return () => {
|
|
210
|
+
log && log("useQuery cleanup unsubscribe()")
|
|
211
|
+
typeof unsubscribe === "function" && unsubscribe()
|
|
212
|
+
}
|
|
200
213
|
|
|
214
|
+
// WARNING: do not change the hooks dependencies param or you risk creating infinite loops as it unsubscribes on cleanup
|
|
215
|
+
// TODO: this isnt right we need to update on options change too
|
|
216
|
+
}, [JSON.stringify(query), key])
|
|
201
217
|
|
|
202
|
-
|
|
218
|
+
const loadNextPage = useCallback(() => {
|
|
219
|
+
console.log("loadNextPage NYI")
|
|
220
|
+
}, [])
|
|
203
221
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
222
|
+
const result = useMemo(
|
|
223
|
+
() => ({data, source, error, loading, loadNextPage}),
|
|
224
|
+
[data, source, error, loading, loadNextPage],
|
|
225
|
+
)
|
|
208
226
|
|
|
209
|
-
|
|
210
|
-
|
|
227
|
+
// TODO:
|
|
228
|
+
// if (Array.isArray(result.data) && !result.source) {
|
|
229
|
+
// console.warn("RESULT HAS NO SOURCE", {data, error, loading, source})
|
|
230
|
+
// }
|
|
211
231
|
|
|
232
|
+
return result
|
|
233
|
+
}
|
|
212
234
|
|
|
213
235
|
export default getUseQuery
|
package/rts/rts.js
CHANGED
|
@@ -39,7 +39,7 @@ export const add_local_txn = (txn_id) => {
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
// TODO: add compression / decompression
|
|
42
|
-
const dispatch_query_payload = (payload) => {
|
|
42
|
+
const dispatch_query_payload = (payload, uid) => {
|
|
43
43
|
log("dispatch_query_payload", payload)
|
|
44
44
|
|
|
45
45
|
const {model_name, query_key} = payload
|
|
@@ -83,19 +83,19 @@ const dispatch_query_payload = (payload) => {
|
|
|
83
83
|
|
|
84
84
|
// TODO: pouchdb on react native
|
|
85
85
|
if (Platform.OS === "web") {
|
|
86
|
-
store.update_docs(model_name, data)
|
|
86
|
+
store.update_docs(model_name, data, uid)
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
|
|
91
|
-
export const connect = (tenant_id) => new Promise((resolve) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
log("rts client will connect")
|
|
95
|
-
} else {
|
|
96
|
-
log("no tenant_id, rts connect will skip")
|
|
91
|
+
export const connect = (tenant_id, user_id) => new Promise((resolve) => {
|
|
92
|
+
if (!tenant_id) {
|
|
93
|
+
log("missing tenant_id, skipping")
|
|
97
94
|
return
|
|
98
95
|
}
|
|
96
|
+
assert(user_id, "missing user_id")
|
|
97
|
+
|
|
98
|
+
log("rts client will connect")
|
|
99
99
|
|
|
100
100
|
_socket = io(getBaseUrl(), {
|
|
101
101
|
forceNew: true,
|
|
@@ -126,7 +126,7 @@ export const connect = (tenant_id) => new Promise((resolve) => {
|
|
|
126
126
|
|
|
127
127
|
_socket.on("query_payload", (payload) => {
|
|
128
128
|
// console.log("socket:query_payload", payload)
|
|
129
|
-
dispatch_query_payload(payload)
|
|
129
|
+
dispatch_query_payload(payload, user_id)
|
|
130
130
|
})
|
|
131
131
|
|
|
132
132
|
_socket.on("delete_doc", (payload) => {
|
|
@@ -151,13 +151,13 @@ export const disconnect = () => {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
|
|
154
|
-
export const reconnect = (tenant_id) => {
|
|
154
|
+
export const reconnect = (tenant_id, user_id) => {
|
|
155
155
|
log("socket will force reconnect")
|
|
156
156
|
|
|
157
157
|
// destroy current socket if exists
|
|
158
158
|
disconnect()
|
|
159
159
|
|
|
160
|
-
connect(tenant_id)
|
|
160
|
+
connect(tenant_id, user_id)
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
// register a query
|
|
@@ -204,7 +204,7 @@ export const register_query = (model_name, query, _options, _callback) => {
|
|
|
204
204
|
|
|
205
205
|
if (Platform.OS === "web") {
|
|
206
206
|
// run the query from the cache a first time
|
|
207
|
-
store.run_query({model_name, query,
|
|
207
|
+
store.run_query({model_name, query, options}, callback)
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
return () => {
|
package/rts/signout.ts
ADDED
|
@@ -22,24 +22,34 @@ PouchDB.prefix = prefix
|
|
|
22
22
|
PouchDB.plugin(IndexedDBAdapter)
|
|
23
23
|
PouchDB.plugin(FindPlugin)
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
let _cols_store = Object.create(null)
|
|
26
26
|
|
|
27
|
-
const get_collection = (col_name) => {
|
|
27
|
+
export const get_collection = (col_name, options) => {
|
|
28
28
|
|
|
29
29
|
if (!col_name) {
|
|
30
30
|
console.warn("supplied invalid / empty collection name to rts")
|
|
31
31
|
}
|
|
32
|
+
if (!options.uid) {
|
|
33
|
+
console.warn("rts: get_collection: missing options.uid")
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const col_key = `${options.uid}/${col_name}`
|
|
32
37
|
|
|
33
|
-
if (_cols_store[
|
|
34
|
-
return _cols_store[
|
|
38
|
+
if (_cols_store[col_key]) {
|
|
39
|
+
return _cols_store[col_key]
|
|
35
40
|
} else {
|
|
36
41
|
// https://pouchdb.com/api.html#create_database
|
|
37
|
-
const col = new PouchDB(
|
|
38
|
-
_cols_store[
|
|
42
|
+
const col = new PouchDB(col_key, {adapter: "indexeddb", revs_limit: 1})
|
|
43
|
+
_cols_store[col_key] = col
|
|
39
44
|
|
|
40
45
|
return col
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
}
|
|
44
49
|
|
|
45
|
-
|
|
50
|
+
|
|
51
|
+
export const destroy_all = async() => {
|
|
52
|
+
await Promise.map(Object.values(_cols_store), (db) => db.destroy())
|
|
53
|
+
|
|
54
|
+
_cols_store = Object.create(null)
|
|
55
|
+
}
|
package/rts/store/index.js
CHANGED
|
@@ -5,13 +5,13 @@ import "./debug"
|
|
|
5
5
|
|
|
6
6
|
import {UNDERSCORE_PREFIX} from "./constants"
|
|
7
7
|
|
|
8
|
-
import get_collection from "./get_collection"
|
|
8
|
+
import {get_collection} from "./get_collection"
|
|
9
9
|
import update_docs from "./update_docs"
|
|
10
10
|
import satisfies_projection from "./satisfies_projection"
|
|
11
11
|
import replace_query_keys from "./replace_query_keys"
|
|
12
12
|
|
|
13
|
-
const log = debug("rb:rts:store")
|
|
14
13
|
|
|
14
|
+
const log = debug("rb:rts:store")
|
|
15
15
|
|
|
16
16
|
// TODO: listening for changes
|
|
17
17
|
// https://github.com/pouchdb/pouchdb/tree/master/packages/node_modules/pouchdb-find#dbcreateindexindex--callback
|
|
@@ -39,12 +39,12 @@ const log = debug("rb:rts:store")
|
|
|
39
39
|
|
|
40
40
|
// TODO: implement store in a shared worker
|
|
41
41
|
// TODO: should we filter all docs by projection ? or just the ones where the projection isn't complete ?
|
|
42
|
-
const run_query = async({model_name, query,
|
|
43
|
-
|
|
42
|
+
const run_query = async({model_name, query, options}, callback) => {
|
|
43
|
+
log("run_query", {model_name, query, options})
|
|
44
44
|
// console.time("store run_query")
|
|
45
45
|
|
|
46
46
|
// TODO: we should prefix model_name with RB_TENANT_ID + env_id
|
|
47
|
-
const collection = get_collection(model_name)
|
|
47
|
+
const collection = get_collection(model_name, options)
|
|
48
48
|
|
|
49
49
|
const replaced_query = replace_query_keys(query, (k) => (k.startsWith("_") && k !== "_id") ? `${UNDERSCORE_PREFIX}${k}` : k)
|
|
50
50
|
|
|
@@ -64,7 +64,7 @@ const run_query = async({model_name, query, query_key, options}, callback) => {
|
|
|
64
64
|
.map(({_rev, ...doc}) => {
|
|
65
65
|
// TODO: handle projections here
|
|
66
66
|
const remapped_doc = Object.entries(doc).reduce((new_doc, [key, value]) => {
|
|
67
|
-
let new_key = key.startsWith(
|
|
67
|
+
let new_key = key.startsWith("$_") ? key.replace(/^\$_/, "") : key
|
|
68
68
|
new_doc[new_key] = value
|
|
69
69
|
return new_doc
|
|
70
70
|
}, {})
|
|
@@ -82,7 +82,7 @@ const run_query = async({model_name, query, query_key, options}, callback) => {
|
|
|
82
82
|
mapped_docs = mapped_docs.sort((a, b) => {
|
|
83
83
|
for (const key in options.sort) {
|
|
84
84
|
// Check if property exists on both objects
|
|
85
|
-
if (
|
|
85
|
+
if (Object.hasOwn(a, key) && Object.hasOwn(b, key)) {
|
|
86
86
|
const dir = options.sort[key] // Direction of sorting: 1 or -1
|
|
87
87
|
|
|
88
88
|
if (a[key] < b[key]) return -1 * dir
|
package/rts/store/update_docs.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/* @flow */
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
import {get_collection} from "./get_collection"
|
|
3
4
|
|
|
4
5
|
import {UNDERSCORE_PREFIX} from "./constants"
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
const update_docs = async(model_name, data) => {
|
|
8
|
-
const collection = get_collection(model_name)
|
|
8
|
+
const update_docs = async(model_name, data, uid) => {
|
|
9
|
+
const collection = get_collection(model_name, {uid})
|
|
9
10
|
|
|
10
11
|
const all_ids = data.map((doc) => doc._id)
|
|
11
12
|
|
|
@@ -31,7 +32,7 @@ const update_docs = async(model_name, data) => {
|
|
|
31
32
|
|
|
32
33
|
const op = Object.entries(mongo_doc)
|
|
33
34
|
.reduce((new_doc, [key, value]) => {
|
|
34
|
-
let new_key = key !== "_id" && key.startsWith(
|
|
35
|
+
let new_key = key !== "_id" && key.startsWith("_") ? `${UNDERSCORE_PREFIX}${key}` : key
|
|
35
36
|
new_doc[new_key] = value
|
|
36
37
|
return new_doc
|
|
37
38
|
}, current_doc)
|
|
@@ -4,7 +4,7 @@ import {forwardRef, useImperativeHandle, useEffect, useState, useRef} from "reac
|
|
|
4
4
|
import {FormProvider} from "react-hook-form"
|
|
5
5
|
|
|
6
6
|
import ActivityIndicator from "../../ActivityIndicator"
|
|
7
|
-
import SubmitButton from "
|
|
7
|
+
import {SubmitButton} from "../../../form/SubmitButton"
|
|
8
8
|
|
|
9
9
|
import Modal from "../Modal"
|
|
10
10
|
|