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
2 changes: 1 addition & 1 deletion packages/pinia-orm/.eslintcache

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/pinia-orm/src/model/Model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert, equals, isArray, isNullish, throwError } from '../support/Utils'
import { assert, equals, isArray, isDate, isNullish, throwError } from '../support/Utils'
import type { Collection, Element, Item } from '../data/Data'
import type { MutatorFunctions, Mutators } from '../types'
import type { ModelConfigOptions } from '../store/Store'
Expand Down Expand Up @@ -1034,7 +1034,7 @@ export class Model {
if (typeof value === 'object') {
// If the value is an object, check if it's an instance of Date and that it has
// a time value with its getTime() method, and that its toISOString() method exists
if (value instanceof Date && !Number.isNaN(value.getTime()) && typeof value.toISOString === 'function') { return value.toISOString() } else {
if (isDate(value)) { return value.toISOString() } else {
// If it's not a Date object, serialize the object using the default method
return this.serializeObject(value)
}
Expand Down
6 changes: 4 additions & 2 deletions packages/pinia-orm/src/model/casts/DateCast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ export class DateCast extends CastAttribute {
* Make the value for the attribute.
*/

set (value: string | Date | null): string | null {
set (value: string | number | Date | null): string | null {
if (value === null) { return null }

return ((typeof value === 'string') ? new Date(Date.parse(value)) : value).toISOString()
if (typeof value === 'number') { return new Date(value).toISOString() }
if (typeof value === 'string') { return new Date(Date.parse(value)).toISOString() }
return value.toISOString()
}
}
11 changes: 10 additions & 1 deletion packages/pinia-orm/src/support/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ export function isNullish (value: any): value is undefined | null {
return value === undefined || value === null
}

/**
* Check if the given value is a Date object.
*/
export function isDate (value: any): value is Date {
return value instanceof Date && !Number.isNaN(value.getTime()) && typeof value.toISOString === 'function'
}

/**
* Check if the given value is the type of array.
*/
Expand Down Expand Up @@ -75,7 +82,9 @@ export function orderBy<T extends Element> (

const result = collection.map<SortableArray<T>>((value) => {
const criteria = iteratees.map((iteratee) => {
return typeof iteratee === 'function' ? iteratee(value) : getValue(value, iteratee, false)
if (typeof iteratee === 'function') { return iteratee(value) }
const newValue = getValue(value, iteratee, false)
return isDate(newValue) ? new Date(newValue).getTime() : newValue
})

return { criteria, index: ++index, value }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { describe, expect, it } from 'vitest'

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

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

it('can sort records by Date using the `orderBy` modifier', () => {
Model.clearRegistries()
class User extends Model {
static entity = 'users'

@Attr() id!: any
@Str('') name!: string
@Num(0) age!: number
@Cast(() => DateCast) @Attr(null) declare createdAt: Date
}

const userRepo = useRepo(User)

fillState({
users: {
1: { id: 1, name: 'James', age: 40, createdAt: new Date ('2023-01-26').toISOString() },
2: { id: 2, name: 'Andy', age: 30, createdAt: new Date ('2023-01-25').toISOString() },
3: { id: 3, name: 'David', age: 20, createdAt: new Date ('2023-03-26').toISOString() },
},
})

const users = userRepo.orderBy('createdAt').get()

const expected = [
{ id: 2, name: 'Andy', age: 30, createdAt: new Date ('2023-01-25').toISOString() },
{ id: 1, name: 'James', age: 40, createdAt: new Date ('2023-01-26').toISOString() },
{ id: 3, name: 'David', age: 20, createdAt: new Date ('2023-03-26').toISOString() },
]

expect(users).toHaveLength(3)
assertInstanceOf(users, User)
assertModels(users, expected)
})
})
13 changes: 13 additions & 0 deletions packages/pinia-orm/tests/unit/model/Model_Casts_Date.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ describe('unit/model/Model_Casts_Date', () => {
expect(new User({ updated: null }, { operation: 'set' }).updated).toBe(null)
})

it('should allow cast with number', () => {
class User extends Model {
static entity = 'users'

@Cast(() => DateCast)
@Attr('test')
declare updated: Date
}

expect(new User({ updated: 1714849419 }, { operation: 'get' }).updated).toStrictEqual(new Date(1714849419))
expect(new User({ updated: 1214849419 }, { operation: 'set' }).updated).toBe(new Date(1214849419).toISOString())
})

it('should cast before saved into store', () => {
const expectedIsoDate2 = new Date('2023-01-26')

Expand Down