You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/guide/data/cache.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -89,7 +89,7 @@ You can also use the `store.<collectionName>.clearItem` method:
89
89
store.User.clearItem('abc')
90
90
```
91
91
92
-
## Layers
92
+
## Layers <Badgetext="New in v0.7" />
93
93
94
94
A cache layer is a way to create a temporary state modification that can be easily reverted. This is how [optimistic updates](./mutation.md#optimistic-updates) are implemented.
Copy file name to clipboardExpand all lines: docs/guide/data/live.md
+7-7Lines changed: 7 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,20 +2,20 @@
2
2
3
3
rstore provides a set of methods to help build realtime applications. Plugins can use [the relevant hooks](../plugin/hooks.md#subscriptions) to connect to WebSockets, Server-Sent Events, or any other realtime protocol.
4
4
5
-
## Subscribe
5
+
## Subscribe <Badgetext="Changed in v0.7"type="warning" />
6
6
7
7
Subscriptions are a way to listen for changes in the data store. You can subscribe to a specific collection and plugins will update the store in realtime. You can pass the same parameters than in the [queries](./query.md).
8
8
9
9
```ts
10
10
const store =useStore()
11
11
12
-
store.ChatMessage.subscribe({
12
+
store.ChatMessage.subscribe(q=>q({
13
13
params: {
14
14
filter: {
15
15
roomId: 'room1',
16
16
},
17
17
},
18
-
})
18
+
}))
19
19
```
20
20
21
21
## Unsubscribe
@@ -39,21 +39,21 @@ const { meta } = store.ChatMessage.subscribe()
39
39
console.log(meta.value)
40
40
```
41
41
42
-
## Live Query
42
+
## Live Query <Badgetext="Changed in v0.7"type="warning" />
43
43
44
44
You can use the `liveQueryFirst` and `liveQueryMany` methods to do both a query and a subscription at the same time.
45
45
46
46
```ts
47
-
const { data: user } =store.User.liveQueryFirst('some-id')
47
+
const { data: user } =store.User.liveQuery(q=>q.first('some-id'))
Copy file name to clipboardExpand all lines: docs/guide/data/module.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,4 +1,4 @@
1
-
# Module
1
+
# Module <Badgetext="Changed in v0.7"type="warning" />
2
2
3
3
In most application, there are cases where some specific logic or state is needed. For example, you may want to handle the current user with a specific key and also have special mutations for login or logout.
Awaiting a module is always optional. You can use the module without awaiting it, but all necessary code might not have run yet. This is a valid use case if you don't use async component setup for example.
181
181
:::
182
182
183
-
## Mutations
183
+
## Mutations <Badgetext="Changed in v0.7"type="warning" />
184
184
185
185
You can define mutations using the `defineMutation` function from the module setup function. This is useful for defining actions that modify the state of the module or the store in general.
You can also use the `createForm` method to create a new record. This method returns a form object that you can use to manage the state of the form and submit it when you're ready. See [Forms](./form.md#create-form) for more details.
16
+
:::
17
+
18
+
## Create Many <Badgetext="New in v0.7.3" />
19
+
20
+
You can create many items at once by using the `createMany` method on the store. This method takes an array of objects with the properties of the records you want to create.
21
+
22
+
```ts
23
+
const newTodos =awaitstore.todos.createMany([
24
+
{ title: 'New Todo 1', completed: false },
25
+
{ title: 'New Todo 2', completed: false },
26
+
])
27
+
```
28
+
29
+
It can be useful to batch the create operations into a single fetch request to your backend. See `createMany` in the [plugin hooks](../plugin/hooks.md#createmany).
30
+
14
31
## Update
15
32
16
33
To update an existing record, you can use the `update` method on the store. This method takes an object with the properties you want to update and the key of the record you want to update.
@@ -58,6 +75,23 @@ async function toggle() {
58
75
}
59
76
```
60
77
78
+
::: tip
79
+
You can also use the `updateForm` method to update an existing record. This method returns a form object that you can use to manage the state of the form and submit it when you're ready. See [Forms](./form.md#update-form) for more details.
80
+
:::
81
+
82
+
## Update Many <Badgetext="New in v0.7.3" />
83
+
84
+
You can update many items at once by using the `updateMany` method on the store. This method takes an array of objects with the properties you want to update. Each object must contain the key (or the properties used to [compute the key](../schema/collection.md#item-key)) of the record you want to update.
85
+
86
+
```ts
87
+
const updatedTodos =awaitstore.todos.updateMany([
88
+
{ id: 'id-1', completed: true },
89
+
{ id: 'id-2', completed: true },
90
+
])
91
+
```
92
+
93
+
It can be useful to batch the update operations into a single fetch request to your backend. See `updateMany` in the [plugin hooks](../plugin/hooks.md#updatemany).
94
+
61
95
## Delete
62
96
63
97
To delete a record, you can use the `delete` method on the store. This method takes the key of the record you want to delete.
@@ -94,7 +128,17 @@ if (todo) {
94
128
}
95
129
```
96
130
97
-
## Optimistic Updates
131
+
## Delete Many <Badgetext="New in v0.7.3" />
132
+
133
+
You can delete many items at once by using the `deleteMany` method on the store. This method takes an array of keys or objects that contain the keys of the records you want to delete.
134
+
135
+
```ts
136
+
awaitstore.todos.deleteMany(['id-1', 'id-2'])
137
+
```
138
+
139
+
It can be useful to batch the delete operations into a single fetch request to your backend. See `deleteMany` in the [plugin hooks](../plugin/hooks.md#deletemany).
140
+
141
+
## Optimistic Updates <Badgetext="New in v0.7" />
98
142
99
143
By default, rstore will try to perform optimistic updates when you create, update or delete a record. This means that the record will be updated in the store immediately, without waiting for the server to confirm the change. If an error is thrown during the mutation, the change will be automatically reverted.
## Query composables <Badgetext="Changed in v0.7"type="warning" />
20
20
21
21
The query composables are the recommended way to fetch data from the server. They are designed to be used in a Vue component and return a reactive result to be used in the components.
22
22
@@ -379,7 +379,7 @@ The cache will automatically resolve the relations as soon as the data is availa
379
379
380
380
Plugins hooked on the `fetchRelations` hook will also be called to potentially fetch the data of the relations. See [Plugin hooks](../plugin/hooks.md#fetching-relations) for more details.
381
381
382
-
## Customizing Find Options Types
382
+
## Customizing Find Options Types <Badgetext="Changed in v0.7"type="warning" />
383
383
384
384
You can customize the `FindOptions` type used in the `first` and `many` query builder methods and in the `peek*`/`find*` methods by declaring a module augmentation for `@rstore/vue` and extending the `FindOptions` interface.
This hook is called when rstore needs to create many new items at once when [`createMany()`](../data/mutation.md#create-many) is used.
216
+
217
+
::: tip
218
+
If no `createMany` hook is defined, rstore will fallback to calling the [`createItem`](#createitem) hook for each item in the array. If hooks for `createMany` are defined but none of them [aborts](#aborting), rstore will also fallback to calling the `createItem` hook for each item. Calling `abort()` or `setResult(value)` with a non-empty array in the `createMany` hook will prevent this behavior.
219
+
:::
220
+
221
+
```ts
222
+
hook('createMany', async (payload) => {
223
+
const result =awaitfetch(`/api/${payload.collection.name}/batch`, {
224
+
method: 'POST',
225
+
headers: {
226
+
'Content-Type': 'application/json',
227
+
},
228
+
body: JSON.stringify(payload.items),
229
+
}).then(r=>r.json())
230
+
payload.setResult(result)
231
+
})
232
+
```
233
+
213
234
### updateItem
214
235
215
236
This hook is called when rstore needs to update an existing item.
This hook is called when rstore needs to update many existing items at once when [`updateMany()`](../data/mutation.md#update-many) is used.
293
+
294
+
::: tip
295
+
If no `updateMany` hook is defined, rstore will fallback to calling the [`updateItem`](#updateitem) hook for each item in the array. If hooks for `updateMany` are defined but none of them [aborts](#aborting), rstore will also fallback to calling the `updateItem` hook for each item. Calling `abort()` or `setResult(value)` with a non-empty array in the `updateMany` hook will prevent this behavior.
296
+
:::
297
+
298
+
::: danger
299
+
300
+
Contrary to `createMany` hook, the `updateMany` hook receives an array of items that already contain their keys:
301
+
302
+
```ts
303
+
interfacePayload {
304
+
items:Array<{ key:string|number, item:any }>
305
+
/// ...
306
+
}
307
+
```
308
+
309
+
:::
310
+
311
+
```ts
312
+
hook('updateMany', async (payload) => {
313
+
const result =awaitfetch(`/api/${payload.collection.name}/batch`, {
If you have multiple plugins that can handle the same collections, you can abort the remaining callbacks for a *Data handling* hook by calling `abort()` on the payload.
For `fetchFirst`, `fetchMany`, `createItem` and `updateItem`, the remaining callbacks are automatically aborted when a non-null result is set with `setResult`. You can override this behavior by passing `{ abort: false }` as the second argument to `setResult`.
394
+
For `fetchFirst`, `fetchMany`, `createItem` and `updateItem`, the remaining callbacks are automatically aborted when a non-null result is set with `setResult`.
395
+
396
+
```ts
397
+
pluginApi.hook('fetchFirst', async (payload) => {
398
+
// If the item is non-null,
399
+
// remaining `fetchFirst` hooks will not be called
400
+
payload.setResult(cache.get(payload.key))
401
+
// If `cache.get(payload.key)` is null,
402
+
// remaining `fetchFirst` hooks will be called
403
+
})
404
+
```
405
+
406
+
Note that in the above example, adding a condition to call `setResult` is not necessary because it checks if the value is null or empty (for arrays) before aborting the remaining callbacks.
407
+
408
+
You can prevent this behavior by setting `abort: false` to the second argument of `setResult()`.
Explore the [Plugin hooks](./hooks.md) for a complete list of available hooks.
131
131
132
+
### Aborting hook <Badgetext="New in v0.7" />
133
+
134
+
You can abort most the hooks by calling either `setResult()` with a non-null/non-empty value, or `abort()`. This will prevent the remaining plugins from running the same hook. This is useful when you want to short-circuit the data flow, for example when you have a cache plugin that can return the data without needing to call a remote API.
135
+
136
+
```ts
137
+
pluginApi.hook('fetchFirst', async (payload) => {
138
+
// If the item is non-null,
139
+
// remaining `fetchFirst` hooks will not be called
140
+
payload.setResult(cachedmyCache.get(payload.key))
141
+
})
142
+
```
143
+
144
+
::: tip
145
+
You can prevent this behavior by setting `abort: false` to the second argument of `setResult()`.
if (payload.collection.name==='SomeSpecialCollection') {
156
+
// Do something special here
157
+
awaitdoSomethingSpecial()
158
+
// Remaining `fetchFirst` hooks will not be called
159
+
payload.abort()
160
+
}
161
+
})
162
+
```
163
+
164
+
See also [Category](#category) and [Sorting plugins](#sorting-plugins). Learn more in [Hooks](./hooks.md#aborting).
165
+
132
166
## Scope ID
133
167
134
168
The scope ID allows filtering which plugins will handle the collection. For example, if a collection has a scope A, only plugins with the scope A will be able to handle it by default. This is very useful to handle multiple data sources.
@@ -190,7 +224,7 @@ export default definePlugin({
190
224
})
191
225
```
192
226
193
-
## Sorting plugins
227
+
## Sorting plugins <Badgetext="New in v0.7" />
194
228
195
229
Plugins are sorted based on their dependencies and category. You can specify that a plugin should be loaded before or after another plugin or category using the `before` and `after` options:
Copy file name to clipboardExpand all lines: docs/guide/schema/collection.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -40,7 +40,7 @@ const store = await createStore({
40
40
41
41
:::
42
42
43
-
## Defining a Collection
43
+
## Defining a Collection <Badgetext="Changed in v0.7"type="warning" />
44
44
45
45
For JavaScript, you can use the `defineCollection` utility function to define a collection with auto-completion in your IDE:
46
46
@@ -88,7 +88,7 @@ const store = await createStore({
88
88
The [currying](https://en.wikipedia.org/wiki/Currying) is necessary to specify the type of the item while still letting TypeScript infer the type of the collection. This is a limitation of TypeScript, and [it might improve in the future](https://github.com/microsoft/TypeScript/issues/26242).
89
89
:::
90
90
91
-
## Collection hooks
91
+
## Collection hooks <Badgetext="New in v0.7" />
92
92
93
93
You can define hooks on the collection that will be called at different stages of the item lifecycle in the `hooks` option. The available hooks are:
0 commit comments