Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import net.fwbrasil.activate.statement.FunctionApply
import net.fwbrasil.activate.statement.ToUpperCase
import net.fwbrasil.activate.entity.StringEntityValue
import net.fwbrasil.activate.statement.ToLowerCase
import net.fwbrasil.activate.statement.ToUserFunction
import com.google.common.collect.MapMaker
import java.util.concurrent.ConcurrentMap
import CacheType._
Expand Down Expand Up @@ -538,6 +539,8 @@ class LiveCache(
executeStatementSelectValue(value.value).asInstanceOf[String].toUpperCase()
case value: ToLowerCase =>
executeStatementSelectValue(value.value).asInstanceOf[String].toLowerCase()
case ToUserFunction(fn, value) =>
fn.applyGeneric(executeStatementSelectValue(value))
}

def executeStatementSelectValue(value: StatementSelectValue)(implicit entitySourceInstancesMap: Map[EntitySource, BaseEntity]): Any =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ case class SimpleStatementBooleanValue(value: Boolean)(implicit val tval: Boolea
trait OperatorContext {
import language.implicitConversions

type UserFunction[V, U] = OperatorContext.UserFunction[V, U]

implicit def toAnd(value: StatementBooleanValue) = And(value)
implicit def toOr(value: StatementBooleanValue) = Or(value)
implicit def toIsEqualTo[V](value: V)(implicit tval1: (=> V) => StatementSelectValue) = IsEqualTo(value)
Expand All @@ -38,11 +40,29 @@ trait OperatorContext {

def toUpperCase(value: String)(implicit tval1: (=> String) => StatementSelectValue) = ToUpperCase(value)
def toLowerCase(value: String)(implicit tval1: (=> String) => StatementSelectValue) = ToLowerCase(value)

def toUserFunction[U, V](fn: UserFunction[U, V])(value: U)(implicit tval1: (=> U) => StatementSelectValue, tval2: (=> V) => StatementSelectValue) = ToUserFunction(fn, value)
}

object OperatorContext {
abstract class UserFunction[U, V] {
def apply(value: U): V
def toStorage(value: String): String

def applyGeneric(value: Any): V = apply(value.asInstanceOf[U])
}
}

import OperatorContext.UserFunction

class SimpleOperator() extends Operator
class CompositeOperator() extends Operator

case class ToUserFunction(fn: UserFunction[_, _], value: StatementSelectValue) extends FunctionApply(value) {
override def toString = s"$fn($value)"
def entityValue = value.entityValue.value.map(fn.applyGeneric)
}

case class Matcher(valueA: StatementSelectValue) extends CompositeOperator {
def like(valueB: => String)(implicit f: Option[String] => EntityValue[String]) =
CompositeOperatorCriteria(valueA, this, SimpleValue(() => wildcardToRegex(valueB), f))
Expand Down Expand Up @@ -75,7 +95,7 @@ case class ToUpperCase(value: StatementSelectValue) extends FunctionApply(value)

case class ToLowerCase(value: StatementSelectValue) extends FunctionApply(value) {
override def toString = s"toLowerCase($value)"
def entityValue = value.entityValue.asInstanceOf[StringEntityValue].value.map(_.toUpperCase)
def entityValue = value.entityValue.asInstanceOf[StringEntityValue].value.map(_.toLowerCase)
}

case class IsNotNull(valueA: StatementSelectValue) extends SimpleOperator {
Expand Down Expand Up @@ -182,4 +202,4 @@ case class Where(valueOption: Option[Criteria]) {
tval4(value4)))

override def toString = valueOption.map(_.toString).getOrElse("()")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ class Query[S](override val from: From, override val where: Where, val select: S

case class Select(values: StatementSelectValue*) {
override def toString = "(" + values.mkString(", ") + ")"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import net.fwbrasil.activate.statement.IsLessThan
import net.fwbrasil.activate.statement.IsNotEqualTo
import net.fwbrasil.activate.statement.IsNotNull
import net.fwbrasil.activate.statement.IsNull
import net.fwbrasil.activate.statement.ToUserFunction
import net.fwbrasil.activate.statement.Matcher
import net.fwbrasil.activate.statement.Operator
import net.fwbrasil.activate.statement.Or
Expand Down Expand Up @@ -280,6 +281,8 @@ trait QlIdiom {
stringUpperFunction(toSqlDml(value.value))
case value: ToLowerCase =>
stringLowerFunction(toSqlDml(value.value))
case ToUserFunction(fn, value) =>
fn.toStorage(toSqlDml(value))
}

def stringUpperFunction(value: String): String = s"UPPER($value)"
Expand Down Expand Up @@ -468,4 +471,4 @@ trait QlIdiom {
res
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,4 @@ trait ActivateTest extends SpecificationWithJUnit with Serializable {
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import net.fwbrasil.activate.mongoContext
import net.fwbrasil.activate.polyglotContext
import net.fwbrasil.activate.ActivateContext
import net.fwbrasil.activate.asyncMongoContext
import net.fwbrasil.activate.mysqlContext
import net.fwbrasil.activate.migration.StorageVersion
import net.fwbrasil.activate.multipleVms.CustomEncodedEntityValue

Expand Down Expand Up @@ -576,6 +577,38 @@ class QuerySpecs extends ActivateTest {

}

"support user function" in {
activateTest(
(step: StepExecutor) => {
val excludedContexts = Seq(mongoContext, asyncMongoContext, mysqlContext)
if (!excludedContexts.contains(step.ctx)) {
import step.ctx._
val string1 = "-1"
val string2 = "-2"
import net.fwbrasil.activate.statement.StatementSelectValue

object absFunc extends UserFunction[String, Int] {
def apply(value: String) = value.toInt.abs
def toStorage(value: String) = s"ABS(CAST($value as INTEGER))"
}

def abs(value: String)(implicit tval1: (=> String) => StatementSelectValue) = toUserFunction(absFunc)(value)
step {
newEmptyActivateTestEntity.stringValue = string1
newEmptyActivateTestEntity.stringValue = string2
}
step {
val result = select[ActivateTestEntity].where(e => toUserFunction(absFunc)(e.stringValue) :== string1.toInt.abs)
result.size === 1
}
step {
val result = select[ActivateTestEntity].where(e => abs(e.stringValue) :>= string1.toInt.abs)
result.size === 2
}
}
})
}

"support query with many results" in {
activateTest(
(step: StepExecutor) => {
Expand Down Expand Up @@ -747,4 +780,4 @@ class QuerySpecs extends ActivateTest {
})
}
}
}
}