Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opt in to autoRemove #24

Merged
merged 8 commits into from
Jun 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,34 @@ To see `feathers-vuex` in a working vue-cli application, check out [`feathers-ch

## API Documentation

### Global Configuration

The following default options are available for configuration:

```js
const defaultOptions = {
idField: 'id', // The field in each record that will contain the id
auto: true, // automatically setup a store for each service.
autoRemove: false, // automatically remove records missing from responses (only use with feathers-rest)
nameStyle: 'short', // Determines the source of the module name. 'short', 'path', or 'explicit'
feathers: {
namespace: 'feathers'
},
auth: {
namespace: 'auth',
userService: '', // Set this to automatically populate the user on login success.
state: {}, // add custom state to the auth module
getters: {}, // add custom getters to the auth module
mutations: {}, // add custom mutations to the auth module
actions: {} // add custom actions to the auth module
}
}
```

Each service module can also be individually configured.

### The Vuex modules

There are three modules included:
1. The Feathers module keeps a list of all services with vuex stores attached.
2. The Service module adds a Vuex store for new services.
Expand Down
19 changes: 9 additions & 10 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,20 @@ import clone from 'clone'
import { normalizePath, makeConfig, isBrowser } from './utils'

const defaultOptions = {
idField: 'id',
auto: true,
autoForce: false,
// Determines the source of the module name. 'short', 'path', or 'explicit'
nameStyle: 'short',
idField: 'id', // The field in each record that will contain the id
auto: true, // automatically setup a store for each service.
autoRemove: false, // automatically remove records missing from responses (only use with feathers-rest)
nameStyle: 'short', // Determines the source of the module name. 'short', 'path', or 'explicit'
feathers: {
namespace: 'feathers'
},
auth: {
namespace: 'auth',
userService: '',
state: {},
getters: {},
mutations: {},
actions: {}
userService: '', // Set this to automatically populate the user on login success.
state: {}, // add custom state to the auth module
getters: {}, // add custom getters to the auth module
mutations: {}, // add custom mutations to the auth module
actions: {} // add custom actions to the auth module
}
}

Expand Down
29 changes: 16 additions & 13 deletions src/service-module/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ export default function makeServiceActions (service) {
find ({ commit, dispatch }, params) {
commit('setFindPending')
const handleResponse = response => {
let data = response.data || response
dispatch('addOrUpdateList', data)
dispatch('addOrUpdateList', response)
commit('unsetFindPending')
return response
}
Expand Down Expand Up @@ -131,17 +130,21 @@ export default function makeServiceActions (service) {
}

const actions = {
addOrUpdateList ({ state, commit }, list) {
let toAdd = []
let toUpdate = []
let toRemove = [] // Added

// Find IDs from the state which are not in the list
state.ids.forEach(id => {
if (id !== state.currentId && !list.some(item => item[idField] === id)) {
toRemove.push(state.keyedById[id])
}
})
addOrUpdateList ({ state, commit }, response) {
const list = response.data || response
const isPaginated = response.hasOwnProperty('total')
const toAdd = []
const toUpdate = []
const toRemove = [] // Added

if (!isPaginated && vuexOptions.global.autoRemove) {
// Find IDs from the state which are not in the list
state.ids.forEach(id => {
if (id !== state.currentId && !list.some(item => item[idField] === id)) {
toRemove.push(state.keyedById[id])
}
})
}

list.forEach(item => {
let id = item[idField]
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/todos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = function makeTodos () {
return {
1: { _id: 1, description: 'Dishes', isComplete: true },
2: { _id: 2, description: 'Laundry', isComplete: true },
3: { _id: 3, description: 'Groceries', isComplete: true }
}
}
137 changes: 136 additions & 1 deletion test/service-module/service-module.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import feathersVuex from '~/src/index'
import makeStore from '../fixtures/store'
import { makeFeathersRestClient } from '../fixtures/feathers-client'
import memory from 'feathers-memory'
import makeTodos from '../fixtures/todos'

describe('Service Module', () => {
describe('Configuration', () => {
Expand All @@ -23,7 +24,7 @@ describe('Service Module', () => {
const expectedGlobal = {
idField: 'id',
auto: true,
autoForce: false,
autoRemove: false,
nameStyle: 'short',
feathers: {
namespace: 'feathers'
Expand Down Expand Up @@ -140,5 +141,139 @@ describe('Service Module', () => {
assert(todoState.idField === '_id')
assert.deepEqual(todoState.keyedById, {})
})

it(`populates items on find`, function (done) {
const store = makeStore()
makeFeathersRestClient()
.configure(feathersVuex(store, {idField: '_id'}))
.service('todos', memory({store: makeTodos()}))

const todoState = store.state.todos

assert(todoState.ids.length === 0)

store.dispatch('todos/find', { query: {} })
.then(todos => {
assert(todoState.ids.length === 3)
done()
})
.catch(error => {
assert(!error, error.message)
done()
})
})

describe('Auto-remove items', function () {
it(`removes missing items when pagination is off`, function (done) {
const store = makeStore()
const todoService = makeFeathersRestClient()
.configure(feathersVuex(store, {
idField: '_id',
autoRemove: true
}))
.service('todos', memory({store: makeTodos()}))

const todoState = store.state.todos

assert(todoState.ids.length === 0)

// Load some data into the store
store.dispatch('todos/find', { query: {} })
.then(todos => {
// Remove the third item from the service
return todoService.remove(3)
})
.then(response => {
// We went around using the store actions, so there will still be three items.
assert(todoState.ids.length === 3, 'there are still three items in the store')

// Perform the same query again
return store.dispatch('todos/find', { query: {} })
})
.then(todos => {
assert(!todos.hasOwnProperty('total'), 'pagination is off')
assert(todoState.ids.length === 2, 'there are now two items in the store')
done()
})
.catch(error => {
assert(!error, error.message)
done()
})
})

it(`does not remove missing items when pagination is on`, function (done) {
const store = makeStore()
const todoService = makeFeathersRestClient()
.configure(feathersVuex(store, {idField: '_id'}))
.service('todos', memory({
store: makeTodos(),
paginate: {
default: 10,
max: 50
}
}))

const todoState = store.state.todos

assert(todoState.ids.length === 0)

// Load some data into the store
store.dispatch('todos/find', { query: {} })
.then(todos => {
// Remove the third item from the service
return todoService.remove(3)
})
.then(response => {
// We went around using the store actions, so there will still be three items.
assert(todoState.ids.length === 3, 'there are still three items in the store')

// Perform the same query again
return store.dispatch('todos/find', { query: {} })
})
.then(todos => {
assert(todos.hasOwnProperty('total'), 'pagination is on')
assert(todoState.ids.length === 3, 'there are still three items in the store')
done()
})
.catch(error => {
assert(!error, error.message)
done()
})
})

it(`does not remove missing items when autoRemove is off`, function (done) {
const store = makeStore()
const todoService = makeFeathersRestClient()
.configure(feathersVuex(store, {idField: '_id', autoRemove: false}))
.service('todos', memory({ store: makeTodos() }))

const todoState = store.state.todos

assert(todoState.ids.length === 0)

// Load some data into the store
store.dispatch('todos/find', { query: {} })
.then(todos => {
// Remove the third item from the service
return todoService.remove(3)
})
.then(response => {
// We went around using the store actions, so there will still be three items.
assert(todoState.ids.length === 3, 'there are still three items in the store')

// Perform the same query again
return store.dispatch('todos/find', { query: {} })
})
.then(todos => {
assert(!todos.hasOwnProperty('total'), 'pagination is off')
assert(todoState.ids.length === 3, 'there are still three items in the store')
done()
})
.catch(error => {
assert(!error, error.message)
done()
})
})
})
})
})