SkinnyRecord#save() with TimestampsFeature doesn't update updatedAtField
riverpuro opened this issue · comments
SkinnyRecord object has companion with TimestampsFeature doesn't update its updatedAtField by save() method. Is it correct?
// There are SkinnyRecord object and companion object with TimestampsFeature.
case class Skill(
id: Long,
name: String,
createdAt: DateTime,
updatedAt: DateTime,
lockVersion: Long
) extends SkinnyRecord[Skill] {
def skinnyCRUDMapper = Skill
}
object Skill extends SkinnyCRUDMapper[Skill]
with TimestampsFeature[Skill]
with OptimisticLockWithVersionFeature[Skill] {
override val tableName = "skills"
override val defaultAlias = createAlias("s")
override def extract(rs: WrappedResultSet, s: ResultName[Skill]): Skill = autoConstruct(rs, s)
}
// My expectations:
describe("TimestampsFeature") {
it("should update updatedAtField by SkinnyRecord#save()") { implicit session =>
val id1 = Skill.createWithAttributes('name -> "Scala")
val skill = Skill.findById(id1).get
Thread.sleep(100L)
skill.copy(name = "Scala Programming").save()
val updatedSkill = Skill.findById(id1).get
updatedSkill.updatedAt should not equal (skill.updatedAt)
}
}
// Test failed:
// [info] - should update updatedAtField by SkinnyRecord#save() *** FAILED ***
// [info] 2014-12-20T23:14:32.076+09:00 equaled 2014-12-20T23:14:32.076+09:00 (SkinnyORMSpec.scala:443)
// skinny's implementation:
trait TimestampsFeature[Entity]
...
override def updateBy(where: SQLSyntax): UpdateOperationBuilder = {
val builder = super.updateBy(where)
builder.addAttributeToBeUpdated(column.field(updatedAtFieldName) -> DateTime.now) // <- updatedAtField pair added
builder
}
trait NoIdCUDFeature[Entity]
...
// attributesToBeUpdated has updatedAtField. But it may be updated by SkinnyRecord's attributesToPersist.
protected def mergeNamedValues(namedValues: Seq[(SQLSyntax, Any)]): Seq[(SQLSyntax, Any)] = {
namedValues.foldLeft(attributesToBeUpdated) {
case (xs, (column, newValue)) =>
if (xs.exists(_._1 == column)) xs.map { case (c, v) => if (c == column) (column -> newValue) else (c, v) }
else xs.+=(column -> newValue)
}.toSeq
}
The reason of this bug is that TimestampsFeature places priority on passed updatedAt value. The following code does that.
As you mentioned, currently SkinnyRecord always tries to persist existing updatedAt value. I guess the simplest fix is adding new configuration to SkinnyRecord to know the skinnyCRUDMapper
is a TimestampsFeature wired one or not when creating attributesToPersist and filter it's attributes.
@riverpuro #218 fix will be out in 1.3.9. Are you in a hurry to fix this issue? If so, we can release the new version as soon as possible.
Thank you! I will wait for 1.3.9 release, don't hurry!