diff --git a/.travis.yml b/.travis.yml index 3b00d4132..fe19656de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ before_cache: - find $HOME/.sbt -name "*.lock" -delete env: global: - - TARGET_SCALA_VERSION: 2.12.4 + - TARGET_SCALA_VERSION: 2.12.5 - GH_REF: github.com/outworkers/phantom.git - secure: WwLG0fkVV1DS5P6GeLOHjPJ2z+GP9UaLzX27DuHBEXRxNPPw27y7jag0gbbf6E80kYwGB4zfBx9YjcJFVFdGCCcAjDJHMP8kLQirUak1jzuoWZFUEtTkF7ev/OVs0PmMHrOGuysT4W/UaL9MZD/mYO5lO9oavycTQ0kbOwZJwUg= - secure: Qtr5ULJ90s5pfLBaXRKFLMPBcDSYBQfUVz+abgjlG/um8iWE/OJswYn2n3zylAqnI4bSKhPobl6bBYzt8f6k9kzMqpR4t/4gWFV1LJUas0eAsTnrjV1He4nbPvO9RVEkvuQcTCqmus2AgYEnwdKhGWwktok5PAoJ22ycy4HK8C8= @@ -37,7 +37,7 @@ jdk: - oraclejdk8 matrix: include: - - scala: 2.12.4 + - scala: 2.12.5 jdk: oraclejdk8 addons: apt: diff --git a/build.sbt b/build.sbt index dad604add..8b37d079a 100644 --- a/build.sbt +++ b/build.sbt @@ -87,7 +87,7 @@ scalacOptions in ThisBuild ++= ScalacOptions ++ YWarnOptions lazy val Versions = new { val logback = "1.2.3" - val util = "0.38.0" + val util = "0.40.0" val json4s = "3.5.1" val datastax = "3.4.0" val scalatest = "3.0.4" @@ -108,7 +108,7 @@ lazy val Versions = new { val scala210 = "2.10.6" val scala211 = "2.11.11" - val scala212 = "2.12.4" + val scala212 = "2.12.5" val scalaAll = Seq(scala210, scala211, scala212) val scala = new { @@ -329,7 +329,6 @@ lazy val phantomFinagle = (project in file("phantom-finagle")) compilerPlugin("org.scalamacros" % "paradise" % Versions.macroParadise cross CrossVersion.full), "com.twitter" %% "util-core" % Versions.twitterUtil(scalaVersion.value), "com.outworkers" %% "util-testing" % Versions.util % Test, - "com.outworkers" %% "util-testing-twitter" % Versions.util % Test, "com.storm-enroute" %% "scalameter" % Versions.scalameter % Test ) ).dependsOn( @@ -350,8 +349,7 @@ lazy val phantomThrift = (project in file("phantom-thrift")) "org.apache.thrift" % "libthrift" % Versions.thrift, "com.twitter" %% "scrooge-core" % Versions.scrooge(scalaVersion.value), "com.twitter" %% "scrooge-serializer" % Versions.scrooge(scalaVersion.value), - "com.outworkers" %% "util-testing" % Versions.util % Test, - "com.outworkers" %% "util-testing-twitter" % Versions.util % Test + "com.outworkers" %% "util-testing" % Versions.util % Test ), coverageExcludedPackages := "com.outworkers.phantom.thrift.models.*" ).settings( diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/CassandraTable.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/CassandraTable.scala index 5eb768784..2a9740c05 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/CassandraTable.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/CassandraTable.scala @@ -96,7 +96,7 @@ abstract class CassandraTable[T <: CassandraTable[T, R], R]( QueryBuilder.Create.sasiIndexName(tableName, index.name), index.name, index.analyzer.qb - )) + ), QueryOptions.empty, Nil) } new QueryCollection[Seq](queries) } diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/clauses/QueryCondition.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/clauses/QueryCondition.scala index d136bc422..03c5917fa 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/clauses/QueryCondition.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/clauses/QueryCondition.scala @@ -15,23 +15,29 @@ */ package com.outworkers.phantom.builder.clauses +import com.outworkers.phantom.Row import com.outworkers.phantom.builder.QueryBuilder +import com.outworkers.phantom.builder.ops.TokenizerKey import com.outworkers.phantom.builder.query.engine.CQLQuery +import com.outworkers.phantom.builder.query.prepared.PrepareMark import com.outworkers.phantom.builder.syntax.CQLSyntax import com.outworkers.phantom.column.AbstractColumn -import com.outworkers.phantom.Row -import com.outworkers.phantom.builder.query.prepared.PrepareMark import shapeless.{::, HList, HNil} -abstract class QueryCondition[T <: HList](val qb: CQLQuery) +abstract class QueryCondition[ + PS <: HList +]( + val qb: CQLQuery, + val tokens: List[TokenizerKey] +) /** * A query that can be used inside "WHERE", "AND", and conditional compare-and-set type queries. */ sealed trait Clause -class PreparedCondition[RR] extends QueryCondition[RR :: HNil](PrepareMark.?.qb) -class ValueCondition[RR](val obj: RR) extends QueryCondition[HNil](CQLQuery.empty) +class PreparedCondition[RR] extends QueryCondition[RR :: HNil](PrepareMark.?.qb, Nil) +class ValueCondition[RR](val obj: RR) extends QueryCondition[HNil](CQLQuery.empty, Nil) class WhereClause extends Clause { @@ -48,15 +54,24 @@ class WhereClause extends Clause { * * @param qb The underlying query builder of the condition. */ - class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb) + class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb, Nil) + + class PartitionCondition( + override val qb: CQLQuery, + tokenCreator: TokenizerKey + ) extends QueryCondition[HNil](qb, tokenCreator :: Nil) /** * * @tparam T Type of argument */ - class ParametricCondition[T](override val qb: CQLQuery) extends QueryCondition[T :: HNil](qb) + class ParametricCondition[T]( + override val qb: CQLQuery + ) extends QueryCondition[T :: HNil](qb, Nil) - class HListCondition[HL <: HList](override val qb: CQLQuery) extends QueryCondition[HL](qb) + class HListCondition[HL <: HList]( + override val qb: CQLQuery + ) extends QueryCondition[HL](qb, Nil) } object WhereClause extends WhereClause @@ -82,18 +97,21 @@ object CompareAndSetClause extends Clause { * * @param qb The underlying builder. */ - class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb) + class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb, Nil) } object OrderingClause extends Clause { - class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb) + class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb, Nil) } object UsingClause extends Clause { - class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb) + class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb, Nil) } object UpdateClause extends Clause { - class Condition[HL <: HList](override val qb: CQLQuery, val skipped: Boolean = false) extends QueryCondition[HL](qb) + class Condition[HL <: HList]( + override val qb: CQLQuery, + val skipped: Boolean = false + ) extends QueryCondition[HL](qb, Nil) type Default = Condition[HNil] @@ -101,23 +119,31 @@ object UpdateClause extends Clause { } object OperatorClause extends Clause { - class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb) + class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb, Nil) } object TypedClause extends Clause { - class Condition[RR](override val qb: CQLQuery, val extractor: Row => RR) extends QueryCondition(qb) + class Condition[RR](override val qb: CQLQuery, val extractor: Row => RR) extends QueryCondition(qb, Nil) } object DeleteClause extends Clause { - class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb) + class Condition(override val qb: CQLQuery) extends QueryCondition[HNil](qb, Nil) } private[phantom] class OrderingColumn[RR](col: AbstractColumn[RR]) { - def asc: OrderingClause.Condition = new OrderingClause.Condition(QueryBuilder.Select.Ordering.ascending(col.name)) - def ascending: OrderingClause.Condition = new OrderingClause.Condition(QueryBuilder.Select.Ordering.ascending(col.name)) - def desc: OrderingClause.Condition = new OrderingClause.Condition(QueryBuilder.Select.Ordering.descending(col.name)) - def descending: OrderingClause.Condition = new OrderingClause.Condition(QueryBuilder.Select.Ordering.descending(col.name)) + def asc: OrderingClause.Condition = { + new OrderingClause.Condition(QueryBuilder.Select.Ordering.ascending(col.name)) + } + def ascending: OrderingClause.Condition = { + new OrderingClause.Condition(QueryBuilder.Select.Ordering.ascending(col.name)) + } + def desc: OrderingClause.Condition = { + new OrderingClause.Condition(QueryBuilder.Select.Ordering.descending(col.name)) + } + def descending: OrderingClause.Condition = { + new OrderingClause.Condition(QueryBuilder.Select.Ordering.descending(col.name)) + } } trait UsingClauseOperations { diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/ImplicitMechanism.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/ImplicitMechanism.scala index 871caefe5..ffcce3a02 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/ImplicitMechanism.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/ImplicitMechanism.scala @@ -15,6 +15,7 @@ */ package com.outworkers.phantom.builder.ops +import com.datastax.driver.core.Session import com.outworkers.phantom.CassandraTable import com.outworkers.phantom.builder.QueryBuilder import com.outworkers.phantom.builder.clauses.{CompareAndSetClause, OrderingColumn, WhereClause} @@ -131,7 +132,6 @@ sealed class MapConditionals[T <: CassandraTable[T, R], R, K, V](val col: Abstra } } - private[phantom] trait ImplicitMechanism extends ModifyMechanism { // implicit lazy val context: ExecutionContextExecutor = Manager.scalaExecutor @@ -160,6 +160,10 @@ private[phantom] trait ImplicitMechanism extends ModifyMechanism { new MapEntriesConditionals[K, V](cond) } + implicit def partitionColumnQueries[RR : Primitive]( + col: AbstractColumn[RR] with PartitionKey + ): PartitionQueryColumn[RR] = new PartitionQueryColumn[RR](col.name) + /** * Definition used to cast an index map column with values indexed to a query-able definition. * This will allow users to use "CONTAINS" clauses to search for matches based on map values. diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/PartitionQueryColumn.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/PartitionQueryColumn.scala new file mode 100644 index 000000000..8fd7cb42d --- /dev/null +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/PartitionQueryColumn.scala @@ -0,0 +1,164 @@ +/* + * Copyright 2013 - 2017 Outworkers Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.outworkers.phantom.builder.ops + +import com.datastax.driver.core.Session +import com.outworkers.phantom.builder.QueryBuilder +import com.outworkers.phantom.builder.clauses.{OperatorClause, WhereClause} +import com.outworkers.phantom.builder.primitives.Primitive +import com.outworkers.phantom.builder.query.engine.CQLQuery +import com.outworkers.phantom.builder.query.prepared.{ListValue, PrepareMark} +import com.outworkers.phantom.connectors.SessionAugmenterImplicits + +/** + * A class enforcing columns used in where clauses to be indexed. + * Using an implicit mechanism, only columns that are indexed can be converted into Indexed columns. + * This enforces a Cassandra limitation at compile time. + * It prevents a user from querying and using where operators on a column without any index. + * @param name The name of the column. + * @tparam RR The type of the value the column holds. + */ +case class PartitionQueryColumn[RR](name: String)( + implicit p: Primitive[RR] +) extends SessionAugmenterImplicits { + + protected[this] def operator[R : Primitive]( + value: R + )(fn: (String, String) => CQLQuery)(implicit pp: Primitive[R]): WhereClause.PartitionCondition = { + new WhereClause.PartitionCondition( + fn(name, pp.asCql(value)), { + session: Session => pp.serialize(value, session.protocolVersion) + } + ) + } + + def eqs(value: RR): WhereClause.PartitionCondition = { + operator(value)(QueryBuilder.Where.eqs) + } + + def eqs(value: OperatorClause.Condition): WhereClause.Condition = { + new WhereClause.Condition(QueryBuilder.Where.eqs(name, value.qb.queryString)) + } + + def lt(value: RR): WhereClause.PartitionCondition = { + operator(value)(QueryBuilder.Where.lt) + } + + def <(value: RR): WhereClause.PartitionCondition = lt(value) + + def lt(value: OperatorClause.Condition): WhereClause.Condition = { + new WhereClause.Condition(QueryBuilder.Where.lt(name, value.qb.queryString)) + } + + def <(value: OperatorClause.Condition): WhereClause.Condition = lt(value) + + def lte(value: RR): WhereClause.PartitionCondition = { + operator(value)(QueryBuilder.Where.lte) + } + + def <=(value: RR): WhereClause.PartitionCondition = lte(value) + + def lte(value: OperatorClause.Condition): WhereClause.Condition = { + new WhereClause.Condition(QueryBuilder.Where.lte(name, value.qb.queryString)) + } + + def <=(value: OperatorClause.Condition): WhereClause.Condition = lte(value) + + def gt(value: RR): WhereClause.PartitionCondition = { + operator(value)(QueryBuilder.Where.gt) + } + + def >(value: RR): WhereClause.PartitionCondition = gt(value) + + def gt(value: OperatorClause.Condition): WhereClause.Condition = { + new WhereClause.Condition(QueryBuilder.Where.gt(name, value.qb.queryString)) + } + + def >(value: OperatorClause.Condition): WhereClause.Condition = gt(value) + + def gte(value: RR): WhereClause.PartitionCondition = { + operator(value)(QueryBuilder.Where.gte) + } + + def >=(value: RR): WhereClause.PartitionCondition = gte(value) + + def gte(value: OperatorClause.Condition): WhereClause.Condition = { + new WhereClause.Condition(QueryBuilder.Where.gte(name, value.qb.queryString)) + } + + def >=(value: OperatorClause.Condition): WhereClause.Condition = gte(value) + + def in(values: List[RR])( + implicit ev: Primitive[ListValue[RR]] + ): WhereClause.PartitionCondition = { + new WhereClause.PartitionCondition( + QueryBuilder.Where.in(name, values.map(p.asCql)), { + session: Session => ev.serialize(ListValue(values), session.protocolVersion) + } + ) + } + + final def in(value: PrepareMark): WhereClause.ParametricCondition[ListValue[RR]] = { + new WhereClause.ParametricCondition[ListValue[RR]](QueryBuilder.Where.in(name, value)) + } + + /** + * Equals clause defined for the prepared statement. + * When this prepared clause is applied, the value specified in the WHERE clause can be binded at a later stage. + * + * {{{ + * Example usage: + * + * Table.select.where(_.id eqs ?) + * + * Will produce + * + * SELECT * FROM KEYSPACE.TABLE WHERE ID = ? + * + * }}} + * + * + * @param value The prepare mark value to use, the "?" singleton. + * @return A where clause with a parametric condition specified. + */ + final def eqs(value: PrepareMark): WhereClause.ParametricCondition[RR] = { + new WhereClause.ParametricCondition[RR](QueryBuilder.Where.eqs(name, value.symbol)) + } + + final def lt(value: PrepareMark): WhereClause.ParametricCondition[RR] = { + new WhereClause.ParametricCondition[RR](QueryBuilder.Where.lt(name, value.symbol)) + } + + final def <(value: PrepareMark): WhereClause.ParametricCondition[RR] = lt(value) + + final def lte(value: PrepareMark): WhereClause.ParametricCondition[RR] = { + new WhereClause.ParametricCondition[RR](QueryBuilder.Where.lte(name, value.symbol)) + } + + final def <=(value: PrepareMark): WhereClause.ParametricCondition[RR] = lte(value) + + final def gt(value: PrepareMark): WhereClause.ParametricCondition[RR] = { + new WhereClause.ParametricCondition[RR](QueryBuilder.Where.gt(name, value.symbol)) + } + + final def >(value: PrepareMark): WhereClause.ParametricCondition[RR] = gt(value) + + final def gte(value: PrepareMark): WhereClause.ParametricCondition[RR] = { + new WhereClause.ParametricCondition[RR](QueryBuilder.Where.gte(name, value.symbol)) + } + + final def >=(value: PrepareMark): WhereClause.ParametricCondition[RR] = gte(value) +} diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/QueryColumn.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/QueryColumn.scala index 9b01e8e87..b89eb1df1 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/QueryColumn.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/QueryColumn.scala @@ -34,7 +34,6 @@ abstract class RootQueryColumn[RR](val name: String)(implicit p: Primitive[RR]) new WhereClause.Condition(QueryBuilder.Where.eqs(name, p.asCql(value))) } - def eqs(value: OperatorClause.Condition): WhereClause.Condition = { new WhereClause.Condition(QueryBuilder.Where.eqs(name, value.qb.queryString)) } @@ -206,5 +205,6 @@ class MapKeyUpdateClause[K : Primitive, V : Primitive](val column: String, val k } } -class QueryColumn[RR](override val name: String)(implicit pv: Primitive[RR]) extends RootQueryColumn[RR](name) -class DeleteQueryColumn[RR](override val name: String)(implicit pv: Primitive[RR]) extends RootQueryColumn[RR](name) \ No newline at end of file +class QueryColumn[RR]( + override val name: String +)(implicit pv: Primitive[RR]) extends RootQueryColumn[RR](name) \ No newline at end of file diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/TokenOps.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/TokenOps.scala index e86657da2..d4b9b5390 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/TokenOps.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/TokenOps.scala @@ -35,7 +35,8 @@ sealed trait TokenValueApplyOps { new TokenConstructor(Seq(ev.asCql(value))) } - def apply[RR](value: PrepareMark)( + final def apply[RR]( + value: PrepareMark ): TokenConstructor[RR :: HNil, TokenTypes.ValueToken] = { new TokenConstructor(Seq(value.qb.queryString)) } diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/package.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/package.scala new file mode 100644 index 000000000..b0ab51e7b --- /dev/null +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/ops/package.scala @@ -0,0 +1,24 @@ +/* + * Copyright 2013 - 2017 Outworkers Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.outworkers.phantom.builder + +import java.nio.ByteBuffer + +import com.datastax.driver.core.Session + +package object ops { + type TokenizerKey = (Session => ByteBuffer) +} diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/primitives/Primitive.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/primitives/Primitive.scala index 687e0bf21..3208d5aec 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/primitives/Primitive.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/primitives/Primitive.scala @@ -228,5 +228,4 @@ object Primitive { * @return A reference to a concrete materialised implementation of a primitive for the given type. */ def apply[RR]()(implicit ev: Primitive[RR]): Primitive[RR] = ev - } diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/AlterQuery.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/AlterQuery.scala index 7206b45b3..7e00eb960 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/AlterQuery.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/AlterQuery.scala @@ -121,7 +121,7 @@ class AlterQuery[ new AlterQuery(table, QueryBuilder.Where.and(qb, clause.qb), options) } - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, Nil) } object AlterQuery { diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/CreateQuery.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/CreateQuery.scala index 714abce25..81e4e9f4c 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/CreateQuery.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/CreateQuery.scala @@ -135,7 +135,7 @@ case class CreateQuery[ val qb: CQLQuery = (withClause merge WithPart.empty merge usingPart) build init - def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options) + def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, Nil) def queryString: String = qb.queryString @@ -144,17 +144,29 @@ case class CreateQuery[ new QueryCollection(table.secondaryKeys map { key => if (key.isMapKeyIndex) { - ExecutableCqlQuery(QueryBuilder.Create.mapIndex(table.tableName, name, key.name)) + ExecutableCqlQuery( + qb = QueryBuilder.Create.mapIndex(table.tableName, name, key.name), + options = QueryOptions.empty, + tokens = Nil + ) } else if (key.isMapEntryIndex) { - ExecutableCqlQuery(QueryBuilder.Create.mapEntries(table.tableName, name, key.name)) + ExecutableCqlQuery( + qb = QueryBuilder.Create.mapEntries(table.tableName, name, key.name), + options = QueryOptions.empty, + tokens = Nil + ) } else { - ExecutableCqlQuery(QueryBuilder.Create.index(table.tableName, name, key.name)) + ExecutableCqlQuery( + QueryBuilder.Create.index(table.tableName, name, key.name), + QueryOptions.empty, + Nil + ) } }) } def delegate: DelegatedCreateQuery = DelegatedCreateQuery( - executable = ExecutableCqlQuery(qb, options), + executable = ExecutableCqlQuery(qb, options, Nil), indexList = indexList, sasiIndexes = table.sasiQueries ) diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/DeleteQuery.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/DeleteQuery.scala index 45974f9bd..3f52adf92 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/DeleteQuery.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/DeleteQuery.scala @@ -16,15 +16,15 @@ package com.outworkers.phantom.builder.query import com.datastax.driver.core.{ConsistencyLevel, Session} +import com.outworkers.phantom.CassandraTable import com.outworkers.phantom.builder._ import com.outworkers.phantom.builder.clauses._ -import com.outworkers.phantom.builder.query.execution._ -import com.outworkers.phantom.builder.ops.MapKeyUpdateClause +import com.outworkers.phantom.builder.ops.{MapKeyUpdateClause, TokenizerKey} import com.outworkers.phantom.builder.query.engine.CQLQuery +import com.outworkers.phantom.builder.query.execution._ import com.outworkers.phantom.builder.query.prepared.{PreparedBlock, PreparedFlattener} import com.outworkers.phantom.column.AbstractColumn import com.outworkers.phantom.connectors.KeySpace -import com.outworkers.phantom.{CassandraTable, Row} import org.joda.time.DateTime import shapeless.ops.hlist.{Prepend, Reverse} import shapeless.{=:!=, HList, HNil} @@ -41,39 +41,12 @@ case class DeleteQuery[ PS <: HList ](table: Table, init: CQLQuery, + tokens: List[TokenizerKey] = Nil, wherePart : WherePart = WherePart.empty, casPart : CompareAndSetPart = CompareAndSetPart.empty, usingPart: UsingPart = UsingPart.empty, - override val options: QueryOptions = QueryOptions.empty -) extends Query[Table, Record, Limit, Order, Status, Chain, PS](table, init, None.orNull, usingPart, options) with Batchable { - - override protected[this] type QueryType[ - T <: CassandraTable[T, _], - R, - L <: LimitBound, - O <: OrderBound, - S <: ConsistencyBound, - C <: WhereBound, - P <: HList - ] = DeleteQuery[T, R, L, O, S, C, P] - - protected[this] def create[ - T <: CassandraTable[T, _], - R, - L <: LimitBound, - O <: OrderBound, - S <: ConsistencyBound, - C <: WhereBound, - P <: HList - ]( - t: T, - q: CQLQuery, - r: Row => R, - part: UsingPart, - options: QueryOptions - ): QueryType[T, R, L, O, S, C, P] = { - new DeleteQuery[T, R, L, O, S, C, P](t, q, wherePart, casPart, part, options) - } + options: QueryOptions = QueryOptions.empty +) extends RootQuery[Table, Record, Status] with Batchable { def prepare[Rev <: HList]()( implicit session: Session, @@ -116,25 +89,30 @@ case class DeleteQuery[ * @param ev An evidence request guaranteeing the user cannot chain multiple where clauses on the same query. * @return */ - override def where[ + def where[ RR, HL <: HList, - Out <: HList + Token <: HList, + Out <: HList, + OutTk <: HList ](condition: (Table) => QueryCondition[HL])( implicit ev: =:=[Chain, Unchainned], prepend: Prepend.Aux[HL, PS, Out] ): DeleteQuery[Table, Record, Limit, Order, Status, Chainned, Out] = { - copy(wherePart = wherePart append QueryBuilder.Update.where(condition(table).qb)) + copy( + wherePart = wherePart append QueryBuilder.Update.where(condition(table).qb), + tokens = tokens ::: condition(table).tokens + ) } /** * The where method of a select query. * * @param condition A where clause condition restricted by path dependant types. - * @param ev An evidence request guaranteeing the user cannot chain multiple where clauses on the same query. + * @param ev An evidence request guaranteeing the user cannot chain multiple where clauses on the same query. * @return */ - override def and[ + def and[ RR, HL <: HList, Out <: HList @@ -142,7 +120,10 @@ case class DeleteQuery[ implicit ev: Chain =:= Chainned, prepend: Prepend.Aux[HL, PS, Out] ): DeleteQuery[Table, Record, Limit, Order, Status, Chainned, Out] = { - copy(wherePart = wherePart append QueryBuilder.Update.and(condition(table).qb)) + copy( + wherePart = wherePart append QueryBuilder.Update.and(condition(table).qb), + tokens = tokens ::: condition(table).tokens + ) } def consistencyLevel_=(level: ConsistencyLevel)( @@ -172,6 +153,7 @@ case class DeleteQuery[ ConditionalDeleteQuery( table = table, init = init, + tokens, wherePart = wherePart, casPart = casPart append QueryBuilder.Update.onlyIf(clause(table).qb), usingPart = usingPart, @@ -179,9 +161,9 @@ case class DeleteQuery[ ) } - override val qb: CQLQuery = (usingPart merge wherePart merge casPart) build init + val qb: CQLQuery = (usingPart merge wherePart merge casPart) build init - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, tokens) } @@ -218,6 +200,7 @@ sealed case class ConditionalDeleteQuery[ PS <: HList ](table: Table, init: CQLQuery, + tokens: List[TokenizerKey], wherePart : WherePart = WherePart.empty, casPart : CompareAndSetPart = CompareAndSetPart.empty, usingPart: UsingPart = UsingPart.empty, @@ -229,8 +212,10 @@ sealed case class ConditionalDeleteQuery[ final def and( clause: Table => CompareAndSetClause.Condition ): ConditionalDeleteQuery[Table, Record, Limit, Order, Status, Chain, PS] = { - copy(casPart = casPart append QueryBuilder.Update.and(clause(table).qb)) + copy( + casPart = casPart append QueryBuilder.Update.and(clause(table).qb) + ) } - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, tokens) } diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/InsertQuery.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/InsertQuery.scala index 4c87ed724..ce7d3e819 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/InsertQuery.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/InsertQuery.scala @@ -208,7 +208,7 @@ case class InsertQuery[ copy(lightweightPart = lightweightPart append CQLQuery(CQLSyntax.ifNotExists)) } - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, Nil) } object InsertQuery { @@ -264,7 +264,7 @@ class InsertJsonQuery[ val qb: CQLQuery = (lightweightPart merge usingPart) build init - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, Nil) } diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/Query.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/Query.scala index 12c4d7c98..83fc1cf56 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/Query.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/Query.scala @@ -35,67 +35,6 @@ abstract class RootQuery[ def executableQuery: ExecutableCqlQuery } -abstract class Query[ - Table <: CassandraTable[Table, _], - Record, - Limit <: LimitBound, - Order <: OrderBound, - Status <: ConsistencyBound, - Chain <: WhereBound, - PS <: HList -]( - table: Table, - val qb: CQLQuery, - row: Row => Record, - usingPart: UsingPart = UsingPart.empty, - val options: QueryOptions -) extends RootQuery[Table, Record, Status] { - - protected[this] type QueryType[ - T <: CassandraTable[T, _], - R, - L <: LimitBound, - O <: OrderBound, - S <: ConsistencyBound, - C <: WhereBound, - P <: HList - ] <: Query[T, R, L, O, S, C, P] - - /** - * The where method of a select query. - * @param condition A where clause condition restricted by path dependant types. - * @param ev An evidence request guaranteeing the user cannot chain multiple where clauses on the same query. - * @return - */ - def where[ - RR, - HL <: HList, - Out <: HList - ]( - condition: Table => QueryCondition[HL] - )(implicit - ev: Chain =:= Unchainned, - prepend: Prepend.Aux[HL, PS, Out] - ): QueryType[Table, Record, Limit, Order, Status, Chainned, Out] - - /** - * The where method of a select query. - * @param condition A where clause condition restricted by path dependant types. - * @param ev An evidence request guaranteeing the user cannot chain multiple where clauses on the same query. - * @return - */ - def and[ - RR, - HL <: HList, - Out <: HList - ]( - condition: Table => QueryCondition[HL] - )(implicit - ev: Chain =:= Chainned, - prepend: Prepend.Aux[HL, PS, Out] - ): QueryType[Table, Record, Limit, Order, Status, Chainned, Out] -} - trait Batchable { def executableQuery: ExecutableCqlQuery } diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/QueryOptions.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/QueryOptions.scala index f0864a76a..1240efadb 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/QueryOptions.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/QueryOptions.scala @@ -15,27 +15,51 @@ */ package com.outworkers.phantom.builder.query -import com.datastax.driver.core.{ConsistencyLevel, PagingState, Statement} +import com.datastax.driver.core._ +import com.datastax.driver.core.policies.TokenAwarePolicy +import com.outworkers.phantom.builder.ops.TokenizerKey + +trait Modifier extends (Statement => Statement) + +case class RoutingKeyModifier( + tokens: List[TokenizerKey] +)( + implicit session: Session +) extends (SimpleStatement => SimpleStatement) { + override def apply(st: SimpleStatement): SimpleStatement = { + + val policy = session.getCluster.getConfiguration.getPolicies.getLoadBalancingPolicy + + if (policy.isInstanceOf[TokenAwarePolicy] && tokens.nonEmpty) { + st + .setRoutingKey(tokens.map(_.apply(session)): _*) + .setKeyspace(session.getLoggedKeyspace) + } else { + st + } + } +} -class ConsistencyLevelModifier(level: Option[ConsistencyLevel]) extends (Statement => Statement) { +class ConsistencyLevelModifier(level: Option[ConsistencyLevel]) extends Modifier { override def apply(v1: Statement): Statement = { (level map v1.setConsistencyLevel).getOrElse(v1) } } -class SerialConsistencyLevelModifier(level: Option[ConsistencyLevel]) extends (Statement => Statement) { +class SerialConsistencyLevelModifier(level: Option[ConsistencyLevel]) extends Modifier { override def apply(v1: Statement): Statement = { (level map v1.setSerialConsistencyLevel).getOrElse(v1) } } -class PagingStateModifier(level: Option[PagingState]) extends (Statement => Statement) { + +class PagingStateModifier(level: Option[PagingState]) extends Modifier { override def apply(v1: Statement): Statement = { (level map v1.setPagingState).getOrElse(v1) } } -class EnableTracingModifier(level: Option[Boolean]) extends (Statement => Statement) { +class EnableTracingModifier(level: Option[Boolean]) extends Modifier { override def apply(v1: Statement): Statement = { level match { case Some(true) => v1.enableTracing() @@ -45,7 +69,7 @@ class EnableTracingModifier(level: Option[Boolean]) extends (Statement => Statem } } -class FetchSizeModifier(level: Option[Int]) extends (Statement => Statement) { +class FetchSizeModifier(level: Option[Int]) extends Modifier { override def apply(v1: Statement): Statement = { (level map v1.setFetchSize).getOrElse(v1) } @@ -60,7 +84,7 @@ case class QueryOptions( ) { def apply(st: Statement): Statement = { - val applier = List( + val applier = List[Statement => Statement]( new ConsistencyLevelModifier(consistencyLevel), new SerialConsistencyLevelModifier(serialConsistencyLevel), new PagingStateModifier(pagingState), diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/SelectQuery.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/SelectQuery.scala index db1f07052..61e9be90d 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/SelectQuery.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/SelectQuery.scala @@ -15,8 +15,11 @@ */ package com.outworkers.phantom.builder.query +import java.nio.ByteBuffer + import com.datastax.driver.core.{ConsistencyLevel, Session} import com.outworkers.phantom.builder.clauses._ +import com.outworkers.phantom.builder.ops.TokenizerKey import com.outworkers.phantom.builder.primitives.Primitives.{LongPrimitive, StringPrimitive} import com.outworkers.phantom.builder.query.engine.CQLQuery import com.outworkers.phantom.builder.query.execution._ @@ -43,36 +46,22 @@ case class SelectQuery[ protected[phantom] val table: Table, protected[phantom] val rowFunc: Row => Record, init: CQLQuery, + tokens: List[TokenizerKey] = Nil, protected[phantom] val wherePart: WherePart = WherePart.empty, protected[phantom] val orderPart: OrderPart = OrderPart.empty, protected[phantom] val limitedPart: LimitedPart = LimitedPart.empty, protected[phantom] val filteringPart: FilteringPart = FilteringPart.empty, protected[phantom] val usingPart: UsingPart = UsingPart.empty, protected[phantom] val count: Boolean = false, - override val options: QueryOptions = QueryOptions.empty -) extends Query[Table, Record, Limit, Order, Status, Chain, PS]( - table, qb = init, - rowFunc, - usingPart, - options -) { + options: QueryOptions = QueryOptions.empty +) extends RootQuery[Table, Record, Status] { def fromRow(row: Row): Record = rowFunc(row) - override val qb: CQLQuery = { + val qb: CQLQuery = { (wherePart merge orderPart merge limitedPart merge filteringPart merge usingPart) build init } - override protected[this] type QueryType[ - T <: CassandraTable[T, _], - R, - L <: LimitBound, - O <: OrderBound, - S <: ConsistencyBound, - C <: WhereBound, - P <: HList - ] = SelectQuery[T, R, L, O, S, C, P] - def allowFiltering(): SelectQuery[Table, Record, Limit, Order, Status, Chain, PS] = { copy(filteringPart = filteringPart append QueryBuilder.Select.allowFiltering()) } @@ -109,15 +98,18 @@ case class SelectQuery[ * @param ev An evidence request guaranteeing the user cannot chain multiple where clauses on the same query. * @return */ - override def where[ + def where[ RR, HL <: HList, Out <: HList ](condition: Table => QueryCondition[HL])( implicit ev: Chain =:= Unchainned, prepend: Prepend.Aux[HL, PS, Out] - ): QueryType[Table, Record, Limit, Order, Status, Chainned, Out] = { - copy(wherePart = wherePart append QueryBuilder.Update.where(condition(table).qb)) + ): SelectQuery[Table, Record, Limit, Order, Status, Chainned, Out] = { + copy( + wherePart = wherePart append QueryBuilder.Update.where(condition(table).qb), + tokens = tokens ::: condition(table).tokens + ) } /** @@ -126,15 +118,18 @@ case class SelectQuery[ * @param ev An evidence request guaranteeing the user cannot chain multiple where clauses on the same query. * @return */ - override def and[ + def and[ RR, HL <: HList, Out <: HList ](condition: Table => QueryCondition[HL])( implicit ev: Chain =:= Chainned, prepend: Prepend.Aux[HL, PS, Out] - ): QueryType[Table, Record, Limit, Order, Status, Chainned, Out] = { - copy(wherePart = wherePart append QueryBuilder.Update.and(condition(table).qb)) + ): SelectQuery[Table, Record, Limit, Order, Status, Chainned, Out] = { + copy( + wherePart = wherePart append QueryBuilder.Update.and(condition(table).qb), + tokens = tokens ::: condition(table).tokens + ) } def using(clause: UsingClause.Condition): SelectQuery[Table, Record, Limit, Order, Status, Chainned, PS] = { @@ -155,7 +150,7 @@ case class SelectQuery[ @implicitNotFound("A limit was already specified for this query.") final def limit(ps: PrepareMark)( implicit ev: Limit =:= Unlimited - ): QueryType[Table, Record, Limited, Order, Status, Chain, Int ::PS] = { + ): SelectQuery[Table, Record, Limited, Order, Status, Chain, Int :: PS] = { copy(limitedPart = limitedPart append QueryBuilder.limit(ps.qb.queryString)) } @@ -163,7 +158,7 @@ case class SelectQuery[ @implicitNotFound("A limit was already specified for this query.") def limit(limit: Int)( implicit ev: Limit =:= Unlimited - ): QueryType[Table, Record, Limited, Order, Status, Chain, PS] = { + ): SelectQuery[Table, Record, Limited, Order, Status, Chain, PS] = { copy(limitedPart = limitedPart append QueryBuilder.limit(limit.toString)) } @@ -175,7 +170,7 @@ case class SelectQuery[ copy(orderPart = orderPart append clauses.map(_(table).qb).toList) } - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, tokens) } private[phantom] class RootSelectBlock[ @@ -242,6 +237,7 @@ private[phantom] class RootSelectBlock[ table, f1.extractor, QueryBuilder.Select.select(table.tableName, keySpace.name, f1.qb), + Nil, WherePart.empty, OrderPart.empty, LimitedPart.empty, @@ -258,6 +254,7 @@ private[phantom] class RootSelectBlock[ table, f1(table).extractor, QueryBuilder.Select.select(table.tableName, keySpace.name, f1(table).qb), + Nil, WherePart.empty, OrderPart.empty, LimitedPart.empty, @@ -273,6 +270,7 @@ private[phantom] class RootSelectBlock[ table, extractCount, QueryBuilder.Select.count(table.tableName, keySpace.name), + Nil, WherePart.empty, OrderPart.empty, LimitedPart.empty, diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/TruncateQuery.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/TruncateQuery.scala index b9fe00153..eec29ae7b 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/TruncateQuery.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/TruncateQuery.scala @@ -33,7 +33,9 @@ class TruncateQuery[ protected[phantom] val usingPart: UsingPart = UsingPart.empty ) extends RootQuery[Table, Record, Status] { - def consistencyLevel_=(level: ConsistencyLevel)(implicit session: Session): TruncateQuery[Table, Record, Specified] = { + def consistencyLevel_=( + level: ConsistencyLevel + )(implicit session: Session): TruncateQuery[Table, Record, Specified] = { if (session.protocolConsistency) { new TruncateQuery(table, init, options.consistencyLevel_=(level)) } else { @@ -43,7 +45,7 @@ class TruncateQuery[ def qb: CQLQuery = usingPart build init - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, Nil) } diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/UpdateQuery.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/UpdateQuery.scala index ade98e2e9..e8512b26f 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/UpdateQuery.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/UpdateQuery.scala @@ -18,6 +18,7 @@ package com.outworkers.phantom.builder.query import com.datastax.driver.core.{ConsistencyLevel, Session} import com.outworkers.phantom.builder._ import com.outworkers.phantom.builder.clauses._ +import com.outworkers.phantom.builder.ops.TokenizerKey import com.outworkers.phantom.builder.query.engine.CQLQuery import com.outworkers.phantom.builder.query.execution._ import com.outworkers.phantom.builder.query.prepared.{PrepareMark, PreparedBlock, PreparedFlattener} @@ -40,44 +41,15 @@ case class UpdateQuery[ PS <: HList ](table: Table, init: CQLQuery, + tokens: List[TokenizerKey], usingPart: UsingPart = UsingPart.empty, wherePart: WherePart = WherePart.empty, private[phantom] val setPart: SetPart = SetPart.empty, casPart: CompareAndSetPart = CompareAndSetPart.empty, - override val options: QueryOptions = QueryOptions.empty -) extends Query[Table, Record, Limit, Order, Status, Chain, PS](table, init, None.orNull, usingPart, options) with Batchable { - - override val qb: CQLQuery = usingPart merge setPart merge wherePart build init - - override protected[this] type QueryType[ - T <: CassandraTable[T, _], - R, - L <: LimitBound, - O <: OrderBound, - S <: ConsistencyBound, - C <: WhereBound, - P <: HList - ] = UpdateQuery[T, R, L, O, S, C, P] - - protected[this] def create[ - T <: CassandraTable[T, _], - R, - L <: LimitBound, - O <: OrderBound, - S <: ConsistencyBound, - C <: WhereBound, - P <: HList - ](t: T, q: CQLQuery, r: Row => R, usingPart: UsingPart, options: QueryOptions): QueryType[T, R, L, O, S, C, P] = { - new UpdateQuery[T, R, L, O, S, C, P]( - t, - q, - usingPart, - wherePart, - setPart, - casPart, - options - ) - } + options: QueryOptions = QueryOptions.empty +) extends RootQuery[Table, Record, Status] with Batchable { + + val qb: CQLQuery = usingPart merge setPart merge wherePart build init def ttl(seconds: Long): UpdateQuery[Table, Record, Limit, Order, Status, Chain, PS] = { copy(setPart = setPart append QueryBuilder.ttl(seconds.toString)) @@ -89,15 +61,18 @@ case class UpdateQuery[ * @param ev An evidence request guaranteeing the user cannot chain multiple where clauses on the same query. * @return */ - override def where[ + def where[ RR, HL <: HList, Out <: HList ](condition: Table => QueryCondition[HL])(implicit ev: Chain =:= Unchainned, prepend: Prepend.Aux[HL, PS, Out] - ): QueryType[Table, Record, Limit, Order, Status, Chainned, Out] = { - copy(wherePart = wherePart append QueryBuilder.Update.where(condition(table).qb)) + ): UpdateQuery[Table, Record, Limit, Order, Status, Chainned, Out] = { + copy( + wherePart = wherePart append QueryBuilder.Update.where(condition(table).qb), + tokens = tokens ::: condition(table).tokens + ) } /** @@ -106,15 +81,18 @@ case class UpdateQuery[ * @param ev An evidence request guaranteeing the user cannot chain multiple where clauses on the same query. * @return */ - override def and[ + def and[ RR, HL <: HList, Out <: HList ](condition: Table => QueryCondition[HL])(implicit ev: Chain =:= Chainned, prepend: Prepend.Aux[HL, PS, Out] - ): QueryType[Table, Record, Limit, Order, Status, Chainned, Out] = { - copy(wherePart = wherePart append QueryBuilder.Update.and(condition(table).qb)) + ): UpdateQuery[Table, Record, Limit, Order, Status, Chainned, Out] = { + copy( + wherePart = wherePart append QueryBuilder.Update.and(condition(table).qb), + tokens = tokens ::: condition(table).tokens + ) } final def modify[ @@ -126,6 +104,7 @@ case class UpdateQuery[ AssignmentsQuery( table = table, init = init, + tokens = tokens, usingPart = usingPart, wherePart = wherePart, setPart = setPart appendConditionally(clause(table).qb, !clause(table).skipped), @@ -141,15 +120,18 @@ case class UpdateQuery[ * @param clause The Compare-And-Set clause to append to the builder. * @return A conditional query, now bound by a compare-and-set part. */ - def onlyIf(clause: Table => CompareAndSetClause.Condition): ConditionalQuery[Table, Record, Limit, Order, Status, Chain, PS, HNil] = { + def onlyIf( + clause: Table => CompareAndSetClause.Condition + ): ConditionalQuery[Table, Record, Limit, Order, Status, Chain, PS, HNil] = { ConditionalQuery( - table, - init, - usingPart, - wherePart, - setPart, - casPart append QueryBuilder.Update.onlyIf(clause(table).qb), - options + table = table, + init = init, + tokens = tokens, + usingPart = usingPart, + wherePart = wherePart, + setPart = setPart, + casPart = casPart append QueryBuilder.Update.onlyIf(clause(table).qb), + options = options ) } @@ -165,7 +147,7 @@ case class UpdateQuery[ } } - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, tokens) } sealed case class AssignmentsQuery[ @@ -179,6 +161,7 @@ sealed case class AssignmentsQuery[ ModifyPrepared <: HList ](table: Table, init: CQLQuery, + tokens: List[TokenizerKey], usingPart: UsingPart = UsingPart.empty, wherePart : WherePart = WherePart.empty, private[phantom] val setPart : SetPart = SetPart.empty, @@ -265,27 +248,31 @@ sealed case class AssignmentsQuery[ * @param clause The Compare-And-Set clause to append to the builder. * @return A conditional query, now bound by a compare-and-set part. */ - def onlyIf(clause: Table => CompareAndSetClause.Condition): ConditionalQuery[Table, Record, Limit, Order, Status, Chain, PS, ModifyPrepared] = { + def onlyIf( + clause: Table => CompareAndSetClause.Condition + ): ConditionalQuery[Table, Record, Limit, Order, Status, Chain, PS, ModifyPrepared] = { ConditionalQuery( - table, - init, - usingPart, - wherePart, - setPart, - casPart append QueryBuilder.Update.onlyIf(clause(table).qb), - options + table = table, + init = init, + tokens = tokens, + usingPart = usingPart, + wherePart = wherePart, + setPart = setPart, + casPart = casPart append QueryBuilder.Update.onlyIf(clause(table).qb), + options = options ) } def ifExists: ConditionalQuery[Table, Record, Limit, Order, Status, Chain, PS, ModifyPrepared] = { ConditionalQuery( - table, - init, - usingPart, - wherePart, - setPart, - casPart append QueryBuilder.Update.ifExists, - options + table = table, + init = init, + tokens = tokens, + usingPart = usingPart, + wherePart = wherePart, + setPart = setPart, + casPart = casPart append QueryBuilder.Update.ifExists, + options = options ) } @@ -300,7 +287,7 @@ sealed case class AssignmentsQuery[ } } - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, tokens) } sealed case class ConditionalQuery[ @@ -314,6 +301,7 @@ sealed case class ConditionalQuery[ ModifyPrepared <: HList ](table: Table, init: CQLQuery, + tokens: List[TokenizerKey], usingPart: UsingPart = UsingPart.empty, wherePart : WherePart = WherePart.empty, private[phantom] val setPart : SetPart = SetPart.empty, @@ -387,7 +375,7 @@ sealed case class ConditionalQuery[ } } - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, tokens) } object UpdateQuery { @@ -399,7 +387,8 @@ object UpdateQuery { table, QueryBuilder.Update.update( QueryBuilder.keyspace(keySpace.name, table.tableName).queryString - ) + ), + Nil ) } diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/execution/ExecutableCqlQuery.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/execution/ExecutableCqlQuery.scala index e87adc7bc..523a0f9c3 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/execution/ExecutableCqlQuery.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/execution/ExecutableCqlQuery.scala @@ -17,19 +17,22 @@ package com.outworkers.phantom.builder.query.execution import com.datastax.driver.core.{Session, SimpleStatement, Statement} -import com.outworkers.phantom.builder.query.QueryOptions +import com.outworkers.phantom.builder.ops.TokenizerKey import com.outworkers.phantom.builder.query.engine.CQLQuery +import com.outworkers.phantom.builder.query.{QueryOptions, RoutingKeyModifier} + case class ExecutableCqlQuery( qb: CQLQuery, - options: QueryOptions = QueryOptions.empty + options: QueryOptions = QueryOptions.empty, + tokens: List[TokenizerKey] ) { def statement()(implicit session: Session): Statement = { - options(new SimpleStatement(qb.terminate.queryString)) + options(RoutingKeyModifier(tokens).apply(new SimpleStatement(qb.terminate.queryString))) } } object ExecutableCqlQuery { - def empty: ExecutableCqlQuery = ExecutableCqlQuery(CQLQuery.empty, QueryOptions.empty) + def empty: ExecutableCqlQuery = ExecutableCqlQuery(CQLQuery.empty, QueryOptions.empty, Nil) } \ No newline at end of file diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/execution/QueryCollection.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/execution/QueryCollection.scala index c3cc2dc62..5b108eb1d 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/execution/QueryCollection.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/execution/QueryCollection.scala @@ -32,6 +32,4 @@ class QueryCollection[M[X] <: TraversableOnce[X]](val queries: M[ExecutableCqlQu for (q <- appendable) builder += q new QueryCollection(builder.result()) } - - def ++(st: QueryCollection[M]): QueryCollection[M] = appendAll(st.queries) } diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/prepared/PreparedBuilder.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/prepared/PreparedBuilder.scala index 5715af9f4..bb640305f 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/prepared/PreparedBuilder.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/query/prepared/PreparedBuilder.scala @@ -15,7 +15,7 @@ */ package com.outworkers.phantom.builder.query.prepared -import com.datastax.driver.core.{QueryOptions => _, _} +import com.datastax.driver.core.{PreparedStatement, ProtocolVersion, Session, Statement} import com.outworkers.phantom.builder.LimitBound import com.outworkers.phantom.builder.primitives.Primitive import com.outworkers.phantom.builder.query._ @@ -25,7 +25,8 @@ import com.outworkers.phantom.connectors.{KeySpace, SessionAugmenterImplicits} import com.outworkers.phantom.macros.BindHelper import com.outworkers.phantom.{CassandraTable, Row} import shapeless.ops.hlist.Tupler -import shapeless.{Generic, HList, HNil, ::} +import shapeless.{::, Generic, HList, HNil} + import scala.concurrent.{ExecutionContextExecutor, blocking} private[phantom] trait PrepareMark { @@ -44,7 +45,7 @@ class ExecutablePreparedQuery( val options: QueryOptions ) extends Batchable { - override def executableQuery: ExecutableCqlQuery = new ExecutableCqlQuery(CQLQuery.empty, options) { + override def executableQuery: ExecutableCqlQuery = new ExecutableCqlQuery(CQLQuery.empty, options, Nil) { override def statement()(implicit session: Session): Statement = st } } @@ -134,7 +135,7 @@ class PreparedSelectBlock[ protocolVersion: ProtocolVersion, fn: Row => R, options: QueryOptions -)(implicit session: Session, keySpace: KeySpace) { +) { /** * Method used to bind a set of arguments to a prepared query in a typesafe manner. diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/column/PrimitiveColumn.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/column/PrimitiveColumn.scala index f6307ea5b..b2f6d3a31 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/column/PrimitiveColumn.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/column/PrimitiveColumn.scala @@ -43,7 +43,7 @@ class PrimitiveColumn[ if (isStaticColumn) { root.forcePad.append(CQLSyntax.static) } else if (shouldFreeze && ev.frozen) { - QueryBuilder.Collections.frozen(root) + CQLQuery(name).forcePad.append(QueryBuilder.Collections.frozen(cassandraType)) } else { root } diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/database/Database.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/database/Database.scala index 3522da6a9..e9f000a90 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/database/Database.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/database/Database.scala @@ -17,6 +17,7 @@ package com.outworkers.phantom.database import com.datastax.driver.core.Session import com.outworkers.phantom.CassandraTable +import com.outworkers.phantom.builder.query.QueryOptions import com.outworkers.phantom.builder.query.execution.{ExecutableCqlQuery, QueryCollection} import com.outworkers.phantom.connectors.{CassandraConnection, KeySpace} import com.outworkers.phantom.macros.DatabaseHelper @@ -72,7 +73,7 @@ abstract class Database[ */ private[phantom] def autodrop(): QueryCollection[Seq] = { new QueryCollection(tables.map { table => - ExecutableCqlQuery(table.alter().drop().qb) + ExecutableCqlQuery(table.alter().drop().qb, QueryOptions.empty, Nil) }) } @@ -89,6 +90,8 @@ abstract class Database[ * execute an entire sequence of queries. */ private[phantom] def autotruncate(): QueryCollection[Seq] = { - new QueryCollection(tables.map(table => ExecutableCqlQuery(table.truncate().qb))) + new QueryCollection( + tables.map(table => ExecutableCqlQuery(table.truncate().qb, QueryOptions.empty, Nil)) + ) } } \ No newline at end of file diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/dsl/package.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/dsl/package.scala index f8cafafd8..038a5c591 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/dsl/package.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/dsl/package.scala @@ -48,7 +48,7 @@ package object dsl extends ScalaQueryContext with DefaultImports { str: CQLQuery, options: QueryOptions ): QueryInterface[Future] = new QueryInterface[Future]()(promiseInterface.adapter) { - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(str, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(str, options, Nil) } /** diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/keys/PrimaryKey.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/keys/PrimaryKey.scala index d2f561e71..2d72eaea9 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/keys/PrimaryKey.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/keys/PrimaryKey.scala @@ -28,7 +28,9 @@ object Indexed { new QueryColumn(col.name) } - implicit def optionalIndexToQueryColumn[T : Primitive](col: AbstractColumn[Option[T]] with Indexed): QueryColumn[T] = new QueryColumn(col.name) + implicit def optionalIndexToQueryColumn[ + T : Primitive + ](col: AbstractColumn[Option[T]] with Indexed): QueryColumn[T] = new QueryColumn(col.name) } private[phantom] trait Key[KeyType <: Key[KeyType]] { @@ -40,7 +42,7 @@ trait PrimaryKey extends Key[PrimaryKey] with Unmodifiable with Indexed with Und abstract override def isPrimary: Boolean = true } -trait PartitionKey extends Key[PartitionKey] with Unmodifiable with Indexed with Undroppable { +trait PartitionKey extends Key[PartitionKey] with Unmodifiable with Undroppable { self: AbstractColumn[_] => abstract override def isPartitionKey: Boolean = true abstract override def isPrimary: Boolean = true diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/macros/RootMacro.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/macros/RootMacro.scala index 0091f4bac..0c06a4344 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/macros/RootMacro.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/macros/RootMacro.scala @@ -168,11 +168,11 @@ trait RootMacro extends HListHelpers with WhiteboxToolbelt { def withoutMatch(m: RecordMatch): TableDescriptor = withMatch(m) def unmatched: Seq[Unmatched] = matches.collect { - case u @ Unmatched(records, reason) => u + case u: Unmatched => u } def matched: Seq[MatchedField] = matches.collect { - case m @ MatchedField(left, right) => m + case m: MatchedField => m } def fromRow: Option[Tree] = { @@ -247,11 +247,11 @@ trait RootMacro extends HListHelpers with WhiteboxToolbelt { } } - protected[this] def unmatchedValue(field: Column.Field, ref: Tree) = { + protected[this] def unmatchedValue(field: Column.Field, ref: Tree): Tree = { q"$enginePkg.CQLQuery($tableTerm.${field.name}.asCql($ref))" } - protected[this] def valueTerm(field: MatchedField, refTerm: Option[Tree]) = { + protected[this] def valueTerm(field: MatchedField, refTerm: Option[Tree]): Tree = { refTerm match { case Some(ref) => q"$enginePkg.CQLQuery($tableTerm.${field.right.name}.asCql($ref.${field.left.name}))" case None => q"$enginePkg.CQLQuery($tableTerm.${field.right.name}.asCql($inputTerm.${field.left.name}))" diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/ops/QueryContext.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/ops/QueryContext.scala index 54bc162b0..ca9225d5f 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/ops/QueryContext.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/ops/QueryContext.scala @@ -310,7 +310,13 @@ abstract class QueryContext[P[_], F[_], Timeout]( ev: Out ==:== Repr ): F[ResultSet] = promiseInterface.adapter.fromGuava(table.store(input).executableQuery) - def storeRecords[M[X] <: TraversableOnce[X], V1, Repr <: HList, HL <: HList, Out <: HList](inputs: M[V1])( + def storeRecords[ + M[X] <: TraversableOnce[X], + V1, + Repr <: HList, + HL <: HList, + Out <: HList + ](inputs: M[V1])( implicit keySpace: KeySpace, session: Session, thl: TableHelper.Aux[T, R, Repr], diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/ops/SelectQueryOps.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/ops/SelectQueryOps.scala index 40004d829..a7683f94b 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/ops/SelectQueryOps.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/ops/SelectQueryOps.scala @@ -36,7 +36,8 @@ class SelectQueryOps[ Order <: OrderBound, Status <: ConsistencyBound, Chain <: WhereBound, - PS <: HList + PS <: HList, + TK <: HList ]( val query: SelectQuery[Table, Record, Limit, Order, Status, Chain, PS] )( diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/db/specialized/SecondaryIndexTest.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/db/specialized/SecondaryIndexTest.scala index feef2306e..2e40e3e58 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/db/specialized/SecondaryIndexTest.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/db/specialized/SecondaryIndexTest.scala @@ -19,7 +19,6 @@ import com.datastax.driver.core.exceptions.InvalidQueryException import com.outworkers.phantom.PhantomSuite import com.outworkers.phantom.dsl._ import com.outworkers.phantom.tables._ -import com.outworkers.phantom.tables.dbs.SecondaryIndexOnlyDatabase import com.outworkers.util.samplers._ class SecondaryIndexTest extends PhantomSuite { diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/db/specialized/TupleColumnTest.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/db/specialized/TupleColumnTest.scala index 745440e63..18b4298ca 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/db/specialized/TupleColumnTest.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/db/specialized/TupleColumnTest.scala @@ -19,6 +19,7 @@ import com.outworkers.phantom.PhantomSuite import com.outworkers.phantom.tables.{NestedTupleRecord, TupleCollectionRecord, TupleRecord} import com.outworkers.util.samplers._ import com.outworkers.phantom.dsl._ +import com.outworkers.phantom.tables.bugs.TuplePartitionRecord class TupleColumnTest extends PhantomSuite { override def beforeAll(): Unit = { @@ -26,6 +27,7 @@ class TupleColumnTest extends PhantomSuite { database.tuple2Table.createSchema() database.nestedTupleTable.createSchema() database.tupleCollectionsTable.createSchema() + database.tuplePartitionKeyTable.createSchema() } it should "store and retrieve a record with a tuple column" in { @@ -130,10 +132,8 @@ class TupleColumnTest extends PhantomSuite { val appended = gen[Int] -> gen[String] - val insert = database.tupleCollectionsTable.store(sample) - val chain = for { - store <- insert.future() + store <- database.tupleCollectionsTable.store(sample).future() rec <- database.tupleCollectionsTable.findById(sample.id) update <- database.tupleCollectionsTable.update .where(_.id eqs sample.id) @@ -151,4 +151,42 @@ class TupleColumnTest extends PhantomSuite { afterUpdate.value.tuples should contain (appended) } } + + it should "allow using a tuple column as a partition key" in { + val sample = gen[TuplePartitionRecord] + + val chain = for { + store <- database.tuplePartitionKeyTable.store(sample).future + rec <- database.tuplePartitionKeyTable.select.where(_.id eqs sample.id).one() + } yield rec + + whenReady(chain) { res => + res shouldBe defined + res.value shouldEqual sample + } + } + + it should "allow using a tuple column as a partition key to update records" in { + val sample = gen[TuplePartitionRecord] + val newUuid = gen[UUID] + + val chain = for { + store <- database.tuplePartitionKeyTable.store(sample).future + rec <- database.tuplePartitionKeyTable.select.where(_.id eqs sample.id).one() + updateRec <- database.tuplePartitionKeyTable.update + .where(_.id eqs sample.id) + .modify(_.rec setTo newUuid) + .future() + recUpdated <- database.tuplePartitionKeyTable.select.where(_.id eqs sample.id).one() + + } yield rec -> recUpdated + + whenReady(chain) { case (beforeUpdate, afterUpdate) => + beforeUpdate shouldBe defined + beforeUpdate.value shouldEqual sample + + afterUpdate shouldBe defined + afterUpdate.value shouldEqual sample.copy(rec = newUuid) + } + } } diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/engine/CQLQueryTest.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/engine/CQLQueryTest.scala index fc754636a..41547d08a 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/engine/CQLQueryTest.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/engine/CQLQueryTest.scala @@ -223,7 +223,9 @@ class CQLQueryTest extends FlatSpec with Matchers with GeneratorDrivenPropertyCh it should "append and wrap a CQLQuery with ()" in { forAll { (q1: String, q2: String) => - CQLQuery(q1).wrap(CQLQuery(q2)).queryString shouldEqual s"$q1 ($q2)" + whenever(q1.nonEmpty) { + CQLQuery(q1).wrap(CQLQuery(q2)).queryString shouldEqual s"$q1 ($q2)" + } } } diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/execution/QueryCollectionsTest.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/execution/QueryCollectionsTest.scala index 88d346a11..8a247e09c 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/execution/QueryCollectionsTest.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/execution/QueryCollectionsTest.scala @@ -24,32 +24,17 @@ class QueryCollectionsTest extends FlatSpec with Matchers { it should "create a simple collection of queries from an input source" in { val source = genSet[String]().map(CQLQuery.apply) - val col = new QueryCollection[Set](source.map(ExecutableCqlQuery.apply(_, QueryOptions.empty))) + val col = new QueryCollection[Set](source.map(ExecutableCqlQuery.apply(_, QueryOptions.empty, Nil))) col.size shouldEqual source.size col.queries.map(_.qb) should contain theSameElementsAs source } - it should "append new elements to an existing QueryCollection" in { - val source = genSet[String]().map(CQLQuery.apply) - val appendable = genSet[String]().map(CQLQuery.apply) - val col = new QueryCollection[Set](source.map(ExecutableCqlQuery.apply(_, QueryOptions.empty))) - val colAppendable = new QueryCollection[Set](appendable.map(ExecutableCqlQuery.apply(_, QueryOptions.empty))) - - col.size shouldEqual source.size - col.queries.map(_.qb) should contain theSameElementsAs source - - val colFinal = col ++ colAppendable - - colFinal.size shouldEqual (source.size + appendable.size) - colFinal.queries.map(_.qb) should contain theSameElementsAs (source ++ appendable) - } - it should "append another collection to an existing QueryCollection" in { val source = genSet[String]().map(CQLQuery.apply) val appendable = genSet[String]().map(CQLQuery.apply) - val col = new QueryCollection[Set](source.map(ExecutableCqlQuery.apply(_, QueryOptions.empty))) - val colAppendable = appendable.map(ExecutableCqlQuery.apply(_, QueryOptions.empty)) + val col = new QueryCollection[Set](source.map(ExecutableCqlQuery.apply(_, QueryOptions.empty, Nil))) + val colAppendable = appendable.map(ExecutableCqlQuery.apply(_, QueryOptions.empty, Nil)) col.size shouldEqual source.size col.queries.map(_.qb) should contain theSameElementsAs source diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/prepared/PreparedDeleteQueryTest.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/prepared/PreparedDeleteQueryTest.scala index 24c014a3d..b8f433039 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/prepared/PreparedDeleteQueryTest.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/prepared/PreparedDeleteQueryTest.scala @@ -92,9 +92,9 @@ class PreparedDeleteQueryTest extends PhantomSuite { val chain = for { query <- database.articlesByAuthor.delete.where(_.category eqs ?).and(_.author_id eqs ?).prepareAsync() - store <- database.articlesByAuthor.store(author, cat, article).future() + _ <- database.articlesByAuthor.store(author, cat, article).future() get <- database.articlesByAuthor.select.where(_.category eqs cat).and(_.author_id eqs author).one() - delete <- query.bind(cat, author).future() + _ <- query.bind(cat, author).future() get2 <- database.articlesByAuthor.select.where(_.category eqs cat).and(_.author_id eqs author).one() } yield (get, get2) diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/prepared/PreparedUpdateQueryTest.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/prepared/PreparedUpdateQueryTest.scala index 79f5f9b30..d4f534804 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/prepared/PreparedUpdateQueryTest.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/query/prepared/PreparedUpdateQueryTest.scala @@ -196,9 +196,9 @@ class PreparedUpdateQueryTest extends PhantomSuite { insert2 <- db.verizonSchema.storeRecord(sample2) updated <- db.verizonSchema.updateDeleteStatus.flatMap(_.bind(false, sample.uid).future()) res <- db.verizonSchema.select.where(_.uid eqs sample.uid).one() - } yield (updated, res) + } yield res - whenReady(chain) { case (updated, res) => + whenReady(chain) { res => res shouldBe defined res.value.isDeleted shouldBe false } diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/select/TokenQuerySerialisationTest.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/TokenQuerySerialisationTest.scala similarity index 96% rename from phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/select/TokenQuerySerialisationTest.scala rename to phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/TokenQuerySerialisationTest.scala index 96f48a316..36731acb7 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/select/TokenQuerySerialisationTest.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/TokenQuerySerialisationTest.scala @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.outworkers.phantom.builder.serializers.select +package com.outworkers.phantom.builder.serializers import com.outworkers.phantom.builder.query.SerializationTest import com.outworkers.phantom.dsl._ import com.outworkers.phantom.tables.TestDatabase -import org.scalatest.{FlatSpec, Matchers} import com.outworkers.util.samplers._ +import org.scalatest.{FlatSpec, Matchers} class TokenQuerySerialisationTest extends FlatSpec with SerializationTest with Matchers { diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/DataTypeSerializationTest.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/datatypes/DataTypeSerializationTest.scala similarity index 94% rename from phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/DataTypeSerializationTest.scala rename to phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/datatypes/DataTypeSerializationTest.scala index cdf12e817..98800fa02 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/DataTypeSerializationTest.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/datatypes/DataTypeSerializationTest.scala @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.outworkers.phantom.builder.serializers +package com.outworkers.phantom.builder.serializers.datatypes import com.outworkers.phantom.builder.QueryBuilder import com.outworkers.phantom.builder.primitives.Primitive @@ -127,4 +127,11 @@ class DataTypeSerializationTest extends FlatSpec with Matchers with Serializatio listP.cassandraType shouldEqual s"frozen>>>" } + + + it should "freeze a partition key wrapped tuple derived type" in { + val primitive = Primitive[PasswordInfo] + primitive.cassandraType shouldEqual s"frozen>" + } + } diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/datatypes/PasswordInfo.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/datatypes/PasswordInfo.scala new file mode 100644 index 000000000..a533dc039 --- /dev/null +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/serializers/datatypes/PasswordInfo.scala @@ -0,0 +1,40 @@ +/* + * Copyright 2013 - 2017 Outworkers Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.outworkers.phantom.builder.serializers.datatypes + +import com.outworkers.phantom.builder.primitives.Primitive + +/** + * The password details. + * + * @param hasher The ID of the hasher used to hash this password. + * @param password The hashed password. + * @param salt The optional salt used when hashing. + */ +case class PasswordInfo( + hasher: String, + password: String, + salt: Option[String] = None +) + +object PasswordInfo{ + implicit val conversion: Primitive[PasswordInfo] = { + Primitive.derive[PasswordInfo, (String, String, Option[String])](pi => (pi.hasher, pi.password, pi.salt)) { x => + val (a, b, c) = x + PasswordInfo(a, b, c) + } + } +} diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/TestDatabase.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/TestDatabase.scala index 3370345c2..348cec745 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/TestDatabase.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/TestDatabase.scala @@ -16,6 +16,7 @@ package com.outworkers.phantom.tables import com.datastax.driver.core.SocketOptions +import com.datastax.driver.core.policies.{RoundRobinPolicy, TokenAwarePolicy} import com.outworkers.phantom.builder.query.CreateQuery import com.outworkers.phantom.builder.query.bugs.UserSchemaTable import com.outworkers.phantom.connectors @@ -107,16 +108,18 @@ class TestDatabase( // table to test a schema bug for using RootSelectBlockOps on select projections with no other clauses object userSchema extends UserSchemaTable with Connector object verizonSchema extends VerizonSchema with Connector + object tuplePartitionKeyTable extends TuplePartitionTable with Connector } object Connector { val default: CassandraConnection = connectors.ContactPoint.local - .withClusterBuilder(_.withSocketOptions( + .withClusterBuilder( + _.withSocketOptions( new SocketOptions() .setConnectTimeoutMillis(20000) .setReadTimeoutMillis(20000) - ) + ).withLoadBalancingPolicy(new TokenAwarePolicy(new RoundRobinPolicy())) ).noHeartbeat().keySpace( KeySpace("phantom").ifNotExists().`with`( replication eqs SimpleStrategy.replication_factor(1) diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/bugs/JsonPreparedTable.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/bugs/JsonPreparedTable.scala index 50325a68c..dd8aa5731 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/bugs/JsonPreparedTable.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/bugs/JsonPreparedTable.scala @@ -55,10 +55,10 @@ abstract class JsonPreparedTable extends Table[JsonPreparedTable, NestedJsonReco .p_value(_.name, ?) .p_value(_.description, ?) .p_value(_.user, ?) - .prepare() + .prepareAsync() def insertItem(item: NestedJsonRecord): Future[ResultSet] = - preparedInsert.bind(item).future() + preparedInsert.flatMap(_.bind(item).future()) def findById(id: Int): Future[Option[NestedJsonRecord]] = { select.where(_.id eqs id).one() diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/bugs/TuplePartitionTable.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/bugs/TuplePartitionTable.scala new file mode 100644 index 000000000..ca7d175d9 --- /dev/null +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/bugs/TuplePartitionTable.scala @@ -0,0 +1,32 @@ +/* + * Copyright 2013 - 2017 Outworkers Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.outworkers.phantom.tables.bugs + +import java.util.UUID +import com.outworkers.phantom.dsl._ +import com.outworkers.phantom.builder.serializers.datatypes.PasswordInfo + +case class TuplePartitionRecord( + id: PasswordInfo, + rec: UUID, + props: Map[String, String] +) + +abstract class TuplePartitionTable extends Table[TuplePartitionTable, TuplePartitionRecord] { + object id extends Col[PasswordInfo] with PartitionKey + object rec extends Col[UUID] + object props extends Col[Map[String, String]] +} diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/dbs/SecondaryIndexOnlyDatabase.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/dbs/SecondaryIndexOnlyDatabase.scala index 7b3b699e5..f2096d18c 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/dbs/SecondaryIndexOnlyDatabase.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/dbs/SecondaryIndexOnlyDatabase.scala @@ -24,7 +24,7 @@ import com.outworkers.phantom.tables.bugs.SchemaBugSecondaryIndex object TestConnector { - val specialTests = connectors.ContactPoint.local + val specialTests: CassandraConnection = connectors.ContactPoint.local .withClusterBuilder(_.withSocketOptions( new SocketOptions() .setConnectTimeoutMillis(20000) diff --git a/phantom-finagle/src/main/scala/com/outworkers/phantom/finagle/package.scala b/phantom-finagle/src/main/scala/com/outworkers/phantom/finagle/package.scala index 68728c934..d01bc055b 100644 --- a/phantom-finagle/src/main/scala/com/outworkers/phantom/finagle/package.scala +++ b/phantom-finagle/src/main/scala/com/outworkers/phantom/finagle/package.scala @@ -46,7 +46,7 @@ package object finagle extends TwitterQueryContext with DefaultImports { str: CQLQuery, options: QueryOptions ): QueryInterface[Future] = new QueryInterface[Future]() { - override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(str, options) + override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(str, options, Nil) } /** diff --git a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/OptionalThriftColumnTest.scala b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/OptionalThriftColumnTest.scala index c7d2afd22..b5a960eee 100644 --- a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/OptionalThriftColumnTest.scala +++ b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/OptionalThriftColumnTest.scala @@ -18,7 +18,6 @@ package com.outworkers.phantom.thrift.tests.binary.suites import com.datastax.driver.core.utils.UUIDs import com.outworkers.phantom.dsl._ import com.outworkers.phantom.thrift.tests.binary.BinarySuite -import com.outworkers.phantom.thrift.tests.compact.CompactSuite import com.outworkers.util.samplers._ class OptionalThriftColumnTest extends BinarySuite { diff --git a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/ThriftColumnTest.scala b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/ThriftColumnTest.scala index d91bcec13..79e1387e7 100644 --- a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/ThriftColumnTest.scala +++ b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/ThriftColumnTest.scala @@ -18,7 +18,6 @@ package com.outworkers.phantom.thrift.tests.binary.suites import com.datastax.driver.core.utils.UUIDs import com.outworkers.phantom.dsl._ import com.outworkers.phantom.thrift.tests.binary.BinarySuite -import com.outworkers.phantom.thrift.tests.compact.CompactSuite import com.outworkers.util.samplers._ class ThriftColumnTest extends BinarySuite { diff --git a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/ThriftListOperations.scala b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/ThriftListOperations.scala index 4e58f2bd1..4d1d75129 100644 --- a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/ThriftListOperations.scala +++ b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/binary/suites/ThriftListOperations.scala @@ -20,7 +20,6 @@ import com.outworkers.phantom.thrift.tests.ThriftRecord import com.outworkers.phantom.thrift.tests.binary.BinarySuite import com.outworkers.phantom.thrift.tests.compact.CompactSuite import com.outworkers.util.samplers._ -import com.outworkers.util.testing.twitter._ class ThriftListOperations extends BinarySuite { @@ -37,7 +36,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample2 :: sample.thriftList) } @@ -56,7 +55,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample2 :: sample.thriftList) } @@ -78,7 +77,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual prependedValues ::: sample.thriftList } @@ -100,7 +99,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual prependedValues ::: sample.thriftList } @@ -119,7 +118,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual sample.thriftList :+ sample2 } @@ -138,7 +137,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual sample.thriftList :+ sample2 } @@ -157,7 +156,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList ::: sample2) } @@ -176,7 +175,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList ::: sample2) } @@ -199,7 +198,7 @@ class ThriftListOperations extends BinarySuite { .one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList diff List(sample2)) } @@ -222,7 +221,7 @@ class ThriftListOperations extends BinarySuite { .one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList diff List(sample2)) } @@ -241,7 +240,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList diff removables) } @@ -260,7 +259,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList diff removables) } @@ -301,7 +300,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value should contain (sample2) } @@ -318,7 +317,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value should contain (sample2) } @@ -335,7 +334,7 @@ class ThriftListOperations extends BinarySuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value should contain (sample2) } diff --git a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/compact/suites/ThriftListOperations.scala b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/compact/suites/ThriftListOperations.scala index 74fae41d3..62dbc499b 100644 --- a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/compact/suites/ThriftListOperations.scala +++ b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/compact/suites/ThriftListOperations.scala @@ -20,7 +20,6 @@ import com.outworkers.phantom.thrift.tests.ThriftRecord import com.outworkers.phantom.thrift.tests.compact.CompactSuite import com.outworkers.phantom.thrift.util.ThriftTestSuite import com.outworkers.util.samplers._ -import com.outworkers.util.testing.twitter._ import org.scalatest.FlatSpec class ThriftListOperations extends CompactSuite { @@ -38,7 +37,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample2 :: sample.thriftList) } @@ -57,7 +56,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample2 :: sample.thriftList) } @@ -79,7 +78,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual prependedValues ::: sample.thriftList } @@ -101,7 +100,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual prependedValues ::: sample.thriftList } @@ -120,7 +119,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual sample.thriftList :+ sample2 } @@ -139,7 +138,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual sample.thriftList :+ sample2 } @@ -158,7 +157,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList ::: sample2) } @@ -177,7 +176,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList ::: sample2) } @@ -200,7 +199,7 @@ class ThriftListOperations extends CompactSuite { .one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList diff List(sample2)) } @@ -223,7 +222,7 @@ class ThriftListOperations extends CompactSuite { .one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList diff List(sample2)) } @@ -242,7 +241,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList diff removables) } @@ -261,7 +260,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList diff removables) } @@ -302,7 +301,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value should contain (sample2) } @@ -319,7 +318,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value should contain (sample2) } @@ -336,7 +335,7 @@ class ThriftListOperations extends CompactSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value should contain (sample2) } diff --git a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/compact/suites/ThriftSetOperationsTest.scala b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/compact/suites/ThriftSetOperationsTest.scala index 51232ec3a..330b2aa8d 100644 --- a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/compact/suites/ThriftSetOperationsTest.scala +++ b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/compact/suites/ThriftSetOperationsTest.scala @@ -17,9 +17,7 @@ package com.outworkers.phantom.thrift.tests.compact.suites import com.outworkers.phantom.dsl._ import com.outworkers.phantom.thrift.tests.compact.CompactSuite -import com.outworkers.phantom.thrift.util.ThriftTestSuite import com.outworkers.util.samplers._ -import org.scalatest.FlatSpec class ThriftSetOperationsTest extends CompactSuite { diff --git a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/tjson/suites/ThriftListOperations.scala b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/tjson/suites/ThriftListOperations.scala index 3f29ab429..6239c2d89 100644 --- a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/tjson/suites/ThriftListOperations.scala +++ b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/tjson/suites/ThriftListOperations.scala @@ -19,7 +19,6 @@ import com.outworkers.phantom.finagle._ import com.outworkers.phantom.thrift.tests.ThriftRecord import com.outworkers.phantom.thrift.tests.tjson.TJsonSuite import com.outworkers.util.samplers._ -import com.outworkers.util.testing.twitter._ class ThriftListOperations extends TJsonSuite { @@ -55,7 +54,7 @@ class ThriftListOperations extends TJsonSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample2 :: sample.thriftList) } @@ -99,7 +98,7 @@ class ThriftListOperations extends TJsonSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual prependedValues ::: sample.thriftList } @@ -137,7 +136,7 @@ class ThriftListOperations extends TJsonSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual sample.thriftList :+ sample2 } @@ -175,7 +174,7 @@ class ThriftListOperations extends TJsonSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList ::: sample2) } @@ -221,7 +220,7 @@ class ThriftListOperations extends TJsonSuite { .one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList diff List(sample2)) } @@ -259,7 +258,7 @@ class ThriftListOperations extends TJsonSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value shouldEqual (sample.thriftList diff removables) } @@ -300,7 +299,7 @@ class ThriftListOperations extends TJsonSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value should contain (sample2) } @@ -334,7 +333,7 @@ class ThriftListOperations extends TJsonSuite { select <- thriftDb.thriftColumnTable.select(_.thriftList).where(_.id eqs sample.id).one() } yield select - whenReady(operation.asScala) { items => + whenReady(operation) { items => items shouldBe defined items.value should contain (sample2) } diff --git a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/tjson/suites/ThriftSetOperationsTest.scala b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/tjson/suites/ThriftSetOperationsTest.scala index 465f1c21d..826260a60 100644 --- a/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/tjson/suites/ThriftSetOperationsTest.scala +++ b/phantom-thrift/src/test/scala/com/outworkers/phantom/thrift/tests/tjson/suites/ThriftSetOperationsTest.scala @@ -17,9 +17,7 @@ package com.outworkers.phantom.thrift.tests.tjson.suites import com.outworkers.phantom.dsl._ import com.outworkers.phantom.thrift.tests.tjson.TJsonSuite -import com.outworkers.phantom.thrift.util.ThriftTestSuite import com.outworkers.util.samplers._ -import org.scalatest.FlatSpec class ThriftSetOperationsTest extends TJsonSuite { diff --git a/readme/src/main/tut/migrate.md b/readme/src/main/tut/migrate.md index 7d9ea112d..3c7d79cc8 100644 --- a/readme/src/main/tut/migrate.md +++ b/readme/src/main/tut/migrate.md @@ -114,6 +114,19 @@ This is done to distinguish the underlying consumer mechanism of parsing and fet - `com.outworkers.phantom.dsl.context` should be used instead of `scala.concurrent.ExecutionContext.Implicits.global`. This now has the type `ExecutionContextExecutor` which allows us to use the same context for both Scala and Java futures(which are used internally as part of the Datastax Java driver). +#### The main import has changed + +Instead of `com.websudos.phantom.Implicits._`, you need to import `com.outworkers.phantom.dsl._`. It's +also worth paying attention that if you're using any phantom after 2.14.0, you are also required to have +this import in a lot more places than before. + +This is because the return type of the query methods is now tied to a specific package import. +This was done to allow us to have uniform method names across modules like `phantom-dsl` and `phantom-finagle`. +In the future, this is likely to be replaced with Free monads and `cats.free.Free`, but so far +we have resisted adding new large dependencies such as Cats for any reason. + +To understand more about this, have a look at [execution backends](querying/execution.md). + #### You can remove manual `fromRow` method definitions As of phantom 2.4.0, phantom is capable of automatically generating a `Row` extractor for the majority of