Skip to content

Commit

Permalink
Issue kotlin-orm#466 - Consistent updates of nullable properties
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivan Georgiev authored and Ivan Georgiev committed Dec 21, 2022
1 parent 85647c0 commit 186a012
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ internal class EntityImplementation(
throw UnsupportedOperationException(msg)
}

values[name] = value
values.compute(name) { _, _ -> value }

changedProperties.add(name)
}

Expand Down
97 changes: 93 additions & 4 deletions ktorm-core/src/test/kotlin/org/ktorm/entity/EntityTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import java.io.ObjectOutputStream
import java.time.LocalDate
import java.util.*
import kotlin.reflect.jvm.jvmErasure
import kotlin.test.assertNotNull
import kotlin.test.assertNull

/**
* Created by vince on Dec 09, 2018.
Expand Down Expand Up @@ -277,15 +279,15 @@ class EntityTest : BaseTest() {
}

@Test
fun testHasColumnValue() {
fun testHasColumnValueTransient() {
val p1 = Parent()
assert(!p1.implementation.hasColumnValue(Parents.id.binding!!))
assert(p1.implementation.getColumnValue(Parents.id.binding!!) == null)

val p2 = Parent {
child = null
}
assert(p2.implementation.hasColumnValue(Parents.id.binding!!))
assert(!p2.implementation.hasColumnValue(Parents.id.binding!!))
assert(p2.implementation.getColumnValue(Parents.id.binding!!) == null)

val p3 = Parent {
Expand All @@ -299,7 +301,7 @@ class EntityTest : BaseTest() {
grandChild = null
}
}
assert(p4.implementation.hasColumnValue(Parents.id.binding!!))
assert(!p4.implementation.hasColumnValue(Parents.id.binding!!))
assert(p4.implementation.getColumnValue(Parents.id.binding!!) == null)

val p5 = Parent {
Expand All @@ -317,7 +319,7 @@ class EntityTest : BaseTest() {
}
}
}
assert(p6.implementation.hasColumnValue(Parents.id.binding!!))
assert(!p6.implementation.hasColumnValue(Parents.id.binding!!))
assert(p6.implementation.getColumnValue(Parents.id.binding!!) == null)

val p7 = Parent {
Expand All @@ -331,6 +333,78 @@ class EntityTest : BaseTest() {
assert(p7.implementation.getColumnValue(Parents.id.binding!!) == 6)
}

@Test
fun testHasColumnValueAttached() {
val sofiaDepartment = Department {
name = "Sofia Office"
location = LocationWrapper("Sofia")
}
database.departments.add(sofiaDepartment)

val now = LocalDate.now()
val employeeManager = Employee {
name = "Simpson"
job = "Manager"
hireDate = now
department = sofiaDepartment
salary = 100
}
database.employees.add(employeeManager)

val employee1 = Employee {
name = "McDonald"
job = "Engineer"
hireDate = now
department = sofiaDepartment
salary = 100
}

val e1 = with(database.employees) {
add(employee1)
find { it.id eq employee1.id }
}

assertNotNull(e1)
assert(!e1.implementation.hasColumnValue(Employees.managerId.binding!!))
assertNull(e1.implementation.getColumnValue(Employees.managerId.binding!!))

val employee2 = Employee {
name = "Smith"
job = "Engineer"
hireDate = now
department = sofiaDepartment
manager = null
salary = 100
}

val e2 = with(database.employees) {
add(employee2)
find { it.id eq employee2.id }
}

assertNotNull(e2)
assert(!e2.implementation.hasColumnValue(Employees.managerId.binding!!))
assertNull(e2.implementation.getColumnValue(Employees.managerId.binding!!))

val employee3 = Employee {
name = "Dennis"
job = "Engineer"
hireDate = now
department = sofiaDepartment
manager = employeeManager
salary = 100
}

val e3 = with(database.employees) {
add(employee3)
find { it.id eq employee3.id }
}

assertNotNull(e3)
assert(e3.implementation.hasColumnValue(Employees.managerId.binding!!))
assertNotNull(e3.implementation.getColumnValue(Employees.managerId.binding!!))
}

@Test
fun testUpdatePrimaryKey() {
try {
Expand Down Expand Up @@ -614,6 +688,21 @@ class EntityTest : BaseTest() {
assert(employee1 == employee2)
}

@Test
fun testValueNullEquality() {
val departmentTransient = Department {
name = "Sofia Office"
location = LocationWrapper("Sofia")
mixedCase = null // explicitly initialized to null
}
database.departments.add(departmentTransient)

val departmentAttached = database.departments.find { it.name eq "Sofia Office" }

assertNotNull(departmentAttached)
assert(departmentTransient == departmentAttached)
}

@Test
fun testDifferentClassesSameValuesNotEqual() {
val employee = Employee {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.ktorm.jackson

import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonInclude.Include
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonProperty.Access
import com.fasterxml.jackson.core.JsonGenerator
Expand Down Expand Up @@ -81,13 +82,18 @@ internal class EntitySerializers : SimpleSerializers() {
gen: JsonGenerator,
serializers: SerializerProvider
) {
val includeNulls = listOf(Include.ALWAYS, Include.CUSTOM, Include.USE_DEFAULTS)
.contains(serializers.getDefaultPropertyInclusion(entity::class.java).valueInclusion)
val entityProperties = entity.properties
val properties = findReadableProperties(entity)

for ((name, value) in entity.properties) {
val prop = properties[name] ?: continue
for ((name, prop) in properties) {
val value = entityProperties[name]
if (value == null && !includeNulls) {
continue
}

gen.writeFieldName(gen.codec.serializeNameForProperty(prop, serializers.config))

if (value == null) {
gen.writeNull()
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package org.ktorm.jackson

import com.fasterxml.jackson.annotation.JsonAlias
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.*
import com.fasterxml.jackson.module.kotlin.readValue
Expand All @@ -29,6 +30,7 @@ import org.ktorm.entity.Entity
class JacksonAnnotationTest {
private val objectMapper = ObjectMapper()
.configure(SerializationFeature.INDENT_OUTPUT, true)
.setDefaultPropertyInclusion(JsonInclude.Include.ALWAYS)
.findAndRegisterModules()

interface TestEntity : Entity<TestEntity> {
Expand Down

0 comments on commit 186a012

Please sign in to comment.