From 4b12273a39f19c4ee4079d7b5e9b835d93456f84 Mon Sep 17 00:00:00 2001 From: Flavian Alexandru Date: Wed, 23 Aug 2017 08:56:38 +0100 Subject: [PATCH] Feature/nested lists (#739) * Adding storage and retrieval tests for nested collection primitives. * Fixing support for nested collections. --- build.sbt | 2 +- .../builder/primitives/Primitives.scala | 2 +- .../primitives/NestedPrimitivesTest.scala | 89 +++++++++++++++++++ .../DataTypeSerializationTest.scala | 24 +++++ .../tables/PrimaryCollectionTable.scala | 4 + 5 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 phantom-dsl/src/test/scala/com/outworkers/phantom/builder/primitives/NestedPrimitivesTest.scala diff --git a/build.sbt b/build.sbt index 4cafa742d..2a085ecd1 100644 --- a/build.sbt +++ b/build.sbt @@ -19,7 +19,7 @@ import com.twitter.sbt._ lazy val Versions = new { val logback = "1.2.3" - val util = "0.37.0" + val util = "0.38.0" val json4s = "3.5.1" val datastax = "3.3.0" val scalatest = "3.0.1" diff --git a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/primitives/Primitives.scala b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/primitives/Primitives.scala index a06fc81ea..848876e6c 100644 --- a/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/primitives/Primitives.scala +++ b/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/primitives/Primitives.scala @@ -485,7 +485,7 @@ object Primitives { implicit ev: Primitive[RR], cbf: CanBuildFrom[Nothing, RR, M[RR]] ): Primitive[M[RR]] = new Primitive[M[RR]] { - override def frozen: Boolean = ev.frozen + override def frozen: Boolean = true override def shouldFreeze: Boolean = true diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/primitives/NestedPrimitivesTest.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/primitives/NestedPrimitivesTest.scala new file mode 100644 index 000000000..452b1eb6d --- /dev/null +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/builder/primitives/NestedPrimitivesTest.scala @@ -0,0 +1,89 @@ +/* + * 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.primitives + +import com.outworkers.phantom.PhantomSuite +import com.outworkers.phantom.dsl._ +import com.outworkers.phantom.tables.NestedCollections +import com.outworkers.util.samplers._ + +class NestedPrimitivesTest extends PhantomSuite { + + override def beforeAll(): Unit = { + super.beforeAll() + db.nestedCollectionTable.createSchema() + } + + it should "automatically store a nested primitive record" in { + val sample = gen[NestedCollections] + + val chain = for { + store <- db.nestedCollectionTable.storeRecord(sample) + retrieve <- db.nestedCollectionTable.select.where(_.id eqs sample.id).one() + } yield retrieve + + whenReady(chain) { rec => + rec shouldBe defined + rec.value shouldEqual sample + } + } + + it should "update the value of an entire record inside a nested list field" in { + val sample = gen[NestedCollections] + val updated = genList[List[String]]() + + val chain = for { + store <- db.nestedCollectionTable.storeRecord(sample) + retrieve <- db.nestedCollectionTable.select.where(_.id eqs sample.id).one() + update <- db.nestedCollectionTable.update + .where(_.id eqs sample.id) + .modify(_.nestedList setTo updated) + .future() + retrieve2 <- db.nestedCollectionTable.select.where(_.id eqs sample.id).one() + } yield (retrieve, retrieve2) + + whenReady(chain) { case (beforeUpdate, afterUpdate) => + beforeUpdate shouldBe defined + beforeUpdate.value shouldEqual sample + + afterUpdate shouldBe defined + afterUpdate.value.nestedList should contain theSameElementsAs updated + } + } + + it should "update the value of an entire record inside a nested list set field" in { + val sample = gen[NestedCollections] + val updated = genList[Set[String]]() + + val chain = for { + store <- db.nestedCollectionTable.storeRecord(sample) + retrieve <- db.nestedCollectionTable.select.where(_.id eqs sample.id).one() + update <- db.nestedCollectionTable.update + .where(_.id eqs sample.id) + .modify(_.nestedListSet setTo updated) + .future() + retrieve2 <- db.nestedCollectionTable.select.where(_.id eqs sample.id).one() + } yield (retrieve, retrieve2) + + whenReady(chain) { case (beforeUpdate, afterUpdate) => + beforeUpdate shouldBe defined + beforeUpdate.value shouldEqual sample + + afterUpdate shouldBe defined + afterUpdate.value.nestedListSet should contain theSameElementsAs updated + } + } +} 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/DataTypeSerializationTest.scala index 38b779ba9..cdf12e817 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/DataTypeSerializationTest.scala @@ -97,10 +97,34 @@ class DataTypeSerializationTest extends FlatSpec with Matchers with Serializatio cType shouldEqual s"map>, frozen>>" } + it should "generate a frozen collection type for a nested list" in { + val stringP = Primitive[String] + val cType = db.nestedCollectionTable.nestedList.cassandraType + + cType shouldEqual s"list>>" + } + + it should "generate a frozen collection type for a nested list set" in { + val stringP = Primitive[String] + val cType = db.nestedCollectionTable.nestedListSet.cassandraType + + cType shouldEqual s"list>>" + } + it should "generate a frozen collection type for map with a collection value type" in { val stringP = Primitive[String] val cType = db.nestedCollectionTable.props.cassandraType cType shouldEqual s"map>>" } + + it should "freeze nested collections properly" in { + val stringP = Primitive[String] + val inner = Primitive[List[String]] + val listP = Primitive[List[List[String]]] + + inner.frozen shouldEqual true + + listP.cassandraType shouldEqual s"frozen>>>" + } } diff --git a/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/PrimaryCollectionTable.scala b/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/PrimaryCollectionTable.scala index 7db9e78bf..a02127fbd 100644 --- a/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/PrimaryCollectionTable.scala +++ b/phantom-dsl/src/test/scala/com/outworkers/phantom/tables/PrimaryCollectionTable.scala @@ -36,6 +36,8 @@ abstract class PrimaryCollectionTable extends Table[PrimaryCollectionTable, Prim case class NestedCollections( id: UUID, text: String, + nestedList: List[List[String]], + nestedListSet: List[Set[String]], props: Map[String, List[String]], doubleProps: Map[Set[String], List[String]] ) @@ -46,6 +48,8 @@ abstract class NestedCollectionTable extends Table[ ] { object id extends UUIDColumn with PartitionKey object text extends StringColumn + object nestedList extends ListColumn[List[String]] + object nestedListSet extends ListColumn[Set[String]] object props extends MapColumn[String, List[String]] object doubleProps extends MapColumn[Set[String], List[String]] }