Skip to content

Commit 7a32aec

Browse files
authored
fix(pinia-orm): scope decorator mutators, casts & hidden fields per entity (#2027)
Mutators, casts and hidden fields registered via setMutator/setCast/ setHidden (and thus via the Mutate, Cast and Hidden decorators) were stored on shared static objects of the base Model class, keyed only by field name. A mutation registered for one entity was therefore applied to every entity that has a field with the same name. They are now keyed by entity, like the schema registries already are. fixes #1937 fixes #1992
1 parent 222e106 commit 7a32aec

4 files changed

Lines changed: 105 additions & 8 deletions

File tree

packages/pinia-orm/src/model/Model.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,14 @@ export class Model {
147147
protected static piniaExtend = {}
148148

149149
/**
150-
* The mutators for the model.
150+
* The mutators for the model, keyed by entity.
151151
*/
152-
protected static fieldMutators: Mutators = {}
152+
protected static fieldMutators: Record<string, Mutators> = {}
153153

154154
/**
155-
* The casts for the model.
155+
* The casts for the model, keyed by entity.
156156
*/
157-
protected static fieldCasts: Record<string, any> = {}
157+
protected static fieldCasts: Record<string, Casts> = {}
158158

159159
/**
160160
* The array of booted models.
@@ -247,7 +247,8 @@ export class Model {
247247
key: string,
248248
mutator: MutatorFunctions<any>,
249249
): M {
250-
this.fieldMutators[key] = mutator
250+
this.fieldMutators[this.modelEntity()] = this.fieldMutators[this.modelEntity()] ?? {}
251+
this.fieldMutators[this.modelEntity()][key] = mutator
251252

252253
return this
253254
}
@@ -260,7 +261,8 @@ export class Model {
260261
key: string,
261262
to: typeof CastAttribute,
262263
): M {
263-
this.fieldCasts[key] = to
264+
this.fieldCasts[this.modelEntity()] = this.fieldCasts[this.modelEntity()] ?? {}
265+
this.fieldCasts[this.modelEntity()][key] = to
264266

265267
return this
266268
}
@@ -272,6 +274,7 @@ export class Model {
272274
this: M,
273275
key: keyof ModelFields,
274276
): M {
277+
if (!Object.prototype.hasOwnProperty.call(this, 'hidden')) { this.hidden = [...this.hidden] }
275278
this.hidden.push(key)
276279

277280
return this
@@ -781,7 +784,7 @@ export class Model {
781784
$casts (): Casts {
782785
return {
783786
...this.$getCasts(),
784-
...this.$self().fieldCasts,
787+
...this.$self().fieldCasts[this.$modelEntity()],
785788
}
786789
}
787790

@@ -802,7 +805,7 @@ export class Model {
802805
const fillRelation = options.relations ?? true
803806
const mutators: Mutators = {
804807
...this.$getMutators(),
805-
...this.$self().fieldMutators,
808+
...this.$self().fieldMutators[this.$modelEntity()],
806809
}
807810

808811
for (const key in fields) {

packages/pinia-orm/tests/unit/model/Model_Casts_Custom.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,30 @@ describe('unit/model/Model_Casts_Custom', () => {
7272
expect(new User().name).toBe('string test')
7373
})
7474

75+
it('should keep decorator casts of same named fields separate between entities', () => {
76+
class UpperCast extends CastAttribute {
77+
get (value?: any): any {
78+
return typeof value === 'string' ? value.toUpperCase() : value
79+
}
80+
}
81+
82+
class User extends Model {
83+
static entity = 'users'
84+
85+
@Cast(() => UpperCast)
86+
@Attr('') name!: string
87+
}
88+
89+
class Group extends Model {
90+
static entity = 'groups'
91+
92+
@Attr('') name!: string
93+
}
94+
95+
expect(new User({ name: 'John' }, { operation: 'get' }).name).toBe('JOHN')
96+
expect(new Group({ name: 'John' }, { operation: 'get' }).name).toBe('John')
97+
})
98+
7599
it('should cast with parameter', () => {
76100
class CustomCast extends CastAttribute {
77101
static parameters = {

packages/pinia-orm/tests/unit/model/Model_Hidden_Field.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,28 @@ describe('unit/model/Model_Hidden_Field', () => {
3636
expect(user.username).toBe(undefined)
3737
})
3838

39+
it('should only hide the field on the entity using the decorator', () => {
40+
class User extends Model {
41+
static entity = 'users'
42+
43+
@Str('') declare name: string
44+
@Hidden() @Str('') declare username: string
45+
}
46+
47+
class Account extends Model {
48+
static entity = 'accounts'
49+
50+
@Str('') declare name: string
51+
@Str('') declare username: string
52+
}
53+
54+
const user = new User({ name: 'Test', username: 'John' }, { operation: 'get' })
55+
const account = new Account({ name: 'Test', username: 'John' }, { operation: 'get' })
56+
57+
expect(user.username).toBe(undefined)
58+
expect(account.username).toBe('John')
59+
})
60+
3961
it('should hide the field with "visible"', () => {
4062
class User extends Model {
4163
static entity = 'users'

packages/pinia-orm/tests/unit/model/Model_Mutators.spec.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,54 @@ describe('unit/model/Model_Mutators', () => {
3939
expect(new User({ name: 'john doe' }, { operation: 'get' }).name).toBe('JOHN DOE')
4040
})
4141

42+
it('should keep decorator mutators of same named fields separate between entities', () => {
43+
class User extends Model {
44+
static entity = 'users'
45+
46+
@Mutate((value: any) => value.toUpperCase())
47+
@Attr('')
48+
firstName!: string
49+
}
50+
51+
class Contact extends Model {
52+
static entity = 'contacts'
53+
54+
@Mutate((value: any) => value.toLowerCase())
55+
@Attr('')
56+
firstName!: string
57+
}
58+
59+
expect(new User({ firstName: 'John' }, { operation: 'get' }).firstName).toBe('JOHN')
60+
expect(new Contact({ firstName: 'John' }, { operation: 'get' }).firstName).toBe('john')
61+
})
62+
63+
it('should only apply mutators added with "setMutator" to the model they were set on', () => {
64+
class User extends Model {
65+
static entity = 'users'
66+
67+
@Attr(0) id!: number
68+
@Attr('') title!: string
69+
}
70+
71+
class Todo extends Model {
72+
static entity = 'todos'
73+
74+
@Attr(0) id!: number
75+
@Attr('') title!: string
76+
}
77+
78+
Todo.setMutator('title', { get: (value: any) => value.toUpperCase() })
79+
80+
const userRepo = useRepo(User)
81+
const todoRepo = useRepo(Todo)
82+
83+
userRepo.save({ id: 1, title: 'user title' })
84+
todoRepo.save({ id: 1, title: 'todo title' })
85+
86+
expect(todoRepo.find(1)?.title).toBe('TODO TITLE')
87+
expect(userRepo.find(1)?.title).toBe('user title')
88+
})
89+
4290
it('should mutate data if mutators with getter are present', () => {
4391
class User extends Model {
4492
static entity = 'users'

0 commit comments

Comments
 (0)