Skip to content

Commit

Permalink
v1.35.1 🐳 [merge]
Browse files Browse the repository at this point in the history
  • Loading branch information
mesqueeb authored Dec 10, 2019
2 parents 6169796 + 600a207 commit 6895c3c
Show file tree
Hide file tree
Showing 19 changed files with 1,309 additions and 588 deletions.
423 changes: 297 additions & 126 deletions dist/index.cjs.js

Large diffs are not rendered by default.

423 changes: 297 additions & 126 deletions dist/index.esm.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Now you just update and add docs with `dispatch('userData/set', newItem)` and fo
- [Hooks](hooks.html#hooks) (before / after sync)
- [Fillables / guard](extra-features.html#fillables-and-guard) (limit fields which will sync)
- [Timestamp conversion to Date()](extra-features.html#firestore-timestamp-conversion)
- [Where / orderBy filters](query-data.html#where-orderby-filters)
- [Where / orderBy clauses](query-data.html#where-orderby-clauses)

# Motivation

Expand Down
2 changes: 1 addition & 1 deletion docs/config-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const firestoreModule = {
removedHook: function (updateStore, doc, id, store) { return updateStore(doc) },
},

// When docs are fetched through `dispatch('module/fetch', filters)`.
// When docs are fetched through `dispatch('module/fetch', {clauses})`.
fetch: {
// The max amount of documents to be fetched. Defaults to 50.
docLimit: 50,
Expand Down
22 changes: 10 additions & 12 deletions docs/extra-features.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Extra features

## Variables for firestorePath or filters
## Variables for firestorePath or clauses

Besides `'{userId}'` in your `firestorePath` in the config or in where filters, you can also use **any variable** in the `firestorePath` or the `where` filter.
Besides `'{userId}'` in your `firestorePath` in the config or in `where` clauses, you can also use **any variable** in the `firestorePath` or the `where` filter.

```js
// your vuex module
Expand All @@ -16,10 +16,10 @@ You can replace a path variable with the actual string by:

```js
// 1. Passing it as a parameter to openDBChannel
dispatch('groupUserData/openDBChannel', {groupId: 'group-A'})
dispatch('groupUserData/openDBChannel', {pathVariables: {groupId: 'group-A'}})

// 2. Passing it as a parameter to fetchAndAdd
dispatch('groupUserData/fetchAndAdd', {groupId: 'group-A'})
dispatch('groupUserData/fetchAndAdd', {pathVariables: {groupId: 'group-A'}})

// 3. Dispatching setPathVars
dispatch('groupUserData/setPathVars', {groupId: 'group-A'})
Expand Down Expand Up @@ -50,11 +50,11 @@ store.dispatch('userData/openDBChannel')
// Then we can get the groupId:
const userGroupId = store.state.userData.groupId
// Then we can pass it as variable to the next openDBChannel:
store.dispatch('groupUserData/openDBChannel', {groupId: userGroupId})
store.dispatch('groupUserData/openDBChannel', {pathVariables: {groupId: userGroupId}})
})
```

### Use case: Retieve data based on the Vue Router path
### Use case: Retrieve data based on the Vue Router path

This is a great use case! But it has a good and a bad implementation. I'll go over both so you can see what I mean:

Expand All @@ -74,7 +74,7 @@ SpecificGroupUserModule: {
export default {
created () {
const pageId = this.$route.params.id
this.$store.dispatch('page/fetchAndAdd', {pageId})
this.$store.dispatch('page/fetchAndAdd', {pathVariables: {pageId}})
},
computed: {
openDoc () {
Expand All @@ -84,14 +84,12 @@ export default {
}
```

The above example shows a Vuex module linked to a single doc, but this path is changed every time the user opens a page and then the doc is retrieved. The reasons not to do this are:

- When opening a new page you will need to release the previous doc from memory every time, so when the user goes back you will be charged with a read every single time!
- Please see [this thread](https://github.com/mesqueeb/vuex-easy-firestore/issues/172) for problems when there's an internet interruption.
The above example shows a Vuex module linked to a single doc, but this path is changed every time the user opens a page and then the doc is retrieved.
When opening a new page you will need to release the previous doc from memory every time, so when the user goes back you will be charged with a read again.

#### Good implementation of Vue Router

Instead, use 'collection' mode! This way you can keep the pages that were openend already and opening those pages again is much faster. That implementation would look like this:
Instead, use 'collection' mode! This way you can keep the pages that were opened already and opening those pages again is much faster. That implementation would look like this:

```js
// MUCH BETTER:
Expand Down
99 changes: 70 additions & 29 deletions docs/query-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,47 +15,86 @@ With Vuex easy firestore using _realtime updates_ will effectively make **a 2-wa

Fetching the document(s) once is when you want to retrieve the document(s) once, when your application or a page is opened, but do not require to have the data to be live updated when the server data changes.

Both with _realtime updates_ and with _fetching docs_ you can use `where` filters to specify which docs you want to retrieve (just like Firestore). In some modules you might initially open a channel for _realtime updates_ with a certain `where` filter, and later when the user requests other docs do an additional `fetch` with another `where` filter.
Both with _realtime updates_ and with _fetching docs_ you can use `where` clauses to specify which docs you want to retrieve (just like Firestore). In some modules you might initially open a channel for _realtime updates_ with a certain `where` clause, and later when the user requests other docs do an additional `fetch` with another `where` clause.

## Realtime updates: openDBChannel

If you want to use _realtime updates_ the only thing you need to do is to dispatch the `openDBChannel` action. Eg.
If you want to get _realtime updates_, you need to dispatch the `openDBChannel` action. Eg.

```js
dispatch('moduleName/openDBChannel').catch(console.error)
dispatch('moduleName/openDBChannel')
```

`openDBChannel` relies on the Firestore [onSnapshot](https://firebase.google.com/docs/firestore/query-data/listen) function to get notified of remote changes. The doc(s) are automatically added to/updated in your Vuex module under `moduleName/statePropName`
`openDBChannel` relies on the Firestore [onSnapshot](https://firebase.google.com/docs/firestore/query-data/listen) function to get notified of remote changes. The doc(s) are automatically added to/updated in your Vuex module under `moduleName/statePropName`.

Mind that:
- if the channel is opened on a document which does not exist yet at Firebase, the document gets automatically created, unless you set `preventInitialDocInsertion` to `true`
- the action returns a promise that lets you know you when the streaming through the channel has successfully started
- when this promise is resolved, it resolves with a function which wraps a promise that lets you know when an error occurs
- if the channel is opened on a document which does not exist yet at Firebase, the document gets automatically (re)created, unless you set `preventInitialDocInsertion` to `true`
- the action returns a promise which resolves when the state of the module has been populated with data (served either from cache or server), so you know you can start working with it
- when this promise is resolved, you get another one which lets you know when an error occurs

Just like the Firebase SDK, you can also use a [where filter](#where-orderby-filters).
Just like the Firebase SDK, you can also use a [`where` clause](#where-orderby-clauses).

```js
dispatch('moduleName/openDBChannel')
.then(streaming => {
// streaming data through the channel has started (ie. data was received)
.then(({streaming}) => {
// the state has been populated with data, you may start working with it
startDoingThings()

// you must monitor if the channel keeps streaming to catch errors. Mind that
// even after going offline, the channel is still considered as "streaming"
// and will remain so until you close it or an error occurs.
// you must check that the channel keeps streaming and catch errors. Mind that
// even while offline, the channel is considered as "streaming" and will remain
// so until you close it or until an error occurs.
streaming()
.then(() => {
// this gets resolved when you close the channel yourself
})
.catch(error => {
// an error occured and the channel has been closed by Firestore, you
// should figure out what happened and open a new channel.
// an error occured and the channel has been closed, you should figure
// out what happened and open a new channel.

// Perhaps the user lost his `read` rights on the resource, or maybe the
// document got deleted and it wasn't possible to recreate it (possibly
// because `preventInitialDocInsertion` is `false`). Or some other error
// from Firestore.
})
})
.catch(error => {
// the document didn't exist and `preventInitialDocInsertion` is `false`
// Same as the other `catch` block above
})
```

Sometimes the promise returned by the action might not be enough for you, because you need to know when the module has been populated with fresh data, not cached data. In that case, you need to pass an option when calling the action, which in turn will provide you with an additional promise. This, however, will also trigger your server hook listeners more frequently. Read [Firestore's documentation](https://firebase.google.com/docs/firestore/query-data/listen#events-metadata-changes) to know more about this.

```js
dispatch('moduleName/openDBChannel', {includeMetadataChanges: true})
.then(({refreshed, streaming}) => {

refreshed
.then(() => {
// the state has been populated with fresh data
})
.catch(error => {...})

streaming()
.then(() => {...})
.catch(error => {...})
})
.catch(error => {...})
```

Finally, if you open multiple channels on a same module with different clauses, you will need to use the `stop` method provided in the promise to handle their closing at your discretion:

```js
dispatch('moduleName/openDBChannel')
.then(({streaming, stop}) => {

stop().then(() => {
// the channel has been closed
})
})
.catch(error => {...})
```


### Close DB channel

In some cases you need to close the connection to Firestore (unsubscribe from Firestore's `onSnapshot` listener). Eg. when your user signs out. In this case, make sure you call `closeDBChannel` like so:
Expand Down Expand Up @@ -120,7 +159,7 @@ Or you could retrieve all Pokémon like so:
dispatch('pokemon/fetchAndAdd')
```

Of course, just like the Firebase SDK, you can also use a `where` filter to retrieve eg. all water Pokémon. (Read more on [where filters](#where-orderby-filters) down below)
Of course, just like the Firebase SDK, you can also use a `where` clause to retrieve eg. all water Pokémon. (Read more on [where clauses](#where-orderby-clauses) down below)

```js
dispatch('pokemon/fetchAndAdd', {where: [['type', '==', 'water']]})
Expand All @@ -142,9 +181,9 @@ You can pass a custom fetch limit or disable the fetch limit by passing 0:

```js
// custom fetch limit:
dispatch('myModule/fetchAndAdd', {limit: 1000})
dispatch('myModule/fetchAndAdd', {clauses: {limit: 1000}})
// no fetch limit:
dispatch('myModule/fetchAndAdd', {limit: 0})
dispatch('myModule/fetchAndAdd', {clauses: {limit: 0}})
```

The `fetchAndAdd` action will return a promise resolving in `{done: true}` if there are no more docs to be fetched. You can use this to check when to stop fetching like so:
Expand Down Expand Up @@ -203,35 +242,37 @@ Firebase.auth().onAuthStateChanged(user => {

When required you can also manually pass a user id like so: `dispatch('userData/setUserId', id)`

## where / orderBy filters
## where / orderBy clauses

> Only for 'collection' mode.
Just like Firestore, you can use `where` and `orderBy` to filter which docs are retrieved and synced.
Just like Firestore, you can use `where` and `orderBy` to clauses which docs are retrieved and synced.

- *where:* arrays of "parameters" that get passed on to firestore's `.where(...parameters)`
- *orderBy:* a single "array" that gets passed on to firestore's `.orderBy(...array)`

There are three ways to use where and orderBy. As per example we will define `where` and `orderBy` variables first, then show how you can use them:

```js
const where = [ // an array of arrays
// an array of arrays
const where = [
['some_field', '==', false],
['another_field', '==', true],
]
const orderBy = ['created_at'] // or more params
// can have several parameters
const orderBy = ['created_at']
```

1. Pass together with openDBChannel:

```js
dispatch('myModule/openDBChannel', {where, orderBy})
dispatch('myModule/openDBChannel', {clauses: {where, orderBy}})
```

2. Pass together with fetchAndAdd:

```js
dispatch('myModule/fetchAndAdd', {where, orderBy})
dispatch('myModule/fetchAndAdd', {clauses: {where, orderBy}})
```

3. Define inside your vuex module, to set as default when for `openDBChannel`:
Expand Down Expand Up @@ -270,7 +311,7 @@ getters: {

### userId in where/orderBy

You can also use variables like `userId` (of the authenticated user) inside where filters. Eg.
You can also use variables like `userId` (of the authenticated user) inside where clauses. Eg.

```js
store.dispatch('myModule/openDBChannel', {
Expand All @@ -280,7 +321,7 @@ store.dispatch('myModule/openDBChannel', {

`{userId}` will be automatically replaced with the authenticated user id.

Besides `userId` you can also use "custom variables". For more information on this, see the chapter on [variables for firestorePath or filters](extra-features.html#variables-for-firestorepath-or-filters).
Besides `userId` you can also use "custom variables". For more information on this, see the chapter on [variables for firestorePath or clauses](extra-features.html#variables-for-firestorepath-or-clauses).

### Example usage: openDBChannel and fetchAndAdd

Expand Down Expand Up @@ -447,7 +488,7 @@ Please note, just like [fetchAndAdd](#fetching-docs) explained above, `fetch` al

```js
// custom fetch limit:
dispatch('myModule/fetch', {limit: 1000})
dispatch('myModule/fetch', {clauses: {limit: 1000}})
// no fetch limit:
dispatch('myModule/fetch', {limit: 0})
dispatch('myModule/fetch', {clauses: {limit: 0}})
```
56 changes: 28 additions & 28 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 6895c3c

Please sign in to comment.