Skip to content

Commit 248b913

Browse files
committed
Add a feature toggle for avoiding n+1 queries
1 parent d64d1dc commit 248b913

File tree

3 files changed

+17
-9
lines changed

3 files changed

+17
-9
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ Vue.use(HalJsonVuex(store, axios, { apiName: 'backend' }))
114114
let someEntity = this.backend.get('/some/endpoint')
115115
```
116116

117+
### avoidNPlusOneRequests
118+
When accessing the elements of an embedded collection, and some of the elements of the collection have not been loaded from the API before, this library will automatically try to avoid N+1 queries by eager fetching the whole collection.
119+
In case you run into problems with this behaviour with your API, you can disable it by setting the `avoidNPlusOneRequests` option to false:
120+
```js
121+
Vue.use(HalJsonVuex(store, axios, { avoidNPlusOneRequests: false }))
122+
```
123+
117124
### forceRequestedSelfLink
118125
When requesting an entity, some HAL JSON APIs will not always return the same `self` link as it was in the request.
119126
An example would be if the API added a `page=0` query parameter to the `self` link of a collection, even if the request was done without that parameter:

src/index.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,16 @@ export class ServerException extends Error {
3333
*/
3434
function HalJsonVuex (store, axios, options) {
3535
const defaultOptions = {
36-
forceRequestedSelfLink: false,
3736
apiName: 'api',
37+
avoidNPlusOneRequests: true,
38+
forceRequestedSelfLink: false,
3839
nuxtInject: null
3940
}
4041
const opts = { ...defaultOptions, ...options }
4142

4243
store.registerModule(opts.apiName, { state: {}, ...storeModule })
4344

44-
const storeValueProxy = StoreValueProxyCreator(axios.defaults.baseURL, get, isUnknown)
45+
const storeValueProxy = StoreValueProxyCreator(axios.defaults.baseURL, get, isUnknown, opts)
4546

4647
if (opts.nuxtInject !== null) axios = adaptNuxtAxios(axios)
4748

src/storeValueProxy.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import urltemplate from 'url-template'
22

3-
export default function StoreValueProxy (apiRoot, get, isUnknown) {
3+
export default function StoreValueProxy (apiRoot, get, isUnknown, opts = {}) {
44
function isEqualIgnoringOrder (array, other) {
55
return array.length === other.length && array.every(elem => other.includes(elem))
66
}
@@ -142,17 +142,17 @@ export default function StoreValueProxy (apiRoot, get, isUnknown) {
142142
* (or from the API if necessary), and returns that as a new array. In case some of the entity references in
143143
* the array have not finished loading yet, returns a loadingArrayProxy instead.
144144
* @param array possibly mixed array of values and references
145-
* @param fetchAllUri optional URI that allows fetching all array items in a single network request, if known
145+
* @param fetchAllUri URI that allows fetching all array items in a single network request, if known
146146
* @param fetchAllProperty property in the entity from fetchAllUri that will contain the array
147147
* @returns array the new array with replaced items, or a loadingArrayProxy if any of the array elements
148148
* is still loading.
149149
*/
150-
function mapArrayOfEntityReferences (array, fetchAllUri = null, fetchAllProperty = null) {
150+
function mapArrayOfEntityReferences (array, fetchAllUri, fetchAllProperty) {
151151
if (!containsUnknownEntityReference(array)) {
152152
return replaceEntityReferences(array)
153153
}
154154

155-
if (fetchAllUri) {
155+
if (opts.avoidNPlusOneRequests) {
156156
const completelyLoaded = get({ _meta: { reload: { uri: fetchAllUri, property: fetchAllProperty } } }, true)
157157
._meta.load.then(() => replaceEntityReferences(array))
158158
return loadingArrayProxy(completelyLoaded)
@@ -174,11 +174,11 @@ export default function StoreValueProxy (apiRoot, get, isUnknown) {
174174
* lazy, since that potentially fetches a large number of entities from the API.
175175
* @param target object on which the items getter should be defined
176176
* @param items array of items, which can be mixed primitive values and entity references
177-
* @param fetchAllUri optional URI that allows fetching all collection items in a single network request, if known
178-
* @param property optional property name inside the entity fetched at fetchAllUri that contains the collection
177+
* @param fetchAllUri URI that allows fetching all collection items in a single network request, if known
178+
* @param property property name inside the entity fetched at fetchAllUri that contains the collection
179179
* @returns object the target object with the added getter
180180
*/
181-
function addItemsGetter (target, items, fetchAllUri = null, property = null) {
181+
function addItemsGetter (target, items, fetchAllUri, property) {
182182
Object.defineProperty(target, 'items', { get: () => filterDeleting(mapArrayOfEntityReferences(items, fetchAllUri, property)) })
183183
Object.defineProperty(target, 'allItems', { get: () => mapArrayOfEntityReferences(items, fetchAllUri, property) })
184184
return target

0 commit comments

Comments
 (0)