diff --git a/dsl/src/main/scala/com/crobox/clickhouse/dsl/column/BitFunctions.scala b/dsl/src/main/scala/com/crobox/clickhouse/dsl/column/BitFunctions.scala index cfdd4f92..79979959 100644 --- a/dsl/src/main/scala/com/crobox/clickhouse/dsl/column/BitFunctions.scala +++ b/dsl/src/main/scala/com/crobox/clickhouse/dsl/column/BitFunctions.scala @@ -8,14 +8,15 @@ trait BitFunctions { self: Magnets => case class BitAnd(a: NumericCol[_], b: NumericCol[_]) extends BitFunction(a) case class BitOr(a: NumericCol[_], b: NumericCol[_]) extends BitFunction(a) case class BitXor(a: NumericCol[_], b: NumericCol[_]) extends BitFunction(a) - case class BitNot(a: NumericCol[_]) extends BitFunction(a) + case class BitNot(a: NumericCol[_]) extends BitFunction(a) case class BitShiftLeft(a: NumericCol[_], b: NumericCol[_]) extends BitFunction(a) case class BitShiftRight(a: NumericCol[_], b: NumericCol[_]) extends BitFunction(a) - def bitAnd(a: NumericCol[_], b: NumericCol[_]) = BitAnd(a: NumericCol[_], b: NumericCol[_]) - def bitOr(a: NumericCol[_], b: NumericCol[_]) = BitOr(a: NumericCol[_], b: NumericCol[_]) - def bitXor(a: NumericCol[_], b: NumericCol[_]) = BitXor(a: NumericCol[_], b: NumericCol[_]) - def bitNot(a: NumericCol[_]) = BitNot(a: NumericCol[_]) - def bitShiftLeft(a: NumericCol[_], b: NumericCol[_]) = BitShiftLeft(a: NumericCol[_], b: NumericCol[_]) - def bitShiftRight(a: NumericCol[_], b: NumericCol[_]) = BitShiftRight(a: NumericCol[_], b: NumericCol[_]) + def bitAnd(a: NumericCol[_], b: NumericCol[_]): BitAnd = BitAnd(a: NumericCol[_], b: NumericCol[_]) + def bitOr(a: NumericCol[_], b: NumericCol[_]): BitOr = BitOr(a: NumericCol[_], b: NumericCol[_]) + def bitXor(a: NumericCol[_], b: NumericCol[_]): BitXor = BitXor(a: NumericCol[_], b: NumericCol[_]) + def bitNot(a: NumericCol[_]): BitNot = BitNot(a: NumericCol[_]) + def bitShiftLeft(a: NumericCol[_], b: NumericCol[_]): BitShiftLeft = BitShiftLeft(a: NumericCol[_], b: NumericCol[_]) + def bitShiftRight(a: NumericCol[_], b: NumericCol[_]): BitShiftRight = + BitShiftRight(a: NumericCol[_], b: NumericCol[_]) } diff --git a/dsl/src/main/scala/com/crobox/clickhouse/dsl/column/ClickhouseColumnFunctions.scala b/dsl/src/main/scala/com/crobox/clickhouse/dsl/column/ClickhouseColumnFunctions.scala index b98db39b..dbe3c835 100644 --- a/dsl/src/main/scala/com/crobox/clickhouse/dsl/column/ClickhouseColumnFunctions.scala +++ b/dsl/src/main/scala/com/crobox/clickhouse/dsl/column/ClickhouseColumnFunctions.scala @@ -14,6 +14,7 @@ trait ClickhouseColumnFunctions with ComparisonFunctions with DateTimeFunctions with DictionaryFunctions + with DistanceFunctions with EmptyFunctions with EncodingFunctions with HashFunctions diff --git a/dsl/src/main/scala/com/crobox/clickhouse/dsl/column/DistanceFunctions.scala b/dsl/src/main/scala/com/crobox/clickhouse/dsl/column/DistanceFunctions.scala new file mode 100644 index 00000000..ac8c64db --- /dev/null +++ b/dsl/src/main/scala/com/crobox/clickhouse/dsl/column/DistanceFunctions.scala @@ -0,0 +1,133 @@ +package com.crobox.clickhouse.dsl.column + +import com.crobox.clickhouse.dsl.{EmptyColumn, ExpressionColumn} + +trait DistanceFunctions { self: Magnets => + + sealed trait DistanceFunction + abstract class DistanceFunctionOp[V] extends ExpressionColumn[V](EmptyColumn) with DistanceFunction + + // L1 + case class L1Norm[V](vector: ArrayColMagnet[_ <: Iterable[V]])(implicit evidence: V => NumericCol[V]) + extends DistanceFunctionOp[V] + case class L1Normalize[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]]) + extends DistanceFunctionOp[V] + case class L1Distance[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]])( + implicit evidence: V => NumericCol[V] + ) extends DistanceFunctionOp[V] + + // L2 + case class L2Norm[V](vector: ArrayColMagnet[_ <: Iterable[V]])(implicit evidence: V => NumericCol[V]) + extends DistanceFunctionOp[V] + case class L2Normalize[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]]) + extends DistanceFunctionOp[V] + case class L2Distance[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]])( + implicit evidence: V => NumericCol[V] + ) extends DistanceFunctionOp[V] + + // L2 Squared + case class L2SquaredNorm[V](vector: ArrayColMagnet[_ <: Iterable[V]])(implicit evidence: V => NumericCol[V]) + extends DistanceFunctionOp[V] + case class L2SquaredDistance[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]])( + implicit evidence: V => NumericCol[V] + ) extends DistanceFunctionOp[V] + + // LInf + case class LInfNorm[V](vector: ArrayColMagnet[_ <: Iterable[V]])(implicit evidence: V => NumericCol[V]) + extends DistanceFunctionOp[V] + case class LInfNormalize[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]]) + extends DistanceFunctionOp[V] + case class LInfDistance[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]])( + implicit evidence: V => NumericCol[V] + ) extends DistanceFunctionOp[V] + + // LP + case class LPNorm[V](vector: ArrayColMagnet[_ <: Iterable[V]], p: Float)(implicit evidence: V => NumericCol[V]) + extends DistanceFunctionOp[V] + case class LPNormalize[V]( + vector1: ArrayColMagnet[_ <: Iterable[V]], + vector2: ArrayColMagnet[_ <: Iterable[V]], + p: Float + ) extends DistanceFunctionOp[V] + case class LPDistance[V]( + vector1: ArrayColMagnet[_ <: Iterable[V]], + vector2: ArrayColMagnet[_ <: Iterable[V]], + p: Float + )(implicit + evidence: V => NumericCol[V] + ) extends DistanceFunctionOp[V] + + // cosine + case class CosineDistance[V]( + vector1: ArrayColMagnet[_ <: Iterable[V]], + vector2: ArrayColMagnet[_ <: Iterable[V]] + )(implicit + evidence: V => NumericCol[V] + ) extends DistanceFunctionOp[V] + + // utilities + def l1Norm[V](vector: ArrayColMagnet[_ <: Iterable[V]])(implicit evidence: V => NumericCol[V]): L1Norm[V] = + L1Norm(vector) + + def l1Normalize[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]])(implicit + evidence: V => NumericCol[V] + ): L1Normalize[V] = L1Normalize(vector1, vector2) + + def l1Distance[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]])(implicit + evidence: V => NumericCol[V] + ): L1Distance[V] = L1Distance(vector1, vector2) + + def l2Norm[V](vector: ArrayColMagnet[_ <: Iterable[V]])(implicit evidence: V => NumericCol[V]): L2Norm[V] = + L2Norm(vector) + + def l2Normalize[V]( + vector1: ArrayColMagnet[_ <: Iterable[V]], + vector2: ArrayColMagnet[_ <: Iterable[V]] + ): L2Normalize[V] = + L2Normalize(vector1, vector2) + + def l2Distance[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]])(implicit + evidence: V => NumericCol[V] + ): L2Distance[V] = L2Distance(vector1, vector2) + + def l2SquaredNorm[V](vector: ArrayColMagnet[_ <: Iterable[V]])(implicit + evidence: V => NumericCol[V] + ): L2SquaredNorm[V] = L2SquaredNorm(vector) + + def l2SquaredDistance[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]])( + implicit evidence: V => NumericCol[V] + ): L2SquaredDistance[V] = L2SquaredDistance(vector1, vector2) + + def lInfNorm[V](vector: ArrayColMagnet[_ <: Iterable[V]])(implicit evidence: V => NumericCol[V]): LInfNorm[V] = + LInfNorm(vector) + + def lInfNormalize[V]( + vector1: ArrayColMagnet[_ <: Iterable[V]], + vector2: ArrayColMagnet[_ <: Iterable[V]] + ): LInfNormalize[V] = LInfNormalize(vector1, vector2) + + def lInfDistance[V](vector1: ArrayColMagnet[_ <: Iterable[V]], vector2: ArrayColMagnet[_ <: Iterable[V]])(implicit + evidence: V => NumericCol[V] + ): LInfDistance[V] = LInfDistance(vector1, vector2) + + def lPNorm[V](vector: ArrayColMagnet[_ <: Iterable[V]], p: Float)(implicit evidence: V => NumericCol[V]): LPNorm[V] = + LPNorm(vector, p) + + def lPNormalize[V]( + vector1: ArrayColMagnet[_ <: Iterable[V]], + vector2: ArrayColMagnet[_ <: Iterable[V]], + p: Float + ): LPNormalize[V] = LPNormalize(vector1, vector2, p) + + def lPDistance[V]( + vector1: ArrayColMagnet[_ <: Iterable[V]], + vector2: ArrayColMagnet[_ <: Iterable[V]], + p: Float + )(implicit evidence: V => NumericCol[V]): LPDistance[V] = LPDistance(vector1, vector2, p) + + def cosineDistance[V]( + vector1: ArrayColMagnet[_ <: Iterable[V]], + vector2: ArrayColMagnet[_ <: Iterable[V]] + )(implicit evidence: V => NumericCol[V]): CosineDistance[V] = CosineDistance(vector1, vector2) + +} diff --git a/dsl/src/main/scala/com/crobox/clickhouse/dsl/language/ClickhouseTokenizerModule.scala b/dsl/src/main/scala/com/crobox/clickhouse/dsl/language/ClickhouseTokenizerModule.scala index f945dffe..3d85c546 100644 --- a/dsl/src/main/scala/com/crobox/clickhouse/dsl/language/ClickhouseTokenizerModule.scala +++ b/dsl/src/main/scala/com/crobox/clickhouse/dsl/language/ClickhouseTokenizerModule.scala @@ -53,6 +53,7 @@ trait ClickhouseTokenizerModule with ComparisonFunctionTokenizer with DateTimeFunctionTokenizer with DictionaryFunctionTokenizer + with DistanceFunctionTokenizer with EncodingFunctionTokenizer with HashFunctionTokenizer with HigherOrderFunctionTokenizer @@ -168,6 +169,7 @@ trait ClickhouseTokenizerModule case col: DateTimeFunctionCol[_] => tokenizeDateTimeColumn(col) case col: DateTimeConst[_] => tokenizeDateTimeConst(col) case col: DictionaryFuncColumn[_] => tokenizeDictionaryFunction(col) + case col: DistanceFunction => tokenizeDistanceFunction(col) case col: EmptyFunction[_] => tokenizeEmptyCol(col) case col: EncodingFunction[_] => tokenizeEncodingFunction(col) case col: HashFunction => tokenizeHashFunction(col) diff --git a/dsl/src/main/scala/com/crobox/clickhouse/dsl/language/DistanceFunctionTokenizer.scala b/dsl/src/main/scala/com/crobox/clickhouse/dsl/language/DistanceFunctionTokenizer.scala new file mode 100644 index 00000000..7215ceee --- /dev/null +++ b/dsl/src/main/scala/com/crobox/clickhouse/dsl/language/DistanceFunctionTokenizer.scala @@ -0,0 +1,47 @@ +package com.crobox.clickhouse.dsl.language + +import com.crobox.clickhouse.dsl._ + +trait DistanceFunctionTokenizer { + self: ClickhouseTokenizerModule => + + def tokenizeDistanceFunction(col: DistanceFunction)(implicit ctx: TokenizeContext): String = col match { + + // cosine + case CosineDistance(vector1, vector2) => + s"cosineDistance(${tokenizeColumn(vector1.column)}, ${tokenizeColumn(vector2.column)})" + + // L1 + case L1Norm(vector) => s"L1Norm(${tokenizeColumn(vector.column)})" + case L1Normalize(vector1, vector2) => + s"L1Normalize(${tokenizeColumn(vector1.column)}, ${tokenizeColumn(vector2.column)})" + case L1Distance(vector1, vector2) => + s"L1Distance(${tokenizeColumn(vector1.column)}, ${tokenizeColumn(vector2.column)})" + + // L2 + case L2Norm(vector) => s"L2Norm(${tokenizeColumn(vector.column)})" + case L2Normalize(vector1, vector2) => + s"L2Normalize(${tokenizeColumn(vector1.column)}, ${tokenizeColumn(vector2.column)})" + case L2Distance(vector1, vector2) => + s"L2Distance(${tokenizeColumn(vector1.column)}, ${tokenizeColumn(vector2.column)})" + + // L2Squared + case L2SquaredNorm(vector) => s"L2SquaredNorm(${tokenizeColumn(vector.column)})" + case L2SquaredDistance(vector1, vector2) => + s"L2SquaredDistance(${tokenizeColumn(vector1.column)}, ${tokenizeColumn(vector2.column)})" + + // LInf + case LInfNorm(vector) => s"LinfNorm(${tokenizeColumn(vector.column)})" + case LInfNormalize(vector1, vector2) => + s"LinfNormalize(${tokenizeColumn(vector1.column)}, ${tokenizeColumn(vector2.column)})" + case LInfDistance(vector1, vector2) => + s"LinfDistance(${tokenizeColumn(vector1.column)}, ${tokenizeColumn(vector2.column)})" + + // LP + case LPNorm(vector, p) => s"LpNorm(${tokenizeColumn(vector.column)}, $p)" + case LPNormalize(vector1, vector2, p: Float) => + s"LpNormalize(${tokenizeColumn(vector1.column)}, ${tokenizeColumn(vector2.column)}, $p)" + case LPDistance(vector1, vector2, p: Float) => + s"LpDistance(${tokenizeColumn(vector1.column)}, ${tokenizeColumn(vector2.column)}, $p)" + } +} diff --git a/dsl/src/test/scala/com/crobox/clickhouse/dsl/language/DistanceFunctionTokenizerTest.scala b/dsl/src/test/scala/com/crobox/clickhouse/dsl/language/DistanceFunctionTokenizerTest.scala new file mode 100644 index 00000000..420a10f4 --- /dev/null +++ b/dsl/src/test/scala/com/crobox/clickhouse/dsl/language/DistanceFunctionTokenizerTest.scala @@ -0,0 +1,167 @@ +package com.crobox.clickhouse.dsl.language + +import com.crobox.clickhouse.DslTestSpec +import com.crobox.clickhouse.dsl._ +import com.crobox.clickhouse.dsl.schemabuilder.ColumnType + +class DistanceFunctionTokenizerTest extends DslTestSpec { + + private val array1: Array[Int] = Array(1) + private val array12: Array[Int] = Array(1, 2) + private val tuple1: Tuple = Tuple(Seq(1).map(const(_))) + private val tuple12: Tuple = Tuple(Seq(1, 2).map(const(_))) + private val numbers2 = NativeColumn[Seq[Int]]("numbers2", ColumnType.Array(ColumnType.UInt32)) + private val p = 1.0f + + behavior of "DistanceFunctionTokenizer" + + it should "tokenize L1Norm " in { + toSQL(select(l1Norm(array1))) should matchSQL(s"SELECT L1Norm([1])") + toSQL(select(l1Norm(array12))) should matchSQL(s"SELECT L1Norm([1, 2])") + toSQL(select(l1Norm[Int](tuple1))) should matchSQL(s"SELECT L1Norm((1))") + toSQL(select(l1Norm[Int](tuple12))) should matchSQL(s"SELECT L1Norm((1, 2))") + toSQL(select(l1Norm(numbers)).from(OneTestTable)) should matchSQL( + s"SELECT L1Norm(numbers) FROM ${OneTestTable.quoted}" + ) + } + + it should "tokenize L1Normalize " in { + toSQL(select(l1Normalize(array1, array1))) should matchSQL(s"SELECT L1Normalize([1], [1])") + toSQL(select(l1Normalize(array12, array12))) should matchSQL(s"SELECT L1Normalize([1, 2], [1, 2])") + toSQL(select(l1Normalize[Int](tuple1, tuple1))) should matchSQL(s"SELECT L1Normalize((1), (1))") + toSQL(select(l1Normalize[Int](tuple12, tuple12))) should matchSQL(s"SELECT L1Normalize((1, 2), (1, 2))") + toSQL(select(l1Normalize(numbers, numbers2)).from(OneTestTable)) should matchSQL( + s"SELECT L1Normalize(numbers, numbers2) FROM ${OneTestTable.quoted}" + ) + } + + it should "tokenize L1Distance " in { + toSQL(select(l1Distance(array1, array1))) should matchSQL(s"SELECT L1Distance([1], [1])") + toSQL(select(l1Distance(array12, array12))) should matchSQL(s"SELECT L1Distance([1, 2], [1, 2])") + toSQL(select(l1Distance[Int](tuple1, tuple1))) should matchSQL(s"SELECT L1Distance((1), (1))") + toSQL(select(l1Distance[Int](tuple12, tuple12))) should matchSQL(s"SELECT L1Distance((1, 2), (1, 2))") + toSQL(select(l1Distance(numbers, numbers2)).from(OneTestTable)) should matchSQL( + s"SELECT L1Distance(numbers, numbers2) FROM ${OneTestTable.quoted}" + ) + } + + it should "tokenize L2Norm " in { + toSQL(select(l2Norm(array1))) should matchSQL(s"SELECT L2Norm([1])") + toSQL(select(l2Norm(array12))) should matchSQL(s"SELECT L2Norm([1, 2])") + toSQL(select(l2Norm[Int](tuple1))) should matchSQL(s"SELECT L2Norm((1))") + toSQL(select(l2Norm[Int](tuple12))) should matchSQL(s"SELECT L2Norm((1, 2))") + toSQL(select(l2Norm(numbers)).from(OneTestTable)) should matchSQL( + s"SELECT L2Norm(numbers) FROM ${OneTestTable.quoted}" + ) + } + + it should "tokenize L2Normalize " in { + toSQL(select(l2Normalize(array1, array1))) should matchSQL(s"SELECT L2Normalize([1], [1])") + toSQL(select(l2Normalize(array12, array12))) should matchSQL(s"SELECT L2Normalize([1, 2], [1, 2])") + toSQL(select(l2Normalize[Int](tuple1, tuple1))) should matchSQL(s"SELECT L2Normalize((1), (1))") + toSQL(select(l2Normalize[Int](tuple12, tuple12))) should matchSQL(s"SELECT L2Normalize((1, 2), (1, 2))") + toSQL(select(l2Normalize(numbers, numbers2)).from(OneTestTable)) should matchSQL( + s"SELECT L2Normalize(numbers, numbers2) FROM ${OneTestTable.quoted}" + ) + } + + it should "tokenize L2Distance " in { + toSQL(select(l2Distance(array1, array1))) should matchSQL(s"SELECT L2Distance([1], [1])") + toSQL(select(l2Distance(array12, array12))) should matchSQL(s"SELECT L2Distance([1, 2], [1, 2])") + toSQL(select(l2Distance[Int](tuple1, tuple1))) should matchSQL(s"SELECT L2Distance((1), (1))") + toSQL(select(l2Distance[Int](tuple12, tuple12))) should matchSQL(s"SELECT L2Distance((1, 2), (1, 2))") + toSQL(select(l2Distance(numbers, numbers2)).from(OneTestTable)) should matchSQL( + s"SELECT L2Distance(numbers, numbers2) FROM ${OneTestTable.quoted}" + ) + } + + it should "tokenize L2SquaredNorm " in { + toSQL(select(l2SquaredNorm(array1))) should matchSQL(s"SELECT L2SquaredNorm([1])") + toSQL(select(l2SquaredNorm(array12))) should matchSQL(s"SELECT L2SquaredNorm([1, 2])") + toSQL(select(l2SquaredNorm[Int](tuple1))) should matchSQL(s"SELECT L2SquaredNorm((1))") + toSQL(select(l2SquaredNorm[Int](tuple12))) should matchSQL(s"SELECT L2SquaredNorm((1, 2))") + toSQL(select(l2SquaredNorm(numbers)).from(OneTestTable)) should matchSQL( + s"SELECT L2SquaredNorm(numbers) FROM ${OneTestTable.quoted}" + ) + } + + it should "tokenize L2SquaredDistance " in { + toSQL(select(l2SquaredDistance(array1, array1))) should matchSQL(s"SELECT L2SquaredDistance([1], [1])") + toSQL(select(l2SquaredDistance(array12, array12))) should matchSQL(s"SELECT L2SquaredDistance([1, 2], [1, 2])") + toSQL(select(l2SquaredDistance[Int](tuple1, tuple1))) should matchSQL(s"SELECT L2SquaredDistance((1), (1))") + toSQL(select(l2SquaredDistance[Int](tuple12, tuple12))) should matchSQL(s"SELECT L2SquaredDistance((1, 2), (1, 2))") + toSQL(select(l2SquaredDistance(numbers, numbers2)).from(OneTestTable)) should matchSQL( + s"SELECT L2SquaredDistance(numbers, numbers2) FROM ${OneTestTable.quoted}" + ) + } + + it should "tokenize L2InfNorm " in { + toSQL(select(lInfNorm(array1))) should matchSQL(s"SELECT LinfNorm([1])") + toSQL(select(lInfNorm(array12))) should matchSQL(s"SELECT LinfNorm([1, 2])") + toSQL(select(lInfNorm[Int](tuple1))) should matchSQL(s"SELECT LinfNorm((1))") + toSQL(select(lInfNorm[Int](tuple12))) should matchSQL(s"SELECT LinfNorm((1, 2))") + toSQL(select(lInfNorm(numbers)).from(OneTestTable)) should matchSQL( + s"SELECT LinfNorm(numbers) FROM ${OneTestTable.quoted}" + ) + } + + it should "tokenize LinfNormalize " in { + toSQL(select(lInfNormalize(array1, array1))) should matchSQL(s"SELECT LinfNormalize([1], [1])") + toSQL(select(lInfNormalize(array12, array12))) should matchSQL(s"SELECT LinfNormalize([1, 2], [1, 2])") + toSQL(select(lInfNormalize(tuple1, tuple1))) should matchSQL(s"SELECT LinfNormalize((1), (1))") + toSQL(select(lInfNormalize(tuple12, tuple12))) should matchSQL(s"SELECT LinfNormalize((1, 2), (1, 2))") + toSQL(select(lInfNormalize(numbers, numbers2)).from(OneTestTable)) should matchSQL( + s"SELECT LinfNormalize(numbers, numbers2) FROM ${OneTestTable.quoted}" + ) + } + + it should "tokenize LinfDistance " in { + toSQL(select(lInfDistance(array1, array1))) should matchSQL(s"SELECT LinfDistance([1], [1])") + toSQL(select(lInfDistance(array12, array12))) should matchSQL(s"SELECT LinfDistance([1, 2], [1, 2])") + toSQL(select(lInfDistance[Int](tuple1, tuple1))) should matchSQL(s"SELECT LinfDistance((1), (1))") + toSQL(select(lInfDistance[Int](tuple12, tuple12))) should matchSQL(s"SELECT LinfDistance((1, 2), (1, 2))") + toSQL(select(lInfDistance(numbers, numbers2)).from(OneTestTable)) should matchSQL( + s"SELECT LinfDistance(numbers, numbers2) FROM ${OneTestTable.quoted}" + ) + } + + it should "tokenize LpNorm " in { + toSQL(select(lPNorm(array1, 1.0f))) should matchSQL(s"SELECT LpNorm([1], 1.0)") + toSQL(select(lPNorm[Int](tuple1, 1.0f))) should matchSQL(s"SELECT LpNorm((1), 1.0)") + toSQL(select(lPNorm[Int](tuple12, 1.0f))) should matchSQL(s"SELECT LpNorm((1, 2), 1.0)") + toSQL(select(lPNorm[Int](numbers, 1.0f))) should matchSQL(s"SELECT LpNorm(numbers, 1.0)") + } + + it should "tokenize LpNormalize " in { + toSQL(select(lPNormalize(array1, array1, p))) should matchSQL(s"SELECT LpNormalize([1], [1], 1.0)") + toSQL(select(lPNormalize(array12, array12, p))) should matchSQL(s"SELECT LpNormalize([1, 2], [1, 2], 1.0)") + toSQL(select(lPNormalize(tuple1, tuple1, p))) should matchSQL(s"SELECT LpNormalize((1), (1), 1.0)") + toSQL(select(lPNormalize(tuple12, tuple12, p))) should matchSQL(s"SELECT LpNormalize((1, 2), (1, 2), 1.0)") + toSQL(select(lPNormalize(numbers, numbers2, p))) should matchSQL(s"SELECT LpNormalize(numbers, numbers2, 1.0)") + } + + it should "tokenize LpDistance " in { + toSQL(select(lPDistance(array1, array1, p))) should matchSQL(s"SELECT LpDistance([1], [1], 1.0)") + toSQL(select(lPDistance(array12, array12, p))) should matchSQL(s"SELECT LpDistance([1, 2], [1, 2], 1.0)") + toSQL(select(lPDistance[Int](tuple1, tuple1, p))) should matchSQL(s"SELECT LpDistance((1), (1), 1.0)") + toSQL(select(lPDistance[Int](tuple12, tuple12, p))) should matchSQL(s"SELECT LpDistance((1, 2), (1, 2), 1.0)") + toSQL(select(lPDistance[Int](numbers, numbers2, p))) should matchSQL(s"SELECT LpDistance(numbers, numbers2, 1.0)") + } + + it should "tokenize cosineDistance " in { + toSQL(select(cosineDistance(array1, array1))) should matchSQL(s"SELECT cosineDistance([1], [1])") + toSQL(select(cosineDistance(array12, array12))) should matchSQL(s"SELECT cosineDistance([1, 2], [1, 2])") + toSQL(select(cosineDistance[Int](tuple1, tuple1))) should matchSQL(s"SELECT cosineDistance((1), (1))") + toSQL(select(cosineDistance[Int](tuple12, tuple12))) should matchSQL(s"SELECT cosineDistance((1, 2), (1, 2))") + toSQL(select(cosineDistance[Int](numbers, numbers2))) should matchSQL(s"SELECT cosineDistance(numbers, numbers2)") + } + + it should "fail for non-numerical values" in { + val col1 = NativeColumn[String]("column_1") + val col2 = NativeColumn[Int]("column_2", ColumnType.UInt32) + assertDoesNotCompile("""toSQL(select(T1Norm(Array("1", "2"))))""".stripMargin) + assertDoesNotCompile("""toSQL(select(l1Norm(col1)).from(OneTestTable))""".stripMargin) + assertDoesNotCompile("""toSQL(select(l1Norm(col2)).from(OneTestTable))""".stripMargin) + } + +}