Skip to content

Commit 67045ec

Browse files
committed
Test the new use/find api defaults
1 parent 980e501 commit 67045ec

File tree

3 files changed

+264
-66
lines changed

3 files changed

+264
-66
lines changed

src/useFind.ts

Lines changed: 111 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,111 @@
1-
import { reactive, computed, toRefs, isRef, watch } from '@vue/composition-api'
1+
/*
2+
eslint
3+
@typescript-eslint/no-explicit-any: 0
4+
*/
25
import {
3-
getServicePrefix,
4-
getServiceCapitalization,
5-
getQueryInfo,
6-
getItemsFromQueryInfo,
7-
Params
8-
} from './utils'
6+
reactive,
7+
computed,
8+
toRefs,
9+
isRef,
10+
watch,
11+
Ref
12+
} from '@vue/composition-api'
13+
import { getQueryInfo, getItemsFromQueryInfo, Params } from './utils'
914
import debounce from 'lodash/debounce'
1015

1116
const defaults = {
1217
model: null,
1318
params: null,
14-
queryWhen: () => true,
15-
qid: 'default'
19+
queryWhen: (): boolean => true,
20+
qid: 'default',
21+
local: false
1622
}
1723

18-
export default function find(options) {
19-
const { model, params, name, queryWhen, qid } = Object.assign(
24+
interface UseFindOptions {
25+
model: Function
26+
params: Params | Ref<Params>
27+
fetchParams?: Params | Ref<Params>
28+
name?: string
29+
queryWhen?: Function
30+
qid?: string
31+
}
32+
interface UseFindState {
33+
debounceTime: null | number
34+
qid: string
35+
isFindPending: boolean
36+
haveBeenRequestedOnce: boolean
37+
haveLoadedOnce: boolean
38+
error: null | Error
39+
latestQuery: null | object
40+
isLocal: boolean
41+
}
42+
interface UseFindData {
43+
items: Ref<any>
44+
servicePath: Ref<string>
45+
isFindPending: Ref<boolean>
46+
haveBeenRequestedOnce: Ref<boolean>
47+
haveLoadedOnce: Ref<boolean>
48+
isLocal: Ref<boolean>
49+
qid: Ref<string>
50+
debounceTime: Ref<number>
51+
find: Function
52+
findInStore: Function
53+
latestQuery: Ref<object>
54+
paginationData: Ref<object>
55+
queryWhen: Ref<boolean>
56+
error: Ref<Error>
57+
}
58+
59+
export default function find(options: UseFindOptions): UseFindData {
60+
const { model, params, queryWhen, qid, local } = Object.assign(
2061
{},
2162
defaults,
2263
options
2364
)
2465

25-
const nameToUse = (name || model.servicePath).replace('-', '_')
26-
const prefix = getServicePrefix(nameToUse)
27-
const capitalized = getServiceCapitalization(nameToUse)
28-
const IS_FIND_PENDING = `isFind${capitalized}Pending`
29-
const QUERY_WHEN = `${prefix}QueryWhen`
30-
const FIND_ACTION = `find${capitalized}`
31-
const FIND_GETTER = `find${capitalized}InStore`
32-
const DEBOUNCED = `${FIND_ACTION}Debounced`
33-
const DEBOUNCE_TIME = `${FIND_ACTION}DebouncedTime`
34-
const HAVE_ITEMS_BEEN_REQUESTED_ONCE = `have${capitalized}BeenRequestedOnce`
35-
const HAVE_ITEMS_LOADED_ONCE = `have${capitalized}LoadedOnce`
36-
const PAGINATION = `${prefix}PaginationData`
37-
const MOST_RECENT_QUERY = `${prefix}LatestQuery`
38-
const ERROR = `${prefix}Error`
39-
const QID = `${prefix}Qid`
66+
const getFetchParams = (providedParams?: object): Params => {
67+
const provided = isRef(providedParams)
68+
? providedParams.value
69+
: providedParams
4070

41-
const getFetchParams = (providedParams?:object) => {
42-
if (providedParams) {
43-
return providedParams
71+
if (provided) {
72+
return provided
4473
} else {
45-
// Returning null fetchParams allows the query to be skipped.
46-
return options.fetchParams || options.fetchParams === null
47-
? options.fetchParams
74+
const fetchParams = isRef(options.fetchParams)
75+
? options.fetchParams.value
76+
: options.fetchParams
77+
const params = isRef(options.params)
78+
? options.params.value
4879
: options.params
80+
81+
// Returning null fetchParams allows the query to be skipped.
82+
return fetchParams || fetchParams === null ? fetchParams : params
4983
}
5084
}
5185

52-
const state = reactive({
86+
const state = reactive<UseFindState>({
87+
qid,
88+
isFindPending: false,
89+
haveBeenRequestedOnce: false,
90+
haveLoadedOnce: false,
91+
error: null,
92+
debounceTime: null,
93+
latestQuery: null,
94+
isLocal: local
95+
})
96+
const computes = {
5397
// The find getter
54-
[prefix]: computed(() => {
55-
// @ts-ignore
56-
const getterParams:Params = isRef(params) ? { ...params.value } : { params }
98+
items: computed<any[]>(() => {
99+
const getterParams: Params = isRef(params)
100+
? Object.assign({}, params.value)
101+
: { params }
57102
if (getterParams.paginate) {
58103
const serviceState = model.store.state[model.servicePath]
59104
const { defaultSkip, defaultLimit } = serviceState.pagination
60105
const skip = getterParams.query.$skip || defaultSkip
61106
const limit = getterParams.query.$limit || defaultLimit
62-
const pagination = state[PAGINATION][getterParams.qid || state[QID]] || {}
107+
const pagination =
108+
computes.paginationData[getterParams.qid || state[qid]] || {}
63109
const response = skip != null && limit != null ? { limit, skip } : {}
64110
const queryInfo = getQueryInfo(getterParams, response)
65111
const items = getItemsFromQueryInfo(
@@ -74,52 +120,50 @@ export default function find(options) {
74120
return model.findInStore(getterParams).data
75121
}
76122
}),
77-
[QID]: qid,
78-
[QUERY_WHEN]: computed(() => queryWhen),
79-
[IS_FIND_PENDING]: false,
80-
[HAVE_ITEMS_BEEN_REQUESTED_ONCE]: false,
81-
[HAVE_ITEMS_LOADED_ONCE]: false,
82-
[ERROR]: null,
83-
[PAGINATION]: computed(() => {
123+
queryWhen: computed<boolean>(() => queryWhen()),
124+
paginationData: computed(() => {
84125
return model.store.state[model.servicePath].pagination
85126
}),
86-
[DEBOUNCED]: null,
87-
[DEBOUNCE_TIME]: null
88-
})
127+
servicePath: computed<string>(() => model.servicePath)
128+
}
89129

90-
function find(params) {
130+
function find<T>(params: Params): T {
91131
params = isRef(params) ? params.value : params
92-
if (state[QUERY_WHEN]) {
93-
console.log('finding')
94-
state[IS_FIND_PENDING] = true
95-
state[HAVE_ITEMS_BEEN_REQUESTED_ONCE] = true
132+
if (computes.queryWhen.value) {
133+
state.isFindPending = true
134+
state.haveBeenRequestedOnce = true
96135

97-
model.find(params).then(response => {
98-
// To prevent thrashing, only clear ERROR on response, not on initial request.
99-
state[ERROR] = null
100-
state[HAVE_ITEMS_LOADED_ONCE] = true
136+
return model.find(params).then(response => {
137+
// To prevent thrashing, only clear error on response, not on initial request.
138+
state.error = null
139+
state.haveLoadedOnce = true
101140

102141
const queryInfo = getQueryInfo(params, response)
103142
queryInfo.response = response
104143
queryInfo.isOutdated = false
105144

106-
state[MOST_RECENT_QUERY] = queryInfo
107-
state[IS_FIND_PENDING] = false
145+
state.latestQuery = queryInfo
146+
state.isFindPending = false
108147
return response
109148
})
110149
}
111150
}
112-
function findProxy(params?:object) {
151+
const methods = {
152+
findDebounced<Promise>(params?: Params): Promise {
153+
return find(params)
154+
}
155+
}
156+
function findProxy<T>(params?: Params): T {
113157
const paramsToUse = getFetchParams(params)
114158

115159
if (paramsToUse && paramsToUse.debounce) {
116-
if (paramsToUse.debounce !== state[DEBOUNCE_TIME]) {
117-
state[DEBOUNCED] = debounce(find, paramsToUse.debounce)
118-
state[DEBOUNCE_TIME] = paramsToUse.debounce
160+
if (paramsToUse.debounce !== state.debounceTime) {
161+
methods.findDebounced = debounce(find, paramsToUse.debounce)
162+
state.debounceTime = paramsToUse.debounce
119163
}
120-
return state[DEBOUNCED](paramsToUse)
164+
return methods.findDebounced(paramsToUse)
121165
} else if (paramsToUse) {
122-
find(paramsToUse)
166+
return find(paramsToUse)
123167
} else {
124168
// Set error
125169
}
@@ -133,8 +177,9 @@ export default function find(options) {
133177
)
134178

135179
return {
180+
...computes,
136181
...toRefs(state),
137-
[FIND_ACTION]: model.find,
138-
[FIND_GETTER]: model.findInStore
182+
find: model.find,
183+
findInStore: model.findInStore
139184
}
140185
}

test/use/InstrumentComponent.vue

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<template>
2+
<div>
3+
4+
</div>
5+
</template>
6+
7+
<script>
8+
import useFind from '../../src/useFind'
9+
10+
export default {
11+
name: 'InstrumentComponent',
12+
props: {
13+
id: {
14+
type: String,
15+
default: ''
16+
}
17+
},
18+
setup(props, context) {
19+
const { Instrument } = context.root.$FeathersVuex
20+
21+
const instrumentsParams = computed(() => {
22+
return {
23+
query: {},
24+
paginate: false
25+
}
26+
})
27+
const instrumentsData = useFind({ model: Instrument, params: instrumentsParams })
28+
const { items: instruments } = instrumentsData
29+
}
30+
}
31+
</script>
32+
33+
<style lang="scss" scoped>
34+
35+
</style>

test/use/find.test.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
eslint
3+
@typescript-eslint/explicit-function-return-type: 0,
4+
@typescript-eslint/no-explicit-any: 0,
5+
@typescript-eslint/no-empty-function: 0
6+
*/
7+
import jsdom from 'jsdom-global'
8+
import { assert } from 'chai'
9+
import feathersVuex, { FeathersVuex } from '../../src/index'
10+
import { feathersRestClient as feathersClient } from '../fixtures/feathers-client'
11+
import useFind from '../../src/useFind'
12+
import Vue from 'vue/dist/vue'
13+
import VueCompositionApi from '@vue/composition-api'
14+
import Vuex from 'vuex'
15+
// import { shallowMount } from '@vue/test-utils'
16+
import { computed, isRef } from '@vue/composition-api'
17+
jsdom()
18+
require('events').EventEmitter.prototype._maxListeners = 100
19+
20+
function makeContext() {
21+
const { makeServicePlugin, BaseModel } = feathersVuex(feathersClient, {
22+
serverAlias: 'make-find-mixin'
23+
})
24+
25+
class Instrument extends BaseModel {
26+
public static modelName = 'Instrument'
27+
}
28+
29+
const serviceName = 'instruments'
30+
const store = new Vuex.Store({
31+
plugins: [
32+
makeServicePlugin({
33+
Model: Instrument,
34+
service: feathersClient.service(serviceName)
35+
})
36+
]
37+
})
38+
return { store, Instrument, BaseModel, makeServicePlugin }
39+
}
40+
41+
Vue.use(VueCompositionApi)
42+
Vue.use(Vuex)
43+
Vue.use(FeathersVuex)
44+
45+
describe('use/find', function() {
46+
it('returns correct default data', function() {
47+
const { Instrument } = makeContext()
48+
49+
const instrumentParams = computed(() => {
50+
return {
51+
query: {},
52+
paginate: false
53+
}
54+
})
55+
const instrumentsData = useFind({
56+
model: Instrument,
57+
params: instrumentParams
58+
})
59+
60+
const {
61+
debounceTime,
62+
error,
63+
find,
64+
findInStore,
65+
haveBeenRequestedOnce,
66+
haveLoadedOnce,
67+
isFindPending,
68+
isLocal,
69+
items,
70+
latestQuery,
71+
paginationData,
72+
qid,
73+
queryWhen
74+
} = instrumentsData
75+
76+
assert(isRef(debounceTime))
77+
assert(debounceTime.value === null)
78+
79+
assert(isRef(error))
80+
assert(error.value === null)
81+
82+
assert(typeof find === 'function')
83+
assert(typeof findInStore === 'function')
84+
85+
assert(isRef(haveBeenRequestedOnce))
86+
assert(haveBeenRequestedOnce.value === true)
87+
88+
assert(isRef(haveLoadedOnce))
89+
assert(haveLoadedOnce.value === false)
90+
91+
assert(isRef(isFindPending))
92+
assert(isFindPending.value === true)
93+
94+
assert(isRef(isLocal))
95+
assert(isLocal.value === false)
96+
97+
assert(isRef(items))
98+
assert(Array.isArray(items.value))
99+
assert(items.value.length === 0)
100+
101+
assert(isRef(latestQuery))
102+
assert(latestQuery.value === null)
103+
104+
assert(isRef(paginationData))
105+
assert.deepStrictEqual(paginationData.value, {
106+
defaultLimit: null,
107+
defaultSkip: null
108+
})
109+
110+
assert(isRef(qid))
111+
assert(qid.value === 'default')
112+
113+
assert(isRef(queryWhen))
114+
assert(queryWhen.value === true)
115+
})
116+
117+
it.skip('allows passing {lazy:true} to not query immediately', function() {})
118+
})

0 commit comments

Comments
 (0)