Exposed: Default values for columns bug

Created on 18 Jul 2018  路  7Comments  路  Source: JetBrains/Exposed

I don't understand how the below test is failing. The default value for timestamp should be equal to the System time at that point.

object Animals : IntIdTable("Animals") {
    val name = varchar("name", length = 60)
    val createdAt = long("timestamp").default(System.currentTimeMillis())
}

class Animal(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<Animal>(Animals)

    var name by Animals.name
    val createdAt by Animals.createdAt
}


class DefaultsTest {

    companion object {

        @BeforeClass
        @JvmStatic
        fun setup() {
            // init db
            val dataSource = HikariDataSource()
            dataSource.jdbcUrl = "jdbc:postgresql://localhost:5432/testdb?ssl=false"
            dataSource.username = "test"
            dataSource.password = "testpassword"
            Database.connect(dataSource)
        }
    }

    @Before
    fun prepareTest() {
        transact {
            SchemaUtils.create(Animals)
        }
    }

    @After
    fun cleanupTest() {
        transact {
            SchemaUtils.drop(Animals)
        }
    }

    @Test
    fun testThatDefaultValuesSavedAreOk() {
        val timeB4Transaction = System.currentTimeMillis()

        val id = transaction {
            val animal = Animal.new {
                name = "Tom"
            }
            return@transaction animal.id
        }

        val animal = transact {
            Animal[id]
        }

        println("timeB4Transaction: $timeB4Transaction, createdAt: ${animal.createdAt}")
        Assert.assertTrue(animal.createdAt > timeB4Transaction)
    }
}

Most helpful comment

Nope, .default(System.currentTimeMillis()) stores the constant value as default and uses it also as a default value in a database (where possible).
What you need is to use .clientDefault { System.currentTimeMillis() } replacement.

All 7 comments

Nope, .default(System.currentTimeMillis()) stores the constant value as default and uses it also as a default value in a database (where possible).
What you need is to use .clientDefault { System.currentTimeMillis() } replacement.

Thanks @Tapac, that was a subtle one.

@Tapac
Can you tell me what different between .default(System.currentTimeMillis()) and .clientDefault { System.currentTimeMillis() }?
Why when i use .default function, the result is always same for every rows but it's will fine when i use .clientDefault?

.default(System.currentTimeMillis()) - will take current time and create DEFAULT '_your_concrete_time_ column declration in a database, while .clientDefault { System.currentTimeMillis() } will be executed before every insert of a new row and value will be added into INSERT statement

@Tapac
When I use
val updatedDate = datetime("updated_dt").default(DateTime.now()),
every new rows created will have same value of updated_dt column as below
Screen Shot 2019-10-10 at 18 25 35

But if I change to
val updatedDate = datetime("updated_dt").clientDefault { DateTime.now() }, new row will create with different value of updated_dt column.

Can you tell me what is the reason of this different?

Execute show create table your_table (if it is MySQL) or look into updated_at declaration somehow and you will see the difference.
In your case, you have to use datetime("updated_dt").defaultExpression(CurrentDateTime())

Thank you for your support

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gcscaglia picture gcscaglia  路  3Comments

fmgonsalves picture fmgonsalves  路  3Comments

junhwong picture junhwong  路  3Comments

ncobc picture ncobc  路  3Comments

brabo-hi picture brabo-hi  路  4Comments