Skip to content

Commit

Permalink
fix(pinia-orm): Model original data is overwritten by different namsp…
Browse files Browse the repository at this point in the history
…ace models with same ID (#1954)

* Model original data isolation

* Fix linting issues in added tests.

resolves #1954
  • Loading branch information
petrmifek authored Nov 25, 2024
1 parent d780ce8 commit 15f5c42
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 3 deletions.
8 changes: 5 additions & 3 deletions packages/pinia-orm/src/model/Model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export class Model {
/**
* Original model data.
*/
protected static original: Record<string, any> = {}
protected static original: Record<string, Record<string, Element>> = {}

/**
* The schema for the model. It contains the result of the `fields`
Expand Down Expand Up @@ -825,7 +825,9 @@ export class Model {
this[key as keyof this] = this[key as keyof this] ?? keyValue
}

operation === 'set' && (this.$self().original[this.$getKey(this, true) as string] = this.$getAttributes())
operation === 'set' && (
(this.$self().original[this.$modelEntity()] ??= {})[this.$getKey(this, true) as string] = this.$getAttributes()
)

modelConfig.withMeta && operation === 'set' && this.$fillMeta(options.action)

Expand Down Expand Up @@ -1003,7 +1005,7 @@ export class Model {
* Get the original values of the model instance
*/
$getOriginal (): Element {
return this.$self().original[this.$getKey(this, true) as string]
return (this.$self().original[this.$modelEntity()] ??= {})[this.$getKey(this, true) as string]
}

/**
Expand Down
73 changes: 73 additions & 0 deletions packages/pinia-orm/tests/unit/model/Model_Isolation.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { describe, expect, it } from 'vitest'
import { Model } from '../../../src'
import { Attr } from '../../../src/decorators'

describe('unit/model/ModelIsolation', () => {
class User extends Model {
static entity = 'users'
@Attr() declare id: number
@Attr() declare name: string
}

class Post extends Model {
static entity = 'posts'
@Attr() declare id: number
@Attr() declare title: string
}

it('maintains separate original states for different model types with same id', () => {
const user = new User({ id: 1, name: 'John' })
const post = new Post({ id: 1, title: 'Hello' })

expect(user.$getOriginal()).toEqual({ id: 1, name: 'John' })
expect(post.$getOriginal()).toEqual({ id: 1, title: 'Hello' })
})

it('tracks changes independently for different model types', () => {
const user = new User({ id: 1, name: 'John' })
const post = new Post({ id: 1, title: 'Hello' })

user.name = 'Jane'
post.title = 'Updated'

expect(user.$isDirty()).toBeTruthy()
expect(post.$isDirty()).toBeTruthy()
expect(user.$getOriginal()).toEqual({ id: 1, name: 'John' })
expect(post.$getOriginal()).toEqual({ id: 1, title: 'Hello' })
})

it('refreshes to correct original state for each model type', () => {
const user = new User({ id: 1, name: 'John' })
const post = new Post({ id: 1, title: 'Hello' })

user.name = 'Jane'
post.title = 'Updated'

user.$refresh()
expect(user.name).toBe('John')
expect(post.title).toBe('Updated')

post.$refresh()
expect(post.title).toBe('Hello')
})

it('handles multiple instances of different models with same ids', () => {
const users = [
new User({ id: 1, name: 'John' }),
new User({ id: 2, name: 'Jane' }),
]

const posts = [
new Post({ id: 1, title: 'First' }),
new Post({ id: 2, title: 'Second' }),
]

users.forEach(u => u.name = `Updated ${u.name}`)
posts.forEach(p => p.title = `Updated ${p.title}`)

expect(users[0].$getOriginal()).toEqual({ id: 1, name: 'John' })
expect(users[1].$getOriginal()).toEqual({ id: 2, name: 'Jane' })
expect(posts[0].$getOriginal()).toEqual({ id: 1, title: 'First' })
expect(posts[1].$getOriginal()).toEqual({ id: 2, title: 'Second' })
})
})

0 comments on commit 15f5c42

Please sign in to comment.