Skip to content

Commit b386703

Browse files
committed
feat: instance hydration control
docs: added examples to reflect this feat test: added coverage test
1 parent f1d8e5f commit b386703

File tree

5 files changed

+81
-15
lines changed

5 files changed

+81
-15
lines changed

docs/api/model.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ sidebarDepth: 2
3131

3232
### `$softDelete`
3333

34-
- **Type**: `() => Promise`
34+
- **Type**: `(hydrate?: boolean) => Promise`
3535

36-
Soft delete the model instance. Updates the `key` and `flagName` attribute values accordingly.
36+
Soft delete the model instance. By default, this updates only the `key` and `flagName` attribute values on the instance after they are persisted to the store.
3737

38+
Passing `hydrate` as `true` will also hydrate the given instance. This is useful where there may be `beforeUpdate`/`afterUpdate` hooks on the model that may mutate other values or to simply update instance with the latest data from the store. However, if the instance has any relation attributes loaded through `with`, they will be reset during hydration.
39+
3840
Returns a Promise that resolves with the soft deleted model.
3941

4042
### `$trashed`

docs/guide/usage.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,24 @@ if (user.$trashed()) {
1919
Models can be soft deleted by calling `softDelete` directly:
2020

2121
```js
22-
User.softDelete(1)
22+
await User.softDelete(1)
2323
```
2424

25-
Model instances can be soft deleted by calling `$softDelete` on the model instance:
25+
Model instances can be soft deleted by calling `$softDelete` on the instance itself:
2626

2727
```js
2828
const user = User.find(1)
2929

30-
user.$softDelete()
30+
await user.$softDelete()
31+
```
32+
33+
The `$softDelete` instance method also accepts a `boolean` argument which can force hydration:
34+
35+
```js
36+
await user.$softDelete(true)
3137
```
3238

33-
Both methods are asynchronous and return a Promise.
39+
**See also**: [API Reference](/api/model.md#softdelete-2)
3440

3541
### Primary Key
3642

src/mixins/Model.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,36 +47,42 @@ export default function Model(
4747
/**
4848
* Trash the record on a model instance.
4949
*/
50-
model.prototype.$softDelete = async function() {
51-
const record = await this.$dispatch(
50+
model.prototype.$softDelete = async function(hydrate?) {
51+
const model = await this.$dispatch(
5252
'softDelete',
5353
this.$self().getIdFromRecord(this)
5454
)
5555

56+
if (hydrate) {
57+
this.$fill(model.$getAttributes())
58+
59+
return this
60+
}
61+
5662
const { key, flagName } = context.createConfig(
5763
this.$self().softDeleteConfig
5864
)
5965

60-
this[key] = record[key]
61-
this[flagName] = record[flagName]
66+
this[key] = model[key]
67+
this[flagName] = model[flagName]
6268

63-
return record
69+
return model
6470
}
6571

6672
/**
6773
* Trash the record on a model instance.
6874
* This method is deprecated and will warn users until retired.
6975
* @deprecated since v1.2.0
7076
*/
71-
model.prototype.softDelete = function() {
77+
model.prototype.softDelete = function(hydrate?) {
7278
/* istanbul ignore next */
7379
if (process.env.NODE_ENV !== 'production') {
7480
console.warn(
7581
'The `softDelete` instance method has been deprecated. Please use `$softDelete`.'
7682
)
7783
}
7884

79-
return this.$softDelete()
85+
return this.$softDelete(hydrate)
8086
}
8187

8288
/**

src/types/vuex-orm.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ declare module '@vuex-orm/core' {
3232
/**
3333
* Trash the record on a model instance.
3434
*/
35-
$softDelete(): Promise<Data.Item<this>>
35+
$softDelete(hydrate?: boolean): Promise<Data.Item<this>>
3636

3737
/**
3838
* Trash the record on a model instance.
3939
* @deprecated since v1.2.0
4040
*/
41-
softDelete(): Promise<Data.Item<this>>
41+
softDelete(hydrate?: boolean): Promise<Data.Item<this>>
4242

4343
/**
4444
* Determine if the instance has been trashed.

test/feature/model/Delete.spec.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,56 @@ describe('Feature - Model - Delete', () => {
294294
expect(user.$isDeleted).toBe(true)
295295
expect(user.deleted_at).toBe(mockDate)
296296
})
297+
298+
it('should hydrate instance after deleting', async () => {
299+
class User extends Model {
300+
static entity = 'users'
301+
302+
name!: string
303+
post!: Post
304+
deleted_at!: number
305+
$isDeleted!: boolean
306+
307+
static fields() {
308+
return {
309+
id: this.attr(null),
310+
name: this.attr(''),
311+
post: this.hasOne(Post, 'user_id')
312+
}
313+
}
314+
315+
static beforeUpdate(model: User) {
316+
model.name = 'Jane Doe'
317+
}
318+
}
319+
320+
class Post extends Model {
321+
static entity = 'posts'
322+
323+
static fields() {
324+
return {
325+
id: this.attr(null),
326+
user_id: this.attr(null)
327+
}
328+
}
329+
}
330+
331+
createStore([User, Post])
332+
333+
await User.insert({
334+
data: { id: 1, name: 'John Doe', post: [{ id: 2 }, { id: 3 }] }
335+
})
336+
337+
const user = User.query().with('post').find(1) as User
338+
339+
expect(user.name).toBe('John Doe')
340+
expect(user.post).toBeInstanceOf(Post)
341+
342+
await user.$softDelete(true)
343+
344+
expect(user.$isDeleted).toBe(true)
345+
expect(user.deleted_at).toBe(mockDate)
346+
expect(user.name).toBe('Jane Doe')
347+
expect(user.post).toBeNull()
348+
})
297349
})

0 commit comments

Comments
 (0)