-
Notifications
You must be signed in to change notification settings - Fork 12
/
useQuery.js
102 lines (87 loc) · 3.05 KB
/
useQuery.js
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
import { useEffect, useCallback } from 'react'
import { createSelectorHook } from 'react-redux'
import get from 'lodash/get'
import useClient from './useClient'
import logger from '../logger'
import { clientContext } from '../context'
import { QueryDefinition } from '../queries/dsl'
const useSelector = createSelectorHook(clientContext)
const resolveToValue = fnOrValue => {
return typeof fnOrValue === 'function' ? fnOrValue() : fnOrValue
}
const generateFetchMoreQueryDefinition = queryResult => {
return queryResult.bookmark
? queryResult.definition.offsetBookmark(queryResult.bookmark)
: queryResult.definition.offset(queryResult.data.length)
}
/**
* Fetches a queryDefinition and returns the queryState
*
* @param {QueryDefinition|(() => QueryDefinition)} queryDefinition - Definition created with Q()
* @param {import("../types").QueryOptions} options - Options created with Q()
* @returns {import("../types").UseQueryReturnValue}
*/
const useQuery = (queryDefinition, options) => {
if (!useSelector) {
throw new Error(
'You must use react-redux > 7.1.0 to use useQuery (uses useSelector) under the hood'
)
}
if (!queryDefinition) {
logger.warn('Bad query', queryDefinition)
throw new Error('Bad query')
}
const { as, enabled = true } = options
// If the query is not enabled, no need to call the queryDefinition
// because sometimes, we can have a getById(null) since we want to
// enabled the query only when the specific id is defined. And since
// Q() can throw error when some checks are KO we don't call Q() if
// enabled is not true
const definition = enabled ? resolveToValue(queryDefinition) : null
if (!as) {
throw new Error('You must specify options.as when using useQuery')
}
const client = useClient()
const queryState = useSelector(() => {
if (options.singleDocData === undefined && definition?.id) {
logger.warn(
'useQuery options.singleDocData will pass to true in a next version of cozy-client, please add it now to prevent any problem in the future.'
)
}
return client.getQueryFromState(as, {
hydrated: get(options, 'hydrated', true),
singleDocData: get(options, 'singleDocData', false)
})
})
useEffect(
() => {
if (enabled === false) {
return
}
client.query(definition, options)
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[as, enabled]
)
const fetchMore = useCallback(() => {
const queryState = client.getQueryFromState(as)
return client.query(generateFetchMoreQueryDefinition(queryState), { as })
}, [as, client])
const fetch = useCallback(() => {
return client.query(definition, options)
}, [client, definition, options])
return {
...queryState,
fetchMore: fetchMore,
fetch: fetch
}
}
export const useQueries = querySpecs => {
const res = {}
for (const [queryAttrName, queryOpts] of Object.entries(querySpecs)) {
// eslint-disable-next-line
res[queryAttrName] = useQuery(queryOpts.query, queryOpts)
}
return res
}
export default useQuery