Squeryl custom field types

2019-09-05 01:06发布

问题:

I am trying to create a custom field type in Squeryl. This field represents an Isin code, so it is backed up by a string field. Following the example on the documentation, I have added a simple validation before creating a new isin (never mind what an Isin code is or how the validation procedure works):

trait Domain[A] { self: CustomType[A] =>
  def validate(a: A): Unit

  validate(value)
}

class Isin(v: String) extends StringField(v) with Domain[String] {
  println("instantiating Isin")
  override def validate(s: String) {
    println("calling validate with " + s)
    assert(checkIsin(s))
  }

  private def checkIsin(isin: String): Boolean = {
    // never mind the exact procedure
  }
}

I have added some println to find out what is going on. I use this field inside a model like

case class Asset(
  val id: Long = 0,
  val isin: Isin
) extends KeyedEntity[Long]

object Asset {
  import Database.assets

  def create(isinCode: String) {
    inTransaction {
      assets.insert(new Asset(isin = new Isin(isinCode)))
    }
  }
}

Now, when I call Asset.create("US0378331005") (a valid ISIN) I get an exception. In the stacktrace it turns out that this exception is due to a call to the init method on a null value, which is supposedly passed to checkIsin. Indeed, the println statements print

calling validate with US0378331005
Instantiating Isin
calling validate with

So it seems that the validate method is actually invoked twice, but the second time it gets a null value.

What is going on wrong?

回答1:

There are several problems here. First off, you seem to be using Lift Record and, if that's the case, you are implementing your validation logic incorrectly. The correct way to validate a Record field is to override

def validations: List[ValidationFunction]

where ValidationFunction is a type alias

type ValidationFunction = ValueType => List[FieldError]

and in your case ValueType == String.

The next issue is your Domain trait. Because your call to validate is inlined into the class definition, it will be called when your field is constructed. Obviously there is no value set at that point, so that's why you are seeing the println that references an empty value. I imagine that the order you see them in has something to do with your application flow. You have an existing record that is validated, and after that a new Record is created which triggers the next 2 println statements.



标签: scala squeryl