Question

Suppose I have an entity class like that:

case class MyEntity(some_flag: Boolean) extends KeyedEntity[Long]

I want to perform the following SQL update using Squeryl:

update table_name set some_flag = not some_flag where id = 1

What is the related Squeryl statement to do this? I have tried already

def toggleFlag(id: Long) = inTransaction {
    update(table)(entity =>
        where(entity.id === id)
        set(entity.some_flag := !entity.some_flag)
    )
}

but this does not have any effect in the database.

Update 2: The Squeryl documentation gives this example of a partial update to increase an integer value by 1:

update(songs)(s =>
  where(s.title === "Watermelon Man")
  set(s.title := "The Watermelon Man",
      s.year  := s.year.~ + 1)
)  

Update:

I am using Squeryl 0.9.5-6 with Scala 2.10 and Play! 2.1

Was it helpful?

Solution

I made a little code project out of your example. The problem is that squeryl serializes the update, but it "swallows" the (!), producing the following SQL:

 update MyEntity set
 some_flag = (some_flag)

Basically, squeryl builds under the hood a tree made of operations, and then serializes it to a string that will be sent to the SQL adapter.

In general, I check it out isolating the update statement and printing it (like squeryl does):

    // From __update, Table.scala
    val dba = Session.currentSession.databaseAdapter
    val sw = new StatementWriter(dba)
    val o0 = _callbacks.beforeUpdate(o.asInstanceOf[AnyRef]).asInstanceOf[T]
    dba.writeUpdate(o0, this, sw, checkOCC)

Either replicating the code in my class (for debugging purposes) or setting a breakpoint directly in Table.scala

To isolate the statement, simply factor out the second part of update:

val s = ((entity: InsertTypeHere) =>
      where(entity.id === id)
      set(entity.some_flag := not entity.some_flag))

Thanks to this "trick", I discovered that the reference to some_flag is correctly transformed into a SelectElementReference of type java.lang.Boolean, but the (!) is not traslated into a PrefixOperator. It seems like a squeryl bug to me, but let me see if it is possible to "fix" it from your code.

UPDATE:

Digging in squeryl code, it really seems that the "not" operator is missing. Fortunately, it is easy to add it back by yourself!

     class NotExpression(val ast: ExpressionNode)(implicit val mapper: OutMapper[BooleanType])
        extends PrefixOperatorNode(ast, "not ", false)
                with LogicalBoolean with NestedExpression with TypedExpressionNode[BooleanType]

     def mynot(b: BooleanExpression[BooleanType]) = new NotExpression(b)

     transaction {
          update(table)(t => where(t.id === 3) set (t.some_flag := mynot(t.some_flag)))
     }

This produces the right SQL, at least in your case. I will submit a patch to squeryl and ask for comments.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top