Skip to content

Commit 2fce6ad

Browse files
committed
feat: add model $delete method
1 parent 6846934 commit 2fce6ad

File tree

7 files changed

+127
-17
lines changed

7 files changed

+127
-17
lines changed

src/model/Model.ts

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Store } from 'vuex'
22
import { isNullish, isArray, assert } from '../support/Utils'
33
import { Element, Item, Collection } from '../data/Data'
4+
import { Query } from '../query/Query'
45
import { NonEnumerable } from './decorators/NonEnumerable'
56
import { Attribute } from './attributes/Attribute'
67
import { Attr } from './attributes/types/Attr'
@@ -253,12 +254,10 @@ export class Model {
253254
}
254255

255256
/**
256-
* Set the store instance.
257+
* Get the model fields for this model.
257258
*/
258-
$setStore(store: Store<any>): this {
259-
this._store = store
260-
261-
return this
259+
get $fields(): ModelFields {
260+
return this.$self.schemas[this.$entity]
262261
}
263262

264263
/**
@@ -275,10 +274,19 @@ export class Model {
275274
}
276275

277276
/**
278-
* Get the model fields for this model.
277+
* Create a new query instance.
279278
*/
280-
get $fields(): ModelFields {
281-
return this.$self.schemas[this.$entity]
279+
$query(): Query<this> {
280+
return new Query(this.$store, this)
281+
}
282+
283+
/**
284+
* Set the store instance.
285+
*/
286+
$setStore(store: Store<any>): this {
287+
this._store = store
288+
289+
return this
282290
}
283291

284292
/**
@@ -450,6 +458,37 @@ export class Model {
450458
return this.$toJson(this, { relations: false })
451459
}
452460

461+
/**
462+
* Delete the model from the database.
463+
*/
464+
async $delete(): Promise<boolean> {
465+
const key = this.$getKeyName()
466+
467+
return isArray(key)
468+
? this.$deleteByCompositeKeyName(key)
469+
: this.$deleteByKeyName(key)
470+
}
471+
472+
/**
473+
* Delete the model from the database by ID.
474+
*/
475+
protected async $deleteByKeyName(key: string): Promise<boolean> {
476+
return !!(await this.$query().destroy(this[key]))
477+
}
478+
479+
/**
480+
* Delete the model from the database by composite key.
481+
*/
482+
protected async $deleteByCompositeKeyName(keys: string[]): Promise<boolean> {
483+
const query = this.$query()
484+
485+
keys.forEach((key) => {
486+
query.where(key, this[key])
487+
})
488+
489+
return (await query.delete()).length > 0
490+
}
491+
453492
/**
454493
* Serialize this model, or the given model, as POJO.
455494
*/

src/query/Options.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Model } from '../model/Model'
21
import { Query } from './Query'
32

43
export interface Where {
@@ -16,12 +15,12 @@ export interface WhereGroup {
1615
or?: Where[]
1716
}
1817

19-
export interface Order<M extends Model> {
20-
field: OrderBy<M>
18+
export interface Order {
19+
field: OrderBy
2120
direction: OrderDirection
2221
}
2322

24-
export type OrderBy<M extends Model> = string | ((model: M) => any)
23+
export type OrderBy = string | ((model: any) => any)
2524

2625
export type OrderDirection = 'asc' | 'desc'
2726

src/query/Query.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class Query<M extends Model = Model> {
6565
/**
6666
* The orderings for the query.
6767
*/
68-
protected orders: Order<M>[] = []
68+
protected orders: Order[] = []
6969

7070
/**
7171
* The maximum number of records to return.
@@ -150,7 +150,7 @@ export class Query<M extends Model = Model> {
150150
/**
151151
* Add an "order by" clause to the query.
152152
*/
153-
orderBy(field: OrderBy<M>, direction: OrderDirection = 'asc'): Query<M> {
153+
orderBy(field: OrderBy, direction: OrderDirection = 'asc'): Query<M> {
154154
this.orders.push({ field, direction })
155155

156156
return this
@@ -286,7 +286,7 @@ export class Query<M extends Model = Model> {
286286
/**
287287
* Get comparator for the where clause.
288288
*/
289-
protected getWhereComparator(): (model: M) => boolean {
289+
protected getWhereComparator(): (model: any) => boolean {
290290
const { and, or } = groupBy(this.wheres, (where) => where.boolean)
291291

292292
return (model) => {

src/repository/Repository.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export class Repository<M extends Model = Model> {
122122
/**
123123
* Add an "order by" clause to the query.
124124
*/
125-
orderBy(field: OrderBy<M>, direction?: OrderDirection): Query<M> {
125+
orderBy(field: OrderBy, direction?: OrderDirection): Query<M> {
126126
return this.query().orderBy(field, direction)
127127
}
128128

src/support/Utils.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,18 @@ interface SortableArray<T> {
44
value: T
55
}
66

7+
/**
8+
* Check if the given value is the type of null.
9+
*/
10+
export function isNull(value: any): value is null {
11+
return value === null
12+
}
13+
714
/**
815
* Check if the given value is the type of undefined or null.
916
*/
1017
export function isNullish(value: any): value is undefined | null {
11-
return value === undefined || value === null
18+
return value === undefined || isNull(value)
1219
}
1320

1421
/**
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { createStore, fillState, assertState } from 'test/Helpers'
2+
import { Model, Attr, Str } from '@/index'
3+
4+
describe('feature/model/deletes_delete', () => {
5+
class User extends Model {
6+
static entity = 'users'
7+
8+
@Attr() id!: any
9+
@Str('') name!: string
10+
}
11+
12+
it('deletes a record', async () => {
13+
const store = createStore()
14+
15+
fillState(store, {
16+
users: {
17+
1: { id: 1, name: 'John Doe' }
18+
}
19+
})
20+
21+
const user = store.$repo(User).find(1)!
22+
23+
const result = await user.$delete()
24+
25+
expect(result).toBe(true)
26+
27+
assertState(store, {
28+
users: {}
29+
})
30+
})
31+
})
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { createStore, fillState, assertState } from 'test/Helpers'
2+
import { Model, Attr, Str } from '@/index'
3+
4+
describe('feature/model/deletes_delete_composite_key', () => {
5+
class User extends Model {
6+
static entity = 'users'
7+
8+
static primaryKey = ['idA', 'idB']
9+
10+
@Attr() idA!: any
11+
@Attr() idB!: any
12+
@Str('') name!: string
13+
}
14+
15+
it('deletes a record', async () => {
16+
const store = createStore()
17+
18+
fillState(store, {
19+
users: {
20+
'[1,2]': { idA: 1, idB: 2, name: 'John Doe' }
21+
}
22+
})
23+
24+
const user = store.$repo(User).where('idA', 1).where('idB', 2).first()!
25+
26+
const result = await user.$delete()
27+
28+
expect(result).toBe(true)
29+
30+
assertState(store, {
31+
users: {}
32+
})
33+
})
34+
})

0 commit comments

Comments
 (0)