Custom functions in Squeryl

If you have a function defined in the database that is not known to Squeryl, you can define its signature in the Scala code like this:

def custom[A1,T1](s: TypedExpression[A1,T1]) =
  new FunctionNode("custom", Seq(s)) with LogicalBoolean

The function in that example takes anything as input and returns logical value. This is how it normally works with functions used in 'where' part of the query, such as 'exists'.

If you want to restrict input types, you may require explicit conversion in scope:

def custom[A1,T1](s: TypedExpression[A1,T1])
  (implicit f: TypedExpressionFactory[A1,T1], ev2: T1 <:< TOptionString) =
    new FunctionNode("custom", Seq(s)) with LogicalBoolean

The function in that example takes anything, that can be converted to a nullable string. That is typical for text search functions.

It is a bit more complex if you want to use custom operator. Like a JSON extraction operator, for instance. That is how custom operator may be defined (in that case it is a standard for PostgreSQL ILIKE):

import scala.language.implicitConversions
implicit class RicherTypedExpression[A1, T1]
  (s1: TypedExpression[A1, T1]) {
    def ilike[A2, T2 <: TOptionString](s2: TypedExpression[A2, T2])
      (implicit ev: CanCompare[T1, T2]) =
        new BinaryOperatorNodeLogicalBoolean(s1, s2, "ilike")
}
implicit def stringToRTE(s: String) =
  RicherTypedExpression(stringTEF.create(s))

This defines an operator on strings (left hand) and anything that is comparable to string (right hand).

I am sorry if this blog post is not detailed enough. I wrote it as a sticky-note-reminder to myself.