diff --git a/README.md b/README.md index cd21a2d03..ed8eceb12 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,9 @@ Data can also be fetched asynchronously in a `Future` or `ZIO`. ## Main features of Molecule - Support for [PostgreSQL](https://www.postgresql.org), [SQlite](https://sqlite.org), [MySQL](https://www.mysql.com), [MariaDB](https://mariadb.com), [H2](https://h2database.com/html/main.html) and [Datomic](http://www.datomic.com) databases. More can easily be added -- Molecules for any database behave identically. Each db pass the same SPI compliance test suite (~1500 tests). +- Molecules for any database behave identically. Each db pass the same SPI compliance test suite (+1500 tests). - Targets Scala 3.3, 2.13 and 2.12 on JVM and JS platforms -- Synchronous, Asynchronous (Future) and ZIO APIs +- Synchronous, Asynchronous (Future), ZIO and cats.effect.IO APIs - All Scala primitive types and collection types available as molecule attributes (!) - Typed methods to compose even complex molecules: - Expression/aggregation functions @@ -133,6 +133,15 @@ val persons: ZIO[Conn, MoleculeError, List[(String, Int, String)]] = Person.name.age.Address.street.query.get ``` +IO API + +```scala +import molecule.sql.postgres.io._ + +val persons: cats.effect.IO[List[(String, Int, String)]] = + Person.name.age.Address.street.query.get +``` + ### Transact data Save one entity @@ -181,7 +190,7 @@ Add the following to your build files: `project/build.properties`: ``` -sbt.version = 1.10.1 +sbt.version = 1.10.2 ``` `project/plugins.sbt`: @@ -198,12 +207,12 @@ lazy val yourProject = project.in(file("app")) .settings( libraryDependencies ++= Seq( // One or more of: - "org.scalamolecule" %%% "molecule-sql-postgres" % "0.10.1", - "org.scalamolecule" %%% "molecule-sql-sqlite" % "0.10.1", - "org.scalamolecule" %%% "molecule-sql-mysql" % "0.10.1", - "org.scalamolecule" %%% "molecule-sql-mariadb" % "0.10.1", - "org.scalamolecule" %%% "molecule-sql-h2" % "0.10.1", - "org.scalamolecule" %%% "molecule-datalog-datomic" % "0.10.1", + "org.scalamolecule" %%% "molecule-sql-postgres" % "0.11.0", + "org.scalamolecule" %%% "molecule-sql-sqlite" % "0.11.0", + "org.scalamolecule" %%% "molecule-sql-mysql" % "0.11.0", + "org.scalamolecule" %%% "molecule-sql-mariadb" % "0.11.0", + "org.scalamolecule" %%% "molecule-sql-h2" % "0.11.0", + "org.scalamolecule" %%% "molecule-datalog-datomic" % "0.11.0", ), moleculeSchemas := Seq("app/dataModel") // paths to directories with Data Model definition files ) diff --git a/build.sbt b/build.sbt index f0a6a0ffe..884ef8a6b 100644 --- a/build.sbt +++ b/build.sbt @@ -1,11 +1,11 @@ import org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv -import org.scalajs.linker.interface.{ESVersion, ModuleSplitStyle} +import org.scalajs.linker.interface.ESVersion import sbt.Keys.libraryDependencies import scala.collection.Seq val scala212 = "2.12.20" -val scala213 = "2.13.14" +val scala213 = "2.13.15" val scala3 = "3.3.3" val allScala = Seq(scala212, scala213, scala3) @@ -20,7 +20,7 @@ inThisBuild( organizationName := "ScalaMolecule", organizationHomepage := Some(url("http://www.scalamolecule.org")), versionScheme := Some("early-semver"), - version := "0.10.2-SNAPSHOT", + version := "0.11.0", scalaVersion := scala213, crossScalaVersions := allScala, @@ -50,20 +50,20 @@ lazy val root = project datalogCore.jvm, datalogDatomic.js, datalogDatomic.jvm, - // // graphql.js, - // // graphql.jvm, + // graphql.js, + // graphql.jvm, sqlCore.js, sqlCore.jvm, - // sqlH2.js, - // sqlH2.jvm, - // sqlMariaDB.js, - // sqlMariaDB.jvm, - // sqlMySQL.js, - // sqlMySQL.jvm, + sqlH2.js, + sqlH2.jvm, + sqlMariaDB.js, + sqlMariaDB.jvm, + sqlMySQL.js, + sqlMySQL.jvm, sqlPostgreSQL.js, sqlPostgreSQL.jvm, - // sqlSQlite.js, - // sqlSQlite.jvm, + sqlSQlite.js, + sqlSQlite.jvm, ) lazy val base = crossProject(JSPlatform, JVMPlatform) @@ -96,7 +96,7 @@ lazy val core = crossProject(JSPlatform, JVMPlatform) .settings(compilerArgs) .settings( libraryDependencies ++= Seq( - "io.suzaku" %%% "boopickle" % "1.4.0", // binary serialization for rpc + "io.suzaku" %%% "boopickle" % "1.5.0", // binary serialization for rpc "dev.zio" %%% "zio" % zioVersion, // zio api "org.typelevel" %%% "cats-effect" % "3.5.4", // cats api ) @@ -141,49 +141,8 @@ lazy val coreTests = crossProject(JSPlatform, JVMPlatform) "dev.zio" %%% "zio-test" % zioVersion % Test, "dev.zio" %%% "zio-test-sbt" % zioVersion % Test, - // "org.typelevel" %%% "munit-cats-effect" % "2.0.0" % Test, - "org.typelevel" %%% "munit-cats-effect" % "2.0.0", + "org.typelevel" %%% "munit-cats-effect" % "2.0.0", // also used in main (IO api) ), - - // // Temporarily limit number of tests to be compiled by sbt (comment out this whole sbt setting to test all) - // // Note that intellij doesn't recognize this setting - there you can right-click on files and exclude - // unmanagedSources / excludeFilter := { - // val test = "src/test/scala/molecule/coreTests" - // def path(platform: String) = (baseDirectory.value / s"../$platform/$test").getCanonicalPath - // val jsTests = path("js") - // val jvmTests = path("jvm") - // val sharedTests = path("shared") - // val allowed = Seq( - // // sharedTests + "/spi/aggr", - // // sharedTests + "/spi/api", - // // sharedTests + "/spi/crud", - // // sharedTests + "/spi/crud/update", - // // sharedTests + "/spi/crud/update/ops", - // // sharedTests + "/spi/crud/update/relation", - // // sharedTests + "/spi/filter", - // // sharedTests + "/spi/filterAttr", - // // sharedTests + "/spi/inspect", - // sharedTests + "/spi/pagination", - // // sharedTests + "/spi/partitions", - // // sharedTests + "/spi/relation", - // // sharedTests + "/spi/sort", - // // sharedTests + "/spi/subscription", - // // sharedTests + "/spi/time", - // // sharedTests + "/spi/validation", - // // sharedTests + "/spi", - // - // sharedTests + "/setup", - // sharedTests + "/util", - // jvmTests + "/setup", - // jsTests + "/setup", - // ) - // new SimpleFileFilter(f => - // (f.getCanonicalPath.startsWith(jsTests) || - // f.getCanonicalPath.startsWith(jvmTests) || - // f.getCanonicalPath.startsWith(sharedTests)) && - // !allowed.exists(p => f.getCanonicalPath.startsWith(p)) - // ) - // }, ) .jsSettings( jsEnvironment, @@ -222,51 +181,7 @@ lazy val datalogDatomic = crossProject(JSPlatform, JVMPlatform) .settings(name := "molecule-datalog-datomic") .settings(doPublish) .settings(compilerArgs) - .settings( - testFrameworks := testingFrameworks, - - // // Temporarily limit number of tests to be compiled by sbt (comment out this whole sbt setting to test all) - // // Note that intellij doesn't recognize this setting - there you can right-click on files and exclude - // unmanagedSources / excludeFilter := { - // val test = "src/test/scala/molecule/datalog/datomic" - // def path(platform: String) = (baseDirectory.value / s"../$platform/$test").getCanonicalPath - // val jsTests = path("js") - // val jvmTests = path("jvm") - // val sharedTests = path("shared") - // val allowed = Seq( - // // sharedTests + "/compliance/aggr", - // sharedTests + "/compliance/api", - // // sharedTests + "/compliance/crud", - // // sharedTests + "/compliance/crud/update", - // // sharedTests + "/compliance/crud/update/ops", - // // sharedTests + "/compliance/crud/update/relation", - // // sharedTests + "/compliance/filter", - // // sharedTests + "/compliance/filterAttr", - // // sharedTests + "/compliance/inspect", - // // sharedTests + "/compliance/pagination", - // // sharedTests + "/compliance/partitions", - // // sharedTests + "/compliance/relation", - // // sharedTests + "/compliance/sort", - // sharedTests + "/compliance/subscription", - // // sharedTests + "/compliance/time", - // // sharedTests + "/compliance/validation", - // // sharedTests + "/compliance", - // - // sharedTests + "/setup", - // jvmTests + "/setup", - // jsTests + "/setup", - // jsTests + "/AdhocJS_datomic.scala", - // jvmTests + "/AdhocJVM_datomic.scala", - // // sharedTests + "/Adhoc_datomic.scala", - // ) - // new SimpleFileFilter(f => - // (f.getCanonicalPath.startsWith(jsTests) || - // f.getCanonicalPath.startsWith(jvmTests) || - // f.getCanonicalPath.startsWith(sharedTests)) && - // !allowed.exists(p => f.getCanonicalPath.startsWith(p)) - // ) - // }, - ) + .settings(testFrameworks := testingFrameworks) .jsSettings(jsEnvironment) .dependsOn(datalogCore) .dependsOn(coreTests % "test->test") @@ -331,110 +246,64 @@ lazy val sqlCore = crossProject(JSPlatform, JVMPlatform) ), ) .jsSettings(jsEnvironment) - // .jvmSettings( - // libraryDependencies ++= Seq( - // "com.zaxxer" % "HikariCP" % "5.1.0" - // ) - // ) .dependsOn(core) -//lazy val sqlH2 = crossProject(JSPlatform, JVMPlatform) -// .crossType(CrossType.Full) -// .in(file("sql/h2")) -// .settings(name := "molecule-sql-h2") -// .settings(doPublish) -// .settings(compilerArgs) -// .settings( -// testFrameworks := testingFrameworks, -//// unmanagedSources / excludeFilter := { -//// val test = "src/test/scala/molecule/sql/h2" -//// def path(platform: String) = (baseDirectory.value / s"../$platform/$test").getCanonicalPath -//// val jsTests = path("js") -//// val jvmTests = path("jvm") -//// val sharedTests = path("shared") -//// val allowed = Seq( -//// // sharedTests + "/compliance/aggr", -//// // sharedTests + "/compliance/api", -//// // sharedTests + "/compliance/crud", -//// // sharedTests + "/compliance/crud/update", -//// // sharedTests + "/compliance/crud/update/ops", -//// // sharedTests + "/compliance/crud/update/relation", -//// // sharedTests + "/compliance/filter", -//// // sharedTests + "/compliance/filterAttr", -//// // sharedTests + "/compliance/inspect", -//// // sharedTests + "/compliance/pagination", -//// // sharedTests + "/compliance/partitions", -//// // sharedTests + "/compliance/relation", -//// // sharedTests + "/compliance/sort", -//// // sharedTests + "/compliance/subscription", -//// // sharedTests + "/compliance/time", -//// // sharedTests + "/compliance/validation", -//// // sharedTests + "/compliance", -//// -//// sharedTests + "/setup", -//// jvmTests + "/setup", -//// jsTests + "/setup", -//// jsTests + "/AdhocJS_h2.scala", -//// jvmTests + "/AdhocJVM_h2.scala", -//// // sharedTests + "/Adhoc_datomic.scala", -//// ) -//// new SimpleFileFilter(f => -//// (f.getCanonicalPath.startsWith(jsTests) || -//// f.getCanonicalPath.startsWith(jvmTests) || -//// f.getCanonicalPath.startsWith(sharedTests)) && -//// !allowed.exists(p => f.getCanonicalPath.startsWith(p)) -//// ) -//// }, -// ) -// .jsSettings(jsEnvironment) -// .jvmSettings( -// libraryDependencies ++= Seq( -// "com.h2database" % "h2" % "2.3.232" -// ), -// Test / fork := true -// ) -// .dependsOn(sqlCore) -// .dependsOn(coreTests % "test->test") +lazy val sqlH2 = crossProject(JSPlatform, JVMPlatform) + .crossType(CrossType.Full) + .in(file("sql/h2")) + .settings(name := "molecule-sql-h2") + .settings(doPublish) + .settings(compilerArgs) + .settings(testFrameworks := testingFrameworks) + .jsSettings(jsEnvironment) + .jvmSettings( + libraryDependencies ++= Seq( + "com.h2database" % "h2" % "2.3.232" + ), + Test / fork := true + ) + .dependsOn(sqlCore) + .dependsOn(coreTests % "test->test") -//lazy val sqlMariaDB = crossProject(JSPlatform, JVMPlatform) -// .crossType(CrossType.Full) -// .in(file("sql/mariadb")) -// .settings(name := "molecule-sql-mariadb") -// .settings(doPublish) -// .settings(compilerArgs) -// .settings(testFrameworks := testingFrameworks) -// .jsSettings(jsEnvironment) -// .jvmSettings( -// libraryDependencies ++= Seq( -// "com.dimafeng" %% "testcontainers-scala-mariadb" % testContainerVersion, -// "org.mariadb.jdbc" % "mariadb-java-client" % "3.4.0", -// "ch.qos.logback" % "logback-classic" % logbackVersion % Test -// ), -// Test / fork := true -// ) -// .dependsOn(sqlCore) -// .dependsOn(coreTests % "test->test") -// -// -//lazy val sqlMySQL = crossProject(JSPlatform, JVMPlatform) -// .crossType(CrossType.Full) -// .in(file("sql/mysql")) -// .settings(name := "molecule-sql-mysql") -// .settings(doPublish) -// .settings(compilerArgs) -// .settings(testFrameworks := testingFrameworks) -// .jsSettings(jsEnvironment) -// .jvmSettings( -// libraryDependencies ++= Seq( -// "org.testcontainers" % "mysql" % "1.19.8", -// "mysql" % "mysql-connector-java" % "8.0.33", -// ), -// Test / fork := true -// ) -// .dependsOn(sqlCore) -// .dependsOn(coreTests % "test->test") +lazy val sqlMariaDB = crossProject(JSPlatform, JVMPlatform) + .crossType(CrossType.Full) + .in(file("sql/mariadb")) + .settings(name := "molecule-sql-mariadb") + .settings(doPublish) + .settings(compilerArgs) + .settings(testFrameworks := testingFrameworks) + .jsSettings(jsEnvironment) + .jvmSettings( + libraryDependencies ++= Seq( + "com.dimafeng" %% "testcontainers-scala-mariadb" % testContainerVersion, + "org.mariadb.jdbc" % "mariadb-java-client" % "3.4.0", + "ch.qos.logback" % "logback-classic" % logbackVersion % Test + ), + Test / fork := true + ) + .dependsOn(sqlCore) + .dependsOn(coreTests % "test->test") + + +lazy val sqlMySQL = crossProject(JSPlatform, JVMPlatform) + .crossType(CrossType.Full) + .in(file("sql/mysql")) + .settings(name := "molecule-sql-mysql") + .settings(doPublish) + .settings(compilerArgs) + .settings(testFrameworks := testingFrameworks) + .jsSettings(jsEnvironment) + .jvmSettings( + libraryDependencies ++= Seq( + "org.testcontainers" % "mysql" % "1.19.8", + "mysql" % "mysql-connector-java" % "8.0.33", + ), + Test / fork := true + ) + .dependsOn(sqlCore) + .dependsOn(coreTests % "test->test") lazy val sqlPostgreSQL = crossProject(JSPlatform, JVMPlatform) @@ -469,48 +338,7 @@ lazy val sqlSQlite = crossProject(JSPlatform, JVMPlatform) .settings(name := "molecule-sql-sqlite") .settings(doPublish) .settings(compilerArgs) - .settings( - testFrameworks := testingFrameworks, - - // unmanagedSources / excludeFilter := { - // val test = "src/test/scala/molecule/sql/sqlite" - // def path(platform: String) = (baseDirectory.value / s"../$platform/$test").getCanonicalPath - // val jsTests = path("js") - // val jvmTests = path("jvm") - // val sharedTests = path("shared") - // val allowed = Seq( - // // sharedTests + "/compliance/aggr", - // // sharedTests + "/compliance/api", - // // sharedTests + "/compliance/crud", - // // sharedTests + "/compliance/crud/update", - // // sharedTests + "/compliance/crud/update/ops", - // // sharedTests + "/compliance/crud/update/relation", - // // sharedTests + "/compliance/filter", - // // sharedTests + "/compliance/filterAttr", - // // sharedTests + "/compliance/inspect", - // sharedTests + "/compliance/pagination", - // // sharedTests + "/compliance/partitions", - // // sharedTests + "/compliance/relation", - // // sharedTests + "/compliance/sort", - // // sharedTests + "/compliance/subscription", - // // sharedTests + "/compliance/time", - // // sharedTests + "/compliance/validation", - // // sharedTests + "/compliance", - // - // sharedTests + "/setup", - // jvmTests + "/setup", - // jsTests + "/setup", - // jsTests + "/AdhocJS_sqlite.scala", - // jvmTests + "/AdhocJVM_sqlite.scala", - // ) - // new SimpleFileFilter(f => - // (f.getCanonicalPath.startsWith(jsTests) || - // f.getCanonicalPath.startsWith(jvmTests) || - // f.getCanonicalPath.startsWith(sharedTests)) && - // !allowed.exists(p => f.getCanonicalPath.startsWith(p)) - // ) - // }, - ) + .settings(testFrameworks := testingFrameworks) .jsSettings(jsEnvironment) .jvmSettings( libraryDependencies ++= Seq( @@ -540,13 +368,7 @@ lazy val jsEnvironment = { // "Error: connect ECONNREFUSED ::1:8080" with this one alone... shouldn't it work? // jsEnv := new org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv(), - // Test / requireJsDomEnv := true, - scalaJSLinkerConfig ~= { - // _.withModuleKind(ModuleKind.ESModule) - // // _.withModuleKind(ModuleKind.CommonJSModule) - // .withModuleSplitStyle(ModuleSplitStyle.SmallestModules) - // Allowing unicode characters in regex expressions (used in email regex) // https://www.scala-js.org/doc/regular-expressions.html // .withESFeatures(_.withESVersion(ESVersion.ES2018)) @@ -564,7 +386,6 @@ lazy val compilerArgs = Def.settings( "-language:higherKinds", "-language:existentials", "-unchecked", - "11" // "-Xfatal-warnings", ) ++ (CrossVersion.partialVersion(scalaVersion.value) match { case Some((2, 12)) => diff --git a/datalog/datomic/jvm/src/main/scala/molecule/datalog/datomic/facade/DatomicConn_JVM.scala b/datalog/datomic/jvm/src/main/scala/molecule/datalog/datomic/facade/DatomicConn_JVM.scala index 8519597f4..3a30ed046 100644 --- a/datalog/datomic/jvm/src/main/scala/molecule/datalog/datomic/facade/DatomicConn_JVM.scala +++ b/datalog/datomic/jvm/src/main/scala/molecule/datalog/datomic/facade/DatomicConn_JVM.scala @@ -3,12 +3,14 @@ package molecule.datalog.datomic.facade import java.io.StringReader import java.util.{List => jList} import java.{lang => jl, util => ju} +import cats.effect.IO import datomic.Util.readAll import datomic.{Connection => DatomicConnection, Datom => _, _} import molecule.base.error._ import molecule.boilerplate.util.MoleculeLogging import molecule.core.marshalling.DatomicProxy import molecule.core.spi.{Conn, TxReport} +import molecule.core.util.Executor import molecule.datalog.datomic.transaction.DatomicDataType_JVM import molecule.datalog.datomic.util.MakeTxReport import scala.concurrent.duration.DurationInt @@ -35,13 +37,17 @@ case class DatomicConn_JVM( final def transactEdn(edn: String)(implicit ec: ExecutionContext): Future[TxReport] = { transact_async(readAll(new StringReader(edn)).get(0).asInstanceOf[Data]) } + final def transactEdnIO(edn: String): IO[TxReport] = { + IO.fromFuture( + IO( + transact_async( + readAll(new StringReader(edn)).get(0).asInstanceOf[Data] + )(Executor.global) + ) + ) + } override def transact_async(javaStmts: Data)(implicit ec: ExecutionContext): Future[TxReport] = { - // println("##########") - // val it = javaStmts.iterator() - // while (it.hasNext) { - // println(it.next) - // } bridgeDatomicFuture(peerConn.transactAsync(javaStmts)) .map(MakeTxReport(_)) .recover { diff --git a/datalog/datomic/jvm/src/main/scala/molecule/datalog/datomic/facade/DatomicPeer.scala b/datalog/datomic/jvm/src/main/scala/molecule/datalog/datomic/facade/DatomicPeer.scala index 1ba6d4ed7..5e9295baa 100644 --- a/datalog/datomic/jvm/src/main/scala/molecule/datalog/datomic/facade/DatomicPeer.scala +++ b/datalog/datomic/jvm/src/main/scala/molecule/datalog/datomic/facade/DatomicPeer.scala @@ -1,12 +1,14 @@ package molecule.datalog.datomic.facade import java.util.UUID.randomUUID +import cats.effect.IO import datomic.Peer import molecule.base.api.Schema import molecule.base.util.BaseHelpers import molecule.core.marshalling.DatomicProxy +import zio.{ZIO, ZLayer} import scala.concurrent.{ExecutionContext, Future, blocking} - +import molecule.core.util.Executor._ /** Facade to Datomic Peer with selected methods. * @@ -34,7 +36,7 @@ trait DatomicPeer extends BaseHelpers { protocol: String, dbIdentifier: String ): DatomicConn_JVM = blocking { - val id = if (dbIdentifier == "") randomUUID().toString else dbIdentifier + val id = if (dbIdentifier == "") randomUUID().toString else dbIdentifier val uri = s"datomic:$protocol://$id" DatomicConn_JVM(proxy, Peer.connect(uri)) } @@ -109,6 +111,88 @@ trait DatomicPeer extends BaseHelpers { dbIdentifier ) } + + def recreateDbIO( + proxy: DatomicProxy, + protocol: String, + dbIdentifier: String + ): IO[DatomicConn_JVM] = { + val id = if (dbIdentifier == "") + randomUUID().toString + else + dbIdentifier + deleteDatabase(protocol, id) + createDatabase(protocol, id) + val conn = connect(proxy, protocol, id) + // Ensure each transaction finishes before the next + for { + // partitions + _ <- if (proxy.datomicPartitions.nonEmpty) + conn.transactEdnIO(proxy.datomicPartitions) else IO.unit + // attributes + _ <- if (proxy.datomicSchema.nonEmpty) + conn.transactEdnIO(proxy.datomicSchema) else IO.unit + // aliases + _ <- if (proxy.datomicAliases.nonEmpty) + conn.transactEdnIO(proxy.datomicAliases) else IO.unit + } yield conn + } + + def recreateDbIO( + schema: Schema, + protocol: String = "mem", + dbIdentifier: String = "" + ): IO[DatomicConn_JVM] = { + recreateDbIO( + DatomicProxy( + protocol, + dbIdentifier, + schema.datomicPartitions, + schema.datomicSchema, + schema.datomicAliases, + schema.metaSchema, + schema.nsMap, + schema.attrMap, + schema.uniqueAttrs, + ), + protocol, + dbIdentifier + ) + } + + def recreateDbZLayer[T]( + proxy: DatomicProxy, + protocol: String, + dbIdentifier: String + ): ZLayer[T, Throwable, DatomicConn_JVM] = { + ZLayer.scoped( + ZIO.fromFuture( + _ => recreateDb(proxy, protocol, dbIdentifier) + ) + ) + } + + def recreateDbZLayer[T]( + schema: Schema, + protocol: String = "mem", + dbIdentifier: String = "" + ): ZLayer[T, Throwable, DatomicConn_JVM] = { + recreateDbZLayer( + DatomicProxy( + protocol, + dbIdentifier, + schema.datomicPartitions, + schema.datomicSchema, + schema.datomicAliases, + schema.metaSchema, + schema.nsMap, + schema.attrMap, + schema.uniqueAttrs, + ), + protocol, + dbIdentifier + ) + } } object DatomicPeer extends DatomicPeer diff --git a/project/releases/v0.11.0.md b/project/releases/v0.11.0.md new file mode 100644 index 000000000..dc904a234 --- /dev/null +++ b/project/releases/v0.11.0.md @@ -0,0 +1,41 @@ +v0.11.0 Cats effect IO API + +Molecule now supports returning data wrapped in a `cats.effect.IO` by importing the relevant database and API. So now there are 4 APIs to choose from: + +#### Synchronous +```scala +import molecule.sql.postgres.sync._ + +val persons: List[(String, Int, String)] = + Person.name.age.Address.street.query.get +``` + +#### Asynchronous (Future) +```scala +import molecule.sql.postgres.async._ + +val persons: Future[List[(String, Int, String)]] = + Person.name.age.Address.street.query.get +``` + +#### ZIO +```scala +import molecule.sql.postgres.zio._ + +val persons: ZIO[Conn, MoleculeError, List[(String, Int, String)]] = + Person.name.age.Address.street.query.get +``` + +#### IO +```scala +import molecule.sql.postgres.io._ + +val persons: cats.effect.IO[List[(String, Int, String)]] = + Person.name.age.Address.street.query.get +``` + +Same wrapping happens for transactions. See + +### Same molecules + +As you can see the molecules are identical for each API. The import determines the return type. Likewise, transaction reports are wrapped as the queries for each API. \ No newline at end of file diff --git a/project/sbt-cheat-sheet.md b/project/sbt-cheat-sheet.md index 44b746c8d..c0d7332fe 100644 --- a/project/sbt-cheat-sheet.md +++ b/project/sbt-cheat-sheet.md @@ -33,9 +33,46 @@ To have molecule jars generated, add `-Dmolecule=true` sbt moleculeJS/fastLinkJS + Test/moleculeJS/fastLinkJS -## Publish +## Test + +Specific Scala version can be set initially + + sbt ++2.12.15 + +## Test JVM + + sbt + project sqlSQliteJVM + test + // or + testOnly moleculemolecule.sql.sqlite.AdhocJS_sqlite + testOnly moleculemolecule.sql.sqlite.* + testOnly moleculemolecule.sql.* + +## Test JS + +Process 1: + + sbt + sqlSQliteJVM/run + +Process 2: + + sbt + project sqlSQliteJS + test + // or + testOnly moleculemolecule.sql.sqlite.AdhocJS_sqlite + testOnly moleculemolecule.sql.sqlite.* + testOnly moleculemolecule.sql.* + +Compilation on JS side can take some time. + + +## Publish with sbt-molecule update too 1) Set molecule build version to new version 2) `sbt ++2.12.20 "project baseJVM" publishLocal` (using sbt-molecule snapshot) @@ -47,7 +84,14 @@ To have molecule jars generated, add `-Dmolecule=true` 8) molecule: `sbt +publishSigned -Ddocs=true` -Publish versions separately +## Publish without sbt-molecule update + +1) Set molecule build version to new version +2) molecule: `sbt +publishLocal` +3) molecule: `sbt +publishSigned -Ddocs=true` + + +### Publish versions separately sbt ++2.12.20 publishLocal sbt ++2.12.20 publishSigned -Ddocs=true diff --git a/project/todo.md b/project/todo.md index ee85ff0dc..cd6a18955 100644 --- a/project/todo.md +++ b/project/todo.md @@ -4,4 +4,6 @@ Possible additions - ClickHouse - RethinkDb +- duckDB +- Oracle - Datascript (synchronous on JS?)