Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/content/1.guide/4.repository/2.retrieving-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,15 @@ You may also pass a function as the first argument. The function will accept a r
const users = useRepo(User).orderBy(user => user.name[2]).get()
```

You can also order many to many relations by their pivot data. To do that you need to use `useSortBy` helper right now.

````ts
const users = userRepo.with('roles').orderBy((user) => {
user.roles = useSortBy(user.roles, [['pivot.level', 'asc']])
}).get()

````

## Grouping

The `groupBy` method allows you to group your results by columns.
Expand Down
2 changes: 1 addition & 1 deletion packages/pinia-orm/.eslintcache

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,11 @@ export class BelongsToMany extends Relation {
relatedModels.forEach((relatedModel) => {
const pivot = pivotModels[`[${parentModel[this.parentKey]},${relatedModel[this.relatedKey]}]`]?.[0] ?? null

if (!pivot) { return }

const relatedModelCopy = relatedModel.$newInstance(relatedModel.$toJson())
relatedModelCopy.$setRelation('pivot', pivot)

if (pivot) { relationResults.push(relatedModelCopy) }
relationResults.push(relatedModelCopy)
})
parentModel.$setRelation(relation, relationResults)
})
Expand Down
13 changes: 10 additions & 3 deletions packages/pinia-orm/src/query/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,10 +463,19 @@ export class Query<M extends Model = Model> {
private internalGet (triggerHook: boolean): Collection<M> | GroupedCollection<M> {
if (this.model.$entity() !== this.model.$baseEntity()) { this.where(this.model.$typeKey(), this.model.$fields()[this.model.$typeKey()].make()) }

const models = this.select()
let models = this.select()

if (!this.orders) {
models = this.filterLimit(models)
}

if (!isEmpty(models)) { this.eagerLoadRelations(models) }

if (this.orders) {
models = this.filterOrder(models)
models = this.filterLimit(models)
}

if (triggerHook) { models.forEach(model => model.$self().retrieved(model)) }

if (this.groups.length > 0) { return this.filterGroup(models) }
Expand Down Expand Up @@ -508,8 +517,6 @@ export class Query<M extends Model = Model> {
let models = this.storeFind(ids)

models = this.filterWhere(models)
models = this.filterOrder(models)
models = this.filterLimit(models)

this.wheres = originalWheres

Expand Down
7 changes: 3 additions & 4 deletions packages/pinia-orm/src/support/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export function orderBy<T extends Element> (

const result = collection.map<SortableArray<T>>((value) => {
const criteria = iteratees.map((iteratee) => {
return typeof iteratee === 'function' ? iteratee(value) : value[iteratee]
return typeof iteratee === 'function' ? iteratee(value) : getValue(value, iteratee, false)
})

return { criteria, index: ++index, value }
Expand Down Expand Up @@ -240,14 +240,13 @@ export function generateKey (key: string, params?: any): string {
/**
* Get a value based on a dot-notation key.
*/
export function getValue (obj: Record<string, any>, keys: string | string[]): any {
export function getValue (obj: Record<string, any>, keys: string | string[], ifNotFoundReturnObject = true): any {
keys = (typeof keys === 'string') ? keys.split('.') : keys
const key = keys.shift() as string

// eslint-disable-next-line @stylistic/brace-style
if (obj && Object.prototype.hasOwnProperty.call(obj, key) && keys.length === 0) { return obj[key] }

else if (!obj || !Object.prototype.hasOwnProperty.call(obj, key)) { return obj } else { return getValue(obj[key], keys) }
else if (!obj || !Object.prototype.hasOwnProperty.call(obj, key)) { return ifNotFoundReturnObject ? obj : undefined } else { return getValue(obj[key], keys) }
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { describe, expect, it } from 'vitest'

import { Model, useRepo } from '../../../src'
import { Attr, Num, Str } from '../../../src/decorators'
import { Attr, BelongsToMany, Num, Str } from '../../../src/decorators'
import { assertInstanceOf, assertModels, fillState } from '../../helpers'
import { useSortBy } from '@/composables/collection/useSortBy'

describe('feature/repository/retrieves_order_by', () => {
class User extends Model {
Expand Down Expand Up @@ -112,4 +113,75 @@ describe('feature/repository/retrieves_order_by', () => {
assertInstanceOf(users, User)
assertModels(users, expected)
})

it('can sort nested records by pivot', () => {
Model.clearRegistries()
class User extends Model {
static entity = 'users'

@Attr() id!: number
@Str('') name!: string
@BelongsToMany(() => Role, () => RoleUser, 'user_id', 'role_id')
roles!: Role[]
}

class Role extends Model {
static entity = 'roles'

@Attr() id!: number
@BelongsToMany(() => User, () => RoleUser, 'role_id', 'user_id')
users!: User[]

pivot!: RoleUser
}

class RoleUser extends Model {
static entity = 'roleUser'

static primaryKey = ['role_id', 'user_id']

@Attr() role_id!: number
@Attr() user_id!: number
@Attr() level!: number
}
const userRepo = useRepo(User)

fillState({
users: {
1: { id: 1, name: 'James' },
2: { id: 2, name: 'Andy' },
3: { id: 3, name: 'David' },
},
roles: {
1: { id: 1 },
2: { id: 2 },
},
roleUser: {
'[1,1]': { role_id: 1, user_id: 1, level: 4 },
'[1,2]': { role_id: 1, user_id: 2, level: 3 },
'[2,1]': { role_id: 2, user_id: 1, level: 1 },
},
})

const users = userRepo.with('roles').orderBy((user) => {
user.roles = useSortBy(user.roles, [['pivot.level', 'asc']])
}).get()

const expected = [
{ id: 1, name: 'James', roles: [
{ id: 2, users: [], pivot_roleUser: null },
{ id: 1, users: [], pivot_roleUser: null },
],
},
{ id: 2, name: 'Andy', roles: [
{ id: 1, users: [], pivot_roleUser: null },
],
},
{ id: 3, name: 'David', roles: [] },
]

expect(users).toHaveLength(3)
assertInstanceOf(users, User)
assertModels(users, expected)
})
})