From 7d13a38d3a98d0215c7b5eae3f7fa8295af79f70 Mon Sep 17 00:00:00 2001 From: Chris Davenport Date: Thu, 11 Jun 2020 13:07:47 -0700 Subject: [PATCH 1/3] scalafmt --- .scalafmt.conf | 18 + build.sbt | 85 ++--- .../cosmos4s/IndexedCosmosContainer.scala | 321 +++++++++++------- .../banno/cosmos4s/RawCosmosContainer.scala | 108 +++--- .../com/banno/cosmos4s/ReactorCore.scala | 28 +- project/plugins.sbt | 3 +- 6 files changed, 337 insertions(+), 226 deletions(-) create mode 100644 .scalafmt.conf diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..e6fc0ce --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,18 @@ +version = 2.5.3 + +style = default + +maxColumn = 100 + +// Vertical alignment is pretty, but leads to bigger diffs +align.preset = none + +danglingParentheses.preset = false + +rewrite.rules = [ + AvoidInfix + RedundantBraces + RedundantParens + AsciiSortImports + PreferCurlyFors +] \ No newline at end of file diff --git a/build.sbt b/build.sbt index 4a7d68e..9fd6b48 100644 --- a/build.sbt +++ b/build.sbt @@ -10,25 +10,28 @@ val kindProjectorV = "0.11.0" val betterMonadicForV = "0.3.1" // Projects -lazy val `cosmos4s` = project.in(file(".")) +lazy val `cosmos4s` = project + .in(file(".")) .disablePlugins(MimaPlugin) .enablePlugins(NoPublishPlugin) .aggregate(core) -lazy val core = project.in(file("core")) +lazy val core = project + .in(file("core")) .settings(commonSettings) .settings( name := "cosmos4s" ) -lazy val site = project.in(file("site")) +lazy val site = project + .in(file("site")) .disablePlugins(MimaPlugin) .enablePlugins(MicrositesPlugin) .enablePlugins(MdocPlugin) .enablePlugins(NoPublishPlugin) .settings(commonSettings) .dependsOn(core) - .settings{ + .settings { import microsites._ Seq( micrositeName := "cosmos4s", @@ -62,8 +65,14 @@ lazy val site = project.in(file("site")) micrositePushSiteWith := GitHub4s, micrositeGithubToken := sys.env.get("GITHUB_TOKEN"), micrositeExtraMdFiles := Map( - file("CODE_OF_CONDUCT.md") -> ExtraMdFileConfig("code-of-conduct.md", "page", Map("title" -> "code of conduct", "section" -> "code of conduct", "position" -> "100")), - file("LICENSE") -> ExtraMdFileConfig("license.md", "page", Map("title" -> "license", "section" -> "license", "position" -> "101")) + file("CODE_OF_CONDUCT.md") -> ExtraMdFileConfig( + "code-of-conduct.md", + "page", + Map("title" -> "code of conduct", "section" -> "code of conduct", "position" -> "100")), + file("LICENSE") -> ExtraMdFileConfig( + "license.md", + "page", + Map("title" -> "license", "section" -> "license", "position" -> "101")) ) ) } @@ -72,41 +81,41 @@ lazy val site = project.in(file("site")) lazy val commonSettings = Seq( scalaVersion := "2.13.1", crossScalaVersions := Seq(scalaVersion.value, "2.12.13"), - - addCompilerPlugin("org.typelevel" %% "kind-projector" % kindProjectorV cross CrossVersion.full), - addCompilerPlugin("com.olegpy" %% "better-monadic-for" % betterMonadicForV), - + addCompilerPlugin( + ("org.typelevel" %% "kind-projector" % kindProjectorV).cross(CrossVersion.full)), + addCompilerPlugin("com.olegpy" %% "better-monadic-for" % betterMonadicForV), libraryDependencies ++= Seq( - "com.azure" % "azure-cosmos" % "4.0.1-beta.2", - - "org.typelevel" %% "cats-core" % catsV, - "org.typelevel" %% "cats-effect" % catsEffectV, - - "co.fs2" %% "fs2-reactive-streams" % fs2V, - - "io.circe" %% "circe-core" % circeV, - "io.circe" %% "circe-parser" % circeV, - "io.circe" %% "circe-jackson210" % "0.13.0", - - "org.specs2" %% "specs2-core" % specs2V % Test, - "org.specs2" %% "specs2-scalacheck" % specs2V % Test + "com.azure" % "azure-cosmos" % "4.0.1-beta.2", + "org.typelevel" %% "cats-core" % catsV, + "org.typelevel" %% "cats-effect" % catsEffectV, + "co.fs2" %% "fs2-reactive-streams" % fs2V, + "io.circe" %% "circe-core" % circeV, + "io.circe" %% "circe-parser" % circeV, + "io.circe" %% "circe-jackson210" % "0.13.0", + "org.specs2" %% "specs2-core" % specs2V % Test, + "org.specs2" %% "specs2-scalacheck" % specs2V % Test ) ) // General Settings -inThisBuild(List( - organization := "com.banno", - developers := List( - Developer("ChristopherDavenport", "Christopher Davenport", "chris@christopherdavenport.tech", url("https://github.com/ChristopherDavenport")) - ), - - homepage := Some(url("https://github.com/Banno/cosmos4s")), - licenses += ("Apache-2.0", new URL("https://www.apache.org/licenses/LICENSE-2.0.txt")), - - pomIncludeRepository := { _ => false}, - scalacOptions in (Compile, doc) ++= Seq( +inThisBuild( + List( + organization := "com.banno", + developers := List( + Developer( + "ChristopherDavenport", + "Christopher Davenport", + "chris@christopherdavenport.tech", + url("https://github.com/ChristopherDavenport")) + ), + homepage := Some(url("https://github.com/Banno/cosmos4s")), + licenses += ("Apache-2.0", new URL("https://www.apache.org/licenses/LICENSE-2.0.txt")), + pomIncludeRepository := { _ => false }, + scalacOptions in (Compile, doc) ++= Seq( "-groups", - "-sourcepath", (baseDirectory in LocalRootProject).value.getAbsolutePath, - "-doc-source-url", "https://github.com/banno/cosmos4s/blob/v" + version.value + "€{FILE_PATH}.scala" - ) -)) \ No newline at end of file + "-sourcepath", + (baseDirectory in LocalRootProject).value.getAbsolutePath, + "-doc-source-url", + "https://github.com/banno/cosmos4s/blob/v" + version.value + "€{FILE_PATH}.scala" + ) + )) diff --git a/core/src/main/scala/com/banno/cosmos4s/IndexedCosmosContainer.scala b/core/src/main/scala/com/banno/cosmos4s/IndexedCosmosContainer.scala index b28a698..1cd23a0 100644 --- a/core/src/main/scala/com/banno/cosmos4s/IndexedCosmosContainer.scala +++ b/core/src/main/scala/com/banno/cosmos4s/IndexedCosmosContainer.scala @@ -12,212 +12,277 @@ import com.fasterxml.jackson.databind.JsonNode import com.azure.cosmos._ import com.azure.cosmos.models._ -trait IndexedCosmosContainer[F[_], K, I, V]{ - def query(partitionKey: K, query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, V] - def queryCustom[A: Decoder](partitionKey: K, query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, A] +trait IndexedCosmosContainer[F[_], K, I, V] { + def query( + partitionKey: K, + query: String, + overrides: FeedOptions => FeedOptions = identity): Stream[F, V] + def queryCustom[A: Decoder]( + partitionKey: K, + query: String, + overrides: FeedOptions => FeedOptions = identity): Stream[F, A] def lookup(partitionKey: K, id: I): F[Option[V]] def insert(partitionKey: K, value: V): F[Option[V]] def replace(partitionKey: K, id: I, value: V): F[Option[V]] def upsert(partitionKey: K, value: V): F[Option[V]] def delete(partitionKey: K, id: I): F[Unit] - def mapK[G[_]](fk: F ~> G): IndexedCosmosContainer[G, K, I, V] = + def mapK[G[_]](fk: F ~> G): IndexedCosmosContainer[G, K, I, V] = new IndexedCosmosContainer.MapKIndexedCosmosContainer(this, fk) - def contramapPartitionKey[A](f: A => K): IndexedCosmosContainer[F, A, I, V] = - new IndexedCosmosContainer.ContramapPartitionKey(this,f) - def contramapId[A](f: A => I): IndexedCosmosContainer[F, K, A, V] = + def contramapPartitionKey[A](f: A => K): IndexedCosmosContainer[F, A, I, V] = + new IndexedCosmosContainer.ContramapPartitionKey(this, f) + def contramapId[A](f: A => I): IndexedCosmosContainer[F, K, A, V] = new IndexedCosmosContainer.ContramapId(this, f) - def semiInvariantFlatMap[A](f: V => F[A])(g: A => V)(implicit F: Monad[F]): IndexedCosmosContainer[F, K, I, A] = + def semiInvariantFlatMap[A](f: V => F[A])(g: A => V)(implicit + F: Monad[F]): IndexedCosmosContainer[F, K, I, A] = new IndexedCosmosContainer.SemiInvariantFlatMap(this, f, g) - def imapValue[A](f: V => A)(g: A => V)(implicit F: Functor[F]): IndexedCosmosContainer[F, K, I, A] = + def imapValue[A](f: V => A)(g: A => V)(implicit + F: Functor[F]): IndexedCosmosContainer[F, K, I, A] = new IndexedCosmosContainer.ImapValue(this, f, g) } object IndexedCosmosContainer { - def impl[F[_]: ConcurrentEffect: ContextShift](container: CosmosAsyncContainer, createFeedOptions: Option[F[FeedOptions]] = None): IndexedCosmosContainer[F, String, String, Json] = + def impl[F[_]: ConcurrentEffect: ContextShift]( + container: CosmosAsyncContainer, + createFeedOptions: Option[F[FeedOptions]] = None) + : IndexedCosmosContainer[F, String, String, Json] = new BaseImpl[F](container, createFeedOptions) - private class BaseImpl[F[_]: ConcurrentEffect: ContextShift](container: CosmosAsyncContainer, createFeedOptions: Option[F[FeedOptions]] = None) - extends IndexedCosmosContainer[F, String, String, Json] { - - def createFeedOptionsAlways = createFeedOptions.getOrElse(Sync[F].delay(new FeedOptions())) - import scala.collection.JavaConverters._ - def query(partitionKey: String, query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, Json] = - queryCustom[Json](partitionKey, query, overrides) - def queryCustom[A: Decoder](partitionKey: String, query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, A] = { - Stream.eval(createFeedOptionsAlways) - .map(overrides) - .flatMap{options => - ReactorCore.fluxToStream( - Sync[F].delay( - container.queryItems(query, options.setPartitionKey(new PartitionKey(partitionKey)), classOf[JsonNode]) - .byPage() - ) + private class BaseImpl[F[_]: ConcurrentEffect: ContextShift]( + container: CosmosAsyncContainer, + createFeedOptions: Option[F[FeedOptions]] = None) + extends IndexedCosmosContainer[F, String, String, Json] { + + def createFeedOptionsAlways = createFeedOptions.getOrElse(Sync[F].delay(new FeedOptions())) + import scala.collection.JavaConverters._ + def query( + partitionKey: String, + query: String, + overrides: FeedOptions => FeedOptions = identity): Stream[F, Json] = + queryCustom[Json](partitionKey, query, overrides) + def queryCustom[A: Decoder]( + partitionKey: String, + query: String, + overrides: FeedOptions => FeedOptions = identity): Stream[F, A] = + Stream + .eval(createFeedOptionsAlways) + .map(overrides) + .flatMap { options => + ReactorCore.fluxToStream( + Sync[F].delay( + container + .queryItems( + query, + options.setPartitionKey(new PartitionKey(partitionKey)), + classOf[JsonNode]) + .byPage() ) - }.flatMap(page => Stream.fromIterator(page.getElements().iterator().asScala)) - .map(jacksonToCirce) - .evalMap(_.as[A].liftTo[F]) - } - def lookup(partitionKey: String, id: String): F[Option[Json]] = - cats.data.OptionT( - ReactorCore.monoToEffectOpt(Sync[F].delay( - container.readItem(id, new PartitionKey(partitionKey), new CosmosItemRequestOptions(), classOf[JsonNode]) - )) - ) - .subflatMap(response => Option(response.getItem())) - .map(jacksonToCirce) - .value - def insert(partitionKey: String, value: Json): F[Option[Json]] = { - cats.data.OptionT.liftF(Sync[F].delay(new CosmosItemRequestOptions())) - .flatMap( options => - cats.data.OptionT( - ReactorCore.monoToEffectOpt(Sync[F].delay( - container.createItem(circeToJackson(value), new PartitionKey(partitionKey), options)) + ) + } + .flatMap(page => Stream.fromIterator(page.getElements().iterator().asScala)) + .map(jacksonToCirce) + .evalMap(_.as[A].liftTo[F]) + def lookup(partitionKey: String, id: String): F[Option[Json]] = + cats.data + .OptionT( + ReactorCore.monoToEffectOpt( + Sync[F].delay( + container.readItem( + id, + new PartitionKey(partitionKey), + new CosmosItemRequestOptions(), + classOf[JsonNode]) )) ) .subflatMap(response => Option(response.getItem())) .map(jacksonToCirce) .value - } - def replace(partitionKey: String, id: String, value: Json): F[Option[Json]] = { - cats.data.OptionT( - ReactorCore.monoToEffectOpt(Sync[F].delay( - container.replaceItem(circeToJackson(value), id, new PartitionKey(partitionKey)) - )) - ).subflatMap(response => Option(response.getItem())) + def insert(partitionKey: String, value: Json): F[Option[Json]] = + cats.data.OptionT + .liftF(Sync[F].delay(new CosmosItemRequestOptions())) + .flatMap(options => + cats.data.OptionT(ReactorCore.monoToEffectOpt(Sync[F].delay( + container.createItem(circeToJackson(value), new PartitionKey(partitionKey), options))))) + .subflatMap(response => Option(response.getItem())) .map(jacksonToCirce) .value - } - def upsert(partitionKey: String, value: Json): F[Option[Json]] = { - cats.data.OptionT( - ReactorCore.monoToEffectOpt(Sync[F].delay( - container.upsertItem(circeToJackson(value)) - )) - ).subflatMap(response => Option(response.getItem())) + def replace(partitionKey: String, id: String, value: Json): F[Option[Json]] = + cats.data + .OptionT( + ReactorCore.monoToEffectOpt( + Sync[F].delay( + container.replaceItem(circeToJackson(value), id, new PartitionKey(partitionKey)) + )) + ) + .subflatMap(response => Option(response.getItem())) + .map(jacksonToCirce) + .value + def upsert(partitionKey: String, value: Json): F[Option[Json]] = + cats.data + .OptionT( + ReactorCore.monoToEffectOpt( + Sync[F].delay( + container.upsertItem(circeToJackson(value)) + )) + ) + .subflatMap(response => Option(response.getItem())) .map(jacksonToCirce) .value - } - def delete(partitionKey: String, id: String): F[Unit] = { - ReactorCore.monoToEffect(Sync[F].delay( - container.deleteItem(id, new PartitionKey(partitionKey)) - )) + def delete(partitionKey: String, id: String): F[Unit] = + ReactorCore + .monoToEffect( + Sync[F].delay( + container.deleteItem(id, new PartitionKey(partitionKey)) + )) .void - } - } + } private class MapKIndexedCosmosContainer[F[_], G[_], K, I, V]( - base: IndexedCosmosContainer[F, K, I, V], - fk: F ~> G - ) extends IndexedCosmosContainer[G, K, I, V]{ - def query(partitionKey: K, query: String, overrides: FeedOptions => FeedOptions = identity): Stream[G, V] = + base: IndexedCosmosContainer[F, K, I, V], + fk: F ~> G + ) extends IndexedCosmosContainer[G, K, I, V] { + def query( + partitionKey: K, + query: String, + overrides: FeedOptions => FeedOptions = identity): Stream[G, V] = base.query(partitionKey, query, overrides).translate(fk) - def queryCustom[A: Decoder](partitionKey: K, query: String, overrides: FeedOptions => FeedOptions = identity): Stream[G,A] = + def queryCustom[A: Decoder]( + partitionKey: K, + query: String, + overrides: FeedOptions => FeedOptions = identity): Stream[G, A] = base.queryCustom[A](partitionKey, query, overrides).translate(fk) - def lookup(partitionKey: K, id: I): G[Option[V]] = + def lookup(partitionKey: K, id: I): G[Option[V]] = fk(base.lookup(partitionKey, id)) - def insert(partitionKey: K, value: V): G[Option[V]] = + def insert(partitionKey: K, value: V): G[Option[V]] = fk(base.insert(partitionKey, value)) def replace(partitionKey: K, id: I, value: V): G[Option[V]] = fk(base.replace(partitionKey, id, value)) - def upsert(partitionKey: K, value: V): G[Option[V]] = + def upsert(partitionKey: K, value: V): G[Option[V]] = fk(base.upsert(partitionKey, value)) - def delete(partitionKey: K, id: I): G[Unit] = + def delete(partitionKey: K, id: I): G[Unit] = fk(base.delete(partitionKey, id)) } private class ContramapPartitionKey[F[_], K, K2, I, V]( - base: IndexedCosmosContainer[F, K, I, V], - contra: K2 => K - ) extends IndexedCosmosContainer[F, K2, I, V]{ - def query(partitionKey: K2, query: String, overrides: FeedOptions => FeedOptions): Stream[F,V] = + base: IndexedCosmosContainer[F, K, I, V], + contra: K2 => K + ) extends IndexedCosmosContainer[F, K2, I, V] { + def query( + partitionKey: K2, + query: String, + overrides: FeedOptions => FeedOptions): Stream[F, V] = base.query(contra(partitionKey), query, overrides) - def queryCustom[A: Decoder](partitionKey: K2, query: String, overrides: FeedOptions => FeedOptions): Stream[F,A] = + def queryCustom[A: Decoder]( + partitionKey: K2, + query: String, + overrides: FeedOptions => FeedOptions): Stream[F, A] = base.queryCustom(contra(partitionKey), query, overrides) - def lookup(partitionKey: K2, id: I): F[Option[V]] = + def lookup(partitionKey: K2, id: I): F[Option[V]] = base.lookup(contra(partitionKey), id) - def insert(partitionKey: K2, value: V): F[Option[V]] = + def insert(partitionKey: K2, value: V): F[Option[V]] = base.insert(contra(partitionKey), value) - def replace(partitionKey: K2, id: I, value: V): F[Option[V]] = + def replace(partitionKey: K2, id: I, value: V): F[Option[V]] = base.replace(contra(partitionKey), id, value) - def upsert(partitionKey: K2, value: V): F[Option[V]] = + def upsert(partitionKey: K2, value: V): F[Option[V]] = base.upsert(contra(partitionKey), value) - def delete(partitionKey: K2, id: I): F[Unit] = + def delete(partitionKey: K2, id: I): F[Unit] = base.delete(contra(partitionKey), id) } private class ContramapId[F[_], K, I, I2, V]( - base: IndexedCosmosContainer[F, K, I, V], - contra: I2 => I - ) extends IndexedCosmosContainer[F, K, I2, V]{ - def query(partitionKey: K, query: String, overrides: FeedOptions => FeedOptions): Stream[F,V] = + base: IndexedCosmosContainer[F, K, I, V], + contra: I2 => I + ) extends IndexedCosmosContainer[F, K, I2, V] { + def query(partitionKey: K, query: String, overrides: FeedOptions => FeedOptions): Stream[F, V] = base.query(partitionKey, query, overrides) - def queryCustom[A: Decoder](partitionKey: K, query: String, overrides: FeedOptions => FeedOptions): Stream[F,A] = + def queryCustom[A: Decoder]( + partitionKey: K, + query: String, + overrides: FeedOptions => FeedOptions): Stream[F, A] = base.queryCustom(partitionKey, query, overrides) - def lookup(partitionKey: K, id: I2): F[Option[V]] = + def lookup(partitionKey: K, id: I2): F[Option[V]] = base.lookup(partitionKey, contra(id)) - def insert(partitionKey: K, value: V): F[Option[V]] = + def insert(partitionKey: K, value: V): F[Option[V]] = base.insert(partitionKey, value) - def replace(partitionKey: K, id: I2, value: V): F[Option[V]] = + def replace(partitionKey: K, id: I2, value: V): F[Option[V]] = base.replace(partitionKey, contra(id), value) - def upsert(partitionKey: K, value: V): F[Option[V]] = + def upsert(partitionKey: K, value: V): F[Option[V]] = base.upsert(partitionKey, value) - def delete(partitionKey: K, id: I2): F[Unit] = + def delete(partitionKey: K, id: I2): F[Unit] = base.delete(partitionKey, contra(id)) } private class SemiInvariantFlatMap[F[_]: Monad, K, I, V, V2]( - base: IndexedCosmosContainer[F, K, I, V], - f: V => F[V2], - g: V2 => V - ) extends IndexedCosmosContainer[F, K, I, V2]{ - def query(partitionKey: K, query: String, overrides: FeedOptions => FeedOptions): Stream[F,V2] = - base.query(partitionKey, query, overrides) + base: IndexedCosmosContainer[F, K, I, V], + f: V => F[V2], + g: V2 => V + ) extends IndexedCosmosContainer[F, K, I, V2] { + def query( + partitionKey: K, + query: String, + overrides: FeedOptions => FeedOptions): Stream[F, V2] = + base + .query(partitionKey, query, overrides) .evalMap(f) - def queryCustom[A: Decoder](partitionKey: K, query: String, overrides: FeedOptions => FeedOptions): Stream[F,A] = + def queryCustom[A: Decoder]( + partitionKey: K, + query: String, + overrides: FeedOptions => FeedOptions): Stream[F, A] = base.queryCustom(partitionKey, query, overrides) - def lookup(partitionKey: K, id: I): F[Option[V2]] = + def lookup(partitionKey: K, id: I): F[Option[V2]] = base.lookup(partitionKey, id).flatMap(_.traverse(f)) - def insert(partitionKey: K, value: V2): F[Option[V2]] = + def insert(partitionKey: K, value: V2): F[Option[V2]] = base.insert(partitionKey, g(value)).flatMap(_.traverse(f)) - def replace(partitionKey: K, id: I, value: V2): F[Option[V2]] = + def replace(partitionKey: K, id: I, value: V2): F[Option[V2]] = base.replace(partitionKey, id, g(value)).flatMap(_.traverse(f)) - def upsert(partitionKey: K, value: V2): F[Option[V2]] = + def upsert(partitionKey: K, value: V2): F[Option[V2]] = base.upsert(partitionKey, g(value)).flatMap(_.traverse(f)) - def delete(partitionKey: K, id: I): F[Unit] = + def delete(partitionKey: K, id: I): F[Unit] = base.delete(partitionKey, id) } private class ImapValue[F[_]: Functor, K, I, V, V2]( - base: IndexedCosmosContainer[F, K, I, V], - f: V => V2, - g: V2 => V - ) extends IndexedCosmosContainer[F, K, I, V2]{ - def query(partitionKey: K, query: String, overrides: FeedOptions => FeedOptions): Stream[F,V2] = - base.query(partitionKey, query, overrides) + base: IndexedCosmosContainer[F, K, I, V], + f: V => V2, + g: V2 => V + ) extends IndexedCosmosContainer[F, K, I, V2] { + def query( + partitionKey: K, + query: String, + overrides: FeedOptions => FeedOptions): Stream[F, V2] = + base + .query(partitionKey, query, overrides) .map(f) - def queryCustom[A: Decoder](partitionKey: K, query: String, overrides: FeedOptions => FeedOptions): Stream[F,A] = + def queryCustom[A: Decoder]( + partitionKey: K, + query: String, + overrides: FeedOptions => FeedOptions): Stream[F, A] = base.queryCustom(partitionKey, query, overrides) - def lookup(partitionKey: K, id: I): F[Option[V2]] = + def lookup(partitionKey: K, id: I): F[Option[V2]] = base.lookup(partitionKey, id).map(_.map(f)) - def insert(partitionKey: K, value: V2): F[Option[V2]] = + def insert(partitionKey: K, value: V2): F[Option[V2]] = base.insert(partitionKey, g(value)).map(_.map(f)) - def replace(partitionKey: K, id: I, value: V2): F[Option[V2]] = + def replace(partitionKey: K, id: I, value: V2): F[Option[V2]] = base.replace(partitionKey, id, g(value)).map(_.map(f)) - def upsert(partitionKey: K, value: V2): F[Option[V2]] = + def upsert(partitionKey: K, value: V2): F[Option[V2]] = base.upsert(partitionKey, g(value)).map(_.map(f)) - def delete(partitionKey: K, id: I): F[Unit] = + def delete(partitionKey: K, id: I): F[Unit] = base.delete(partitionKey, id) } - implicit def partitionKey[F[_], I, V] = new Contravariant[IndexedCosmosContainer[F,*, I, V]]{ - def contramap[A, B](fa: IndexedCosmosContainer[F,A,I,V])(f: B => A): IndexedCosmosContainer[F,B,I,V] = - fa.contramapPartitionKey(f) - } + implicit def partitionKey[F[_], I, V] = + new Contravariant[IndexedCosmosContainer[F, *, I, V]] { + def contramap[A, B](fa: IndexedCosmosContainer[F, A, I, V])( + f: B => A): IndexedCosmosContainer[F, B, I, V] = + fa.contramapPartitionKey(f) + } - implicit def id[F[_], K, V] = new Contravariant[IndexedCosmosContainer[F, K, *, V]]{ - def contramap[A, B](fa: IndexedCosmosContainer[F,K,A,V])(f: B => A): IndexedCosmosContainer[F,K,B,V] = - fa.contramapId(f) - } -} \ No newline at end of file + implicit def id[F[_], K, V] = + new Contravariant[IndexedCosmosContainer[F, K, *, V]] { + def contramap[A, B](fa: IndexedCosmosContainer[F, K, A, V])( + f: B => A): IndexedCosmosContainer[F, K, B, V] = + fa.contramapId(f) + } +} diff --git a/core/src/main/scala/com/banno/cosmos4s/RawCosmosContainer.scala b/core/src/main/scala/com/banno/cosmos4s/RawCosmosContainer.scala index 924d8b9..fa7a2ae 100644 --- a/core/src/main/scala/com/banno/cosmos4s/RawCosmosContainer.scala +++ b/core/src/main/scala/com/banno/cosmos4s/RawCosmosContainer.scala @@ -12,79 +12,95 @@ import com.fasterxml.jackson.databind.JsonNode import com.azure.cosmos._ import com.azure.cosmos.models._ - -trait RawCosmosContainer[F[_], V]{ +trait RawCosmosContainer[F[_], V] { def queryRaw(query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, V] - def queryCustomRaw[A: Decoder](query: String,overrides: FeedOptions => FeedOptions = identity): Stream[F, A] + def queryCustomRaw[A: Decoder]( + query: String, + overrides: FeedOptions => FeedOptions = identity): Stream[F, A] - def map[A](f: V => A): RawCosmosContainer[F, A] = + def map[A](f: V => A): RawCosmosContainer[F, A] = new RawCosmosContainer.MapValueRawCosmosContainter(this, f) - def evalMap[A](f: V => F[A]): RawCosmosContainer[F, A] = + def evalMap[A](f: V => F[A]): RawCosmosContainer[F, A] = new RawCosmosContainer.EvalMapRawCosmosContainer(this, f) - def mapK[G[_]](fk: F ~> G): RawCosmosContainer[G, V] = + def mapK[G[_]](fk: F ~> G): RawCosmosContainer[G, V] = new RawCosmosContainer.MapKRawCosmosContainer(this, fk) } object RawCosmosContainer { - def impl[F[_]: ConcurrentEffect: ContextShift](container: CosmosAsyncContainer, createFeedOptions: Option[F[FeedOptions]] = None): RawCosmosContainer[F,Json] = + def impl[F[_]: ConcurrentEffect: ContextShift]( + container: CosmosAsyncContainer, + createFeedOptions: Option[F[FeedOptions]] = None): RawCosmosContainer[F, Json] = new BaseImpl[F](container, createFeedOptions) - private class BaseImpl[F[_]: ConcurrentEffect: ContextShift](container: CosmosAsyncContainer, createFeedOptions: Option[F[FeedOptions]] = None) - extends RawCosmosContainer[F, Json]{ - def createFeedOptionsAlways = createFeedOptions.getOrElse(Sync[F].delay(new FeedOptions())) - import scala.collection.JavaConverters._ - def queryRaw(query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, Json] = - queryCustomRaw[Json](query, overrides) - def queryCustomRaw[A: Decoder](query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, A] = { - Stream.eval(createFeedOptionsAlways) - .map(overrides) - .flatMap{options => - ReactorCore.fluxToStream( - Sync[F].delay( - container.queryItems(query, options, classOf[JsonNode]) - .byPage() - ) + private class BaseImpl[F[_]: ConcurrentEffect: ContextShift]( + container: CosmosAsyncContainer, + createFeedOptions: Option[F[FeedOptions]] = None) + extends RawCosmosContainer[F, Json] { + def createFeedOptionsAlways = createFeedOptions.getOrElse(Sync[F].delay(new FeedOptions())) + import scala.collection.JavaConverters._ + def queryRaw(query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, Json] = + queryCustomRaw[Json](query, overrides) + def queryCustomRaw[A: Decoder]( + query: String, + overrides: FeedOptions => FeedOptions = identity): Stream[F, A] = + Stream + .eval(createFeedOptionsAlways) + .map(overrides) + .flatMap { options => + ReactorCore.fluxToStream( + Sync[F].delay( + container + .queryItems(query, options, classOf[JsonNode]) + .byPage() ) - }.flatMap(page => Stream.fromIterator(page.getElements().iterator().asScala)) - .map(jacksonToCirce) - .evalMap(_.as[A].liftTo[F]) - } - } + ) + } + .flatMap(page => Stream.fromIterator(page.getElements().iterator().asScala)) + .map(jacksonToCirce) + .evalMap(_.as[A].liftTo[F]) + } private class MapKRawCosmosContainer[F[_], G[_], V]( - base: RawCosmosContainer[F, V], - fk: F ~> G - ) extends RawCosmosContainer[G, V]{ - def queryRaw(query: String, overrides: FeedOptions => FeedOptions = identity): Stream[G, V] = + base: RawCosmosContainer[F, V], + fk: F ~> G + ) extends RawCosmosContainer[G, V] { + def queryRaw(query: String, overrides: FeedOptions => FeedOptions = identity): Stream[G, V] = base.queryRaw(query, overrides).translate(fk) - def queryCustomRaw[A: Decoder](query: String,overrides: FeedOptions => FeedOptions = identity): Stream[G, A] = + def queryCustomRaw[A: Decoder]( + query: String, + overrides: FeedOptions => FeedOptions = identity): Stream[G, A] = base.queryCustomRaw(query, overrides).translate(fk) } private class MapValueRawCosmosContainter[F[_], V, A]( - base: RawCosmosContainer[F, V], - f: V => A - ) extends RawCosmosContainer[F, A]{ - def queryRaw(query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, A] = + base: RawCosmosContainer[F, V], + f: V => A + ) extends RawCosmosContainer[F, A] { + def queryRaw(query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, A] = base.queryRaw(query, overrides).map(f) - def queryCustomRaw[B: Decoder](query: String, overrides: FeedOptions => FeedOptions): Stream[F,B] = + def queryCustomRaw[B: Decoder]( + query: String, + overrides: FeedOptions => FeedOptions): Stream[F, B] = base.queryCustomRaw(query, overrides) } private class EvalMapRawCosmosContainer[F[_], V, A]( - base: RawCosmosContainer[F, V], - f: V => F[A] - ) extends RawCosmosContainer[F, A]{ - def queryRaw(query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, A] = + base: RawCosmosContainer[F, V], + f: V => F[A] + ) extends RawCosmosContainer[F, A] { + def queryRaw(query: String, overrides: FeedOptions => FeedOptions = identity): Stream[F, A] = base.queryRaw(query, overrides).evalMap(f) - def queryCustomRaw[B: Decoder](query: String, overrides: FeedOptions => FeedOptions): Stream[F,B] = + def queryCustomRaw[B: Decoder]( + query: String, + overrides: FeedOptions => FeedOptions): Stream[F, B] = base.queryCustomRaw(query, overrides) } - implicit def functor[F[_]]: Functor[RawCosmosContainer[F, *]] = new Functor[RawCosmosContainer[F, *]]{ - def map[A, B](fa: RawCosmosContainer[F,A])(f: A => B): RawCosmosContainer[F,B] = fa.map(f) - } + implicit def functor[F[_]]: Functor[RawCosmosContainer[F, *]] = + new Functor[RawCosmosContainer[F, *]] { + def map[A, B](fa: RawCosmosContainer[F, A])(f: A => B): RawCosmosContainer[F, B] = fa.map(f) + } -} \ No newline at end of file +} diff --git a/core/src/main/scala/com/banno/cosmos4s/ReactorCore.scala b/core/src/main/scala/com/banno/cosmos4s/ReactorCore.scala index d0c3ffd..641fabc 100644 --- a/core/src/main/scala/com/banno/cosmos4s/ReactorCore.scala +++ b/core/src/main/scala/com/banno/cosmos4s/ReactorCore.scala @@ -9,23 +9,25 @@ import fs2._ import fs2.interop.reactivestreams._ private[cosmos4s] object ReactorCore { - def monoToEffectOpt[F[_]: ConcurrentEffect: ContextShift, A](m: F[Mono[A]]): F[Option[A]] = { - Stream.eval(m) + def monoToEffectOpt[F[_]: ConcurrentEffect: ContextShift, A](m: F[Mono[A]]): F[Option[A]] = + Stream + .eval(m) .flatMap(fromPublisher[F, A]) .compile .last - }.guarantee(ContextShift[F].shift) + .guarantee(ContextShift[F].shift) - def monoToEffect[F[_]: ConcurrentEffect: ContextShift, A](m: F[Mono[A]]): F[A] = - monoToEffectOpt(m).flatMap(opt => - opt.fold(Sync[F].raiseError[A](new Throwable("Mono to Effect Conversion failed to produce value"))){ + def monoToEffect[F[_]: ConcurrentEffect: ContextShift, A](m: F[Mono[A]]): F[A] = + monoToEffectOpt(m).flatMap(opt => + opt.fold( + Sync[F].raiseError[A](new Throwable("Mono to Effect Conversion failed to produce value"))) { Sync[F].pure - } - ) - def fluxToStream[F[_]: ConcurrentEffect: ContextShift, A](m: F[Flux[A]]): fs2.Stream[F, A] = { - Stream.eval(m) + }) + def fluxToStream[F[_]: ConcurrentEffect: ContextShift, A](m: F[Flux[A]]): fs2.Stream[F, A] = + Stream + .eval(m) .flatMap(fromPublisher[F, A]) .chunks - .flatMap(chunk => Stream.eval(ContextShift[F].shift).flatMap(_ => Stream.chunk(chunk).covary[F])) - } -} \ No newline at end of file + .flatMap(chunk => + Stream.eval(ContextShift[F].shift).flatMap(_ => Stream.chunk(chunk).covary[F])) +} diff --git a/project/plugins.sbt b/project/plugins.sbt index 286649b..2ec6022 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -5,4 +5,5 @@ addSbtPlugin("io.chrisdavenport" % "sbt-mima-version-check" % "0.1.2") addSbtPlugin("io.chrisdavenport" % "sbt-no-publish" % "0.1.0") addSbtPlugin("com.47deg" % "sbt-microsites" % "1.1.5") -addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.1.5") \ No newline at end of file +addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.1.5") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.0") From f6859b4e361b7415c1b4f8a5aa9d8e8de2ab35a5 Mon Sep 17 00:00:00 2001 From: Chris Davenport Date: Thu, 11 Jun 2020 13:13:03 -0700 Subject: [PATCH 2/3] Header Check and Application --- build.sbt | 2 ++ .../banno/cosmos4s/IndexedCosmosContainer.scala | 16 ++++++++++++++++ .../com/banno/cosmos4s/RawCosmosContainer.scala | 16 ++++++++++++++++ .../scala/com/banno/cosmos4s/ReactorCore.scala | 16 ++++++++++++++++ project/plugins.sbt | 1 + 5 files changed, 51 insertions(+) diff --git a/build.sbt b/build.sbt index 9fd6b48..081b6d3 100644 --- a/build.sbt +++ b/build.sbt @@ -109,6 +109,8 @@ inThisBuild( url("https://github.com/ChristopherDavenport")) ), homepage := Some(url("https://github.com/Banno/cosmos4s")), + organizationName := "Jack Henry & Associates, Inc.®", + startYear := Some(2020), licenses += ("Apache-2.0", new URL("https://www.apache.org/licenses/LICENSE-2.0.txt")), pomIncludeRepository := { _ => false }, scalacOptions in (Compile, doc) ++= Seq( diff --git a/core/src/main/scala/com/banno/cosmos4s/IndexedCosmosContainer.scala b/core/src/main/scala/com/banno/cosmos4s/IndexedCosmosContainer.scala index 1cd23a0..cff5b29 100644 --- a/core/src/main/scala/com/banno/cosmos4s/IndexedCosmosContainer.scala +++ b/core/src/main/scala/com/banno/cosmos4s/IndexedCosmosContainer.scala @@ -1,3 +1,19 @@ +/* + * Copyright 2020 Jack Henry & Associates, Inc.® + * + * 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.banno.cosmos4s import _root_.io.circe._ diff --git a/core/src/main/scala/com/banno/cosmos4s/RawCosmosContainer.scala b/core/src/main/scala/com/banno/cosmos4s/RawCosmosContainer.scala index fa7a2ae..e1c414f 100644 --- a/core/src/main/scala/com/banno/cosmos4s/RawCosmosContainer.scala +++ b/core/src/main/scala/com/banno/cosmos4s/RawCosmosContainer.scala @@ -1,3 +1,19 @@ +/* + * Copyright 2020 Jack Henry & Associates, Inc.® + * + * 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.banno.cosmos4s import _root_.io.circe._ diff --git a/core/src/main/scala/com/banno/cosmos4s/ReactorCore.scala b/core/src/main/scala/com/banno/cosmos4s/ReactorCore.scala index 641fabc..665b2f8 100644 --- a/core/src/main/scala/com/banno/cosmos4s/ReactorCore.scala +++ b/core/src/main/scala/com/banno/cosmos4s/ReactorCore.scala @@ -1,3 +1,19 @@ +/* + * Copyright 2020 Jack Henry & Associates, Inc.® + * + * 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.banno.cosmos4s import cats.implicits._ diff --git a/project/plugins.sbt b/project/plugins.sbt index 2ec6022..b5fe49e 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -7,3 +7,4 @@ addSbtPlugin("io.chrisdavenport" % "sbt-no-publish" % "0.1.0") addSbtPlugin("com.47deg" % "sbt-microsites" % "1.1.5") addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.1.5") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.0") +addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.6.0") From 830832f87a29c3be2610b3cee782734040938ce5 Mon Sep 17 00:00:00 2001 From: Chris Davenport Date: Thu, 11 Jun 2020 13:15:35 -0700 Subject: [PATCH 3/3] Fix Scala Version --- .github/workflows/ci.yaml | 4 ++-- .github/workflows/release.yaml | 2 +- build.sbt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1c54991..6d50845 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -3,7 +3,7 @@ on: [push, pull_request] env: CI: true CI_SNAPSHOT_RELEASE: +publishSigned - SCALA_VERSION: 2.12.13 + SCALA_VERSION: 2.12.11 jobs: validate: name: Scala ${{ matrix.scala }}, Java ${{ matrix.java }} @@ -12,7 +12,7 @@ jobs: fail-fast: false matrix: java: [adopt@1.8, adopt@1.11, adopt@1.14] - scala: [2.12.13, 2.13.1] + scala: [2.12.11, 2.13.1] env: SCALA_VERSION: ${{ matrix.scala }} steps: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index fb0fb24..2532f75 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -7,7 +7,7 @@ on: - '*' env: CI: true - SCALA_VERSION: 2.12.13 + SCALA_VERSION: 2.12.11 jobs: release: name: Release diff --git a/build.sbt b/build.sbt index 081b6d3..60dabce 100644 --- a/build.sbt +++ b/build.sbt @@ -80,7 +80,7 @@ lazy val site = project // General Settings lazy val commonSettings = Seq( scalaVersion := "2.13.1", - crossScalaVersions := Seq(scalaVersion.value, "2.12.13"), + crossScalaVersions := Seq(scalaVersion.value, "2.12.11"), addCompilerPlugin( ("org.typelevel" %% "kind-projector" % kindProjectorV).cross(CrossVersion.full)), addCompilerPlugin("com.olegpy" %% "better-monadic-for" % betterMonadicForV),