Skip to content

Commit

Permalink
fix: compare DateTime in newUpIfMissing
Browse files Browse the repository at this point in the history
  • Loading branch information
adamcikado committed May 1, 2024
1 parent 42b46f3 commit 669bdb3
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 17 deletions.
36 changes: 20 additions & 16 deletions src/orm/base_model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
*/

import { DateTime } from 'luxon'
import equal from 'fast-deep-equal'
import Hooks from '@poppinss/hooks'
import lodash from '@poppinss/utils/lodash'
import { Exception, defineStaticProperty } from '@poppinss/utils'
Expand Down Expand Up @@ -63,6 +62,8 @@ import {
ensureRelation,
managedTransaction,
normalizeCherryPickObject,
transformDateValue,
compareValues,
} from '../../utils/index.js'

const MANY_RELATIONS = ['hasMany', 'manyToMany', 'hasManyThrough']
Expand Down Expand Up @@ -207,9 +208,13 @@ class BaseModelImpl implements LucidRow {
* array
*/
return rowObjects.map((rowObject: any) => {
const existingRow = existingRows.find((one: any) => {
/* eslint-disable-next-line eqeqeq */
return keys.every((key) => one[key] == rowObject[key])
const existingRow = existingRows.find((row: any) => {
return keys.every((key) => {
const objectValue = rowObject[key]
const rowValue = row[key]

return compareValues(rowValue, objectValue)
})
})

/**
Expand Down Expand Up @@ -852,6 +857,8 @@ class BaseModelImpl implements LucidRow {
payload: any,
options?: ModelAssignOptions
): Promise<any[]> {
const client = this.$adapter.modelConstructorClient(this as LucidModel, options)

uniqueKeys = Array.isArray(uniqueKeys) ? uniqueKeys : [uniqueKeys]
const uniquenessPair: { key: string; value: string[] }[] = uniqueKeys.map(
(uniqueKey: string) => {
Expand All @@ -861,7 +868,7 @@ class BaseModelImpl implements LucidRow {
throw new Exception(
`Value for the "${uniqueKey}" is null or undefined inside "fetchOrNewUpMany" payload`
)
}),
}).map((value) => transformDateValue(value, client.dialect)),
}
}
)
Expand Down Expand Up @@ -896,6 +903,8 @@ class BaseModelImpl implements LucidRow {
payload: any,
options?: ModelAssignOptions
): Promise<any[]> {
const client = this.$adapter.modelConstructorClient(this as LucidModel, options)

uniqueKeys = Array.isArray(uniqueKeys) ? uniqueKeys : [uniqueKeys]
const uniquenessPair: { key: string; value: string[] }[] = uniqueKeys.map(
(uniqueKey: string) => {
Expand All @@ -905,7 +914,7 @@ class BaseModelImpl implements LucidRow {
throw new Exception(
`Value for the "${uniqueKey}" is null or undefined inside "fetchOrCreateMany" payload`
)
}),
}).map((value) => transformDateValue(value, client.dialect)),
}
}
)
Expand Down Expand Up @@ -960,6 +969,8 @@ class BaseModelImpl implements LucidRow {
payload: any,
options?: ModelAssignOptions
): Promise<any> {
const client = this.$adapter.modelConstructorClient(this as LucidModel, options)

uniqueKeys = Array.isArray(uniqueKeys) ? uniqueKeys : [uniqueKeys]
const uniquenessPair: { key: string; value: string[] }[] = uniqueKeys.map(
(uniqueKey: string) => {
Expand All @@ -969,13 +980,11 @@ class BaseModelImpl implements LucidRow {
throw new Exception(
`Value for the "${uniqueKey}" is null or undefined inside "updateOrCreateMany" payload`
)
}),
}).map((value) => transformDateValue(value, client.dialect)),
}
}
)

const client = this.$adapter.modelConstructorClient(this as LucidModel, options)

return managedTransaction(client, async (trx) => {
/**
* Find existing rows
Expand Down Expand Up @@ -1287,15 +1296,10 @@ class BaseModelImpl implements LucidRow {
const originalValue = this.$original[key]
let isEqual = true

if (DateTime.isDateTime(value) || DateTime.isDateTime(originalValue)) {
isEqual =
DateTime.isDateTime(value) && DateTime.isDateTime(originalValue)
? value.equals(originalValue)
: value === originalValue
} else if (isObject(value) && 'isDirty' in value) {
if (isObject(value) && 'isDirty' in value) {
isEqual = !value.isDirty
} else {
isEqual = equal(originalValue, value)
isEqual = compareValues(originalValue, value)
}

if (!isEqual) {
Expand Down
33 changes: 32 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@ import { join, extname } from 'node:path'
import { Exception, fsReadAll, isScriptFile } from '@poppinss/utils'
import { RelationshipsContract } from '../types/relations.js'
import { LucidRow, ModelObject, CherryPickFields } from '../types/model.js'
import { FileNode, QueryClientContract, TransactionClientContract } from '../types/database.js'
import {
DialectContract,
FileNode,
QueryClientContract,
TransactionClientContract,
} from '../types/database.js'
import { fileURLToPath, pathToFileURL } from 'node:url'
import * as errors from '../errors.js'
import { DateTime } from 'luxon'
import equal from 'fast-deep-equal'

/**
* Ensure that relation is defined
Expand Down Expand Up @@ -53,6 +60,30 @@ export function collectValues(payload: any[], key: string, missingCallback: () =
})
}

/**
* Transform value if it is an instance of DateTime, so it can be processed by query builder
*/
export function transformDateValue(value: unknown, dialect: DialectContract) {
if (DateTime.isDateTime(value)) {
return value.toFormat(dialect.dateTimeFormat)
}

return value
}

/**
* Compare two values deeply whether they are equal or not
*/
export function compareValues(valueA: unknown, valueB: unknown) {
if (DateTime.isDateTime(valueA) || DateTime.isDateTime(valueB)) {
return DateTime.isDateTime(valueA) && DateTime.isDateTime(valueB)
? valueA.equals(valueB)
: valueA === valueB
} else {
return equal(valueA, valueB)
}
}

/**
* Raises exception when a relationship `booted` property is false.
*/
Expand Down
62 changes: 62 additions & 0 deletions test/orm/base_model.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4888,6 +4888,68 @@ test.group('Base Model | fetch', (group) => {
assert.lengthOf(usersList, 1)
assert.equal(usersList[0].points, 2)
})

test('updateOrCreateMany should work with DateTime', async ({ fs, assert }) => {
const app = new AppFactory().create(fs.baseUrl, () => {})
await app.init()
const db = getDb()
const adapter = ormAdapter(db)

const BaseModel = getBaseModel(adapter)

class User extends BaseModel {
@column({ isPrimary: true })
declare id: number

@column()
declare username: string

@column()
declare email: string

@column.dateTime()
declare createdAt: DateTime
}

const createdAt1 = DateTime.now().minus({ days: 2 }).startOf('second')
const createdAt2 = DateTime.now().minus({ days: 1 }).startOf('second')

await User.createMany([
{
username: 'virk1',
email: '[email protected]',
createdAt: createdAt1,
},
{
username: 'virk2',
email: '[email protected]',
createdAt: createdAt2,
},
])

const users = await User.updateOrCreateMany('createdAt', [
{
username: 'virk3',
email: '[email protected]',
createdAt: createdAt1,
},
{
username: 'nikk',
email: '[email protected]',
createdAt: DateTime.now(),
},
])

assert.lengthOf(users, 2)
assert.isTrue(users[0].$isPersisted)
assert.isFalse(users[0].$isLocal)

assert.isTrue(users[1].$isPersisted)
assert.isTrue(users[1].$isLocal)

const usersList = await db.query().from('users')
assert.lengthOf(usersList, 3)
})
})

test.group('Base Model | hooks', (group) => {
Expand Down

0 comments on commit 669bdb3

Please sign in to comment.