diff --git a/.gitignore b/.gitignore index 0f70512..3abf6b6 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ target/ project/.ensimeextractors/.scannerwork/ sqlest/.scannerwork/ extractors/.scannerwork/ +.bsp/ diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..af99174 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,13 @@ +version = "3.9.10" +runner.dialect = scala213 +maxColumn = 120 +align.preset = more +continuationIndent.defnSite = 2 +assumeStandardLibraryStripMargin = true +docstrings.style = Asterisk +lineEndings = preserve +includeCurlyBraceInSelectChains = false +danglingParentheses.preset = true +optIn.annotationNewlines = true +newlines.alwaysBeforeMultilineDef = false +rewrite.rules = [SortImports, RedundantBraces] diff --git a/README.md b/README.md index 824ad23..4c7ef01 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ libraryDependencies ++= Seq( ) ``` -sqlest is available for Scala 2.11 +sqlest is available for Scala 2.12 and 2.13 ## Examples ### Database Connection diff --git a/build.sbt b/build.sbt index 1a2ecdc..c44ed37 100644 --- a/build.sbt +++ b/build.sbt @@ -1,11 +1,6 @@ -import com.typesafe.sbt.pgp.PgpKeys -import com.typesafe.sbt.SbtGit.GitKeys.gitRemoteRepo -import com.typesafe.sbt.SbtGhPages -import com.typesafe.sbt.SbtScalariform -import com.typesafe.sbt.SbtScalariform.ScalariformKeys -import com.typesafe.sbt.SbtSite +import com.github.sbt.git.SbtGit.GitKeys.gitRemoteRepo +import com.jsuereth.sbtpgp.PgpKeys import ReleaseTransformations._ -import scalariform.formatter.preferences._ lazy val root = (project in file(".")) .settings(commonSettings: _*) @@ -17,9 +12,9 @@ lazy val sqlest = (project in file("sqlest")) .settings(moduleName := "sqlest") .settings(sqlestSettings: _*) .settings( - tutSourceDirectory := file("docs") / "sqlest", - tutTargetDirectory := file("."), - libraryDependencies ++= Seq("com.typesafe.scala-logging" %% "scala-logging" % "3.5.0") + mdocIn := file("docs") / "sqlest", + mdocOut := file("."), + libraryDependencies ++= Seq("com.typesafe.scala-logging" %% "scala-logging" % "3.9.6") ).dependsOn(extractors) lazy val extractors = (project in file("extractors")) @@ -27,25 +22,25 @@ lazy val extractors = (project in file("extractors")) .settings(moduleName := "sqlest-extractors") .settings(sqlestSettings: _*) .settings( - tutSourceDirectory := file("docs") / "extractors", - tutTargetDirectory := file("extractors"), + mdocIn := file("docs") / "extractors", + mdocOut := file("extractors"), libraryDependencies ++= Seq( "org.scala-lang" % "scala-reflect" % scalaVersion.value, - "joda-time" % "joda-time" % "2.3", - "org.joda" % "joda-convert" % "1.6" + "joda-time" % "joda-time" % "2.14.0", + "org.joda" % "joda-convert" % "3.0.1" ) ) lazy val examples = (project in file("examples")) .settings(commonSettings: _*) .settings(noPublishSettings: _*) - .settings(libraryDependencies += "com.h2database" % "h2" % "1.4.180") + .settings(libraryDependencies += "com.h2database" % "h2" % "2.4.240") .dependsOn(sqlest) -lazy val commonSettings = SbtScalariform.scalariformSettings ++ publishingSettings ++ Seq( +lazy val commonSettings = publishingSettings ++ Seq( organization := "uk.co.jhc", - scalaVersion := "2.12.1", - crossScalaVersions := List("2.11.8", "2.12.1"), + scalaVersion := "2.13.16", + crossScalaVersions := List("2.13.16"), scalacOptions ++= Seq( "-deprecation", "-encoding", "UTF-8", @@ -54,54 +49,55 @@ lazy val commonSettings = SbtScalariform.scalariformSettings ++ publishingSettin "-language:higherKinds", "-language:implicitConversions", "-unchecked", - "-Xfatal-warnings", - "-Xfuture" + "-Xfatal-warnings"//, +// "-Ystatistics:typer", +// "-Xlog-implicit-conversions", +// "-Xlog-implicits" ), - coverageExcludedPackages := "sqlest.examples", - ScalariformKeys.preferences := ScalariformKeys.preferences.value - .setPreference(DanglingCloseParenthesis, Preserve) + coverageExcludedPackages := "sqlest.examples" ) -lazy val sqlestSettings = commonSettings ++ scaladocSettings ++ tutSettings ++ Seq( - tutNameFilter := """README.md""".r, +lazy val sqlestSettings = commonSettings ++ scaladocSettings ++ mdocSettings ++ Seq( + mdocVariables := Map("VERSION" -> version.value), libraryDependencies ++= Seq( - "org.scalatest" %% "scalatest" % "3.0.1" % "test", - "com.chuusai" %% "shapeless" % "2.3.2" % "test", - "com.h2database" % "h2" % "1.4.180" % "test" + "org.scalatest" %% "scalatest" % "3.2.19" % "test", + "com.chuusai" %% "shapeless" % "2.3.13" % "test", + "com.h2database" % "h2" % "2.4.240" % "test" ) ) lazy val noPublishSettings = Seq( - publish := (), - publishLocal := (), + publish / skip := true, + publishLocal / skip := true, publishArtifact := false ) -lazy val scaladocSettings = SbtSite.site.settings ++ SbtSite.site.includeScaladoc() ++ SbtGhPages.ghpages.settings ++ Seq( +lazy val scaladocSettings = Seq( gitRemoteRepo := "git@github.com:jhc-systems/sqlest.git" ) +lazy val mdocSettings = Seq( + mdocExtraArguments := Seq("--no-link-hygiene") +) + lazy val publishingSettings = sonatypeReleaseProcess ++ Seq( // Publishing - http://www.scala-sbt.org/0.13/docs/Using-Sonatype.html releaseCrossBuild := true, releasePublishArtifactsAction := PgpKeys.publishSigned.value, publishMavenStyle := true, - publishArtifact in Test := false, + Test / publishArtifact := false, publishTo := { - val nexus = "https://oss.sonatype.org/" + val nexus = "https://nexus-proxy.lighthouse.jhc.uk/nexus/content/repositories/" if (isSnapshot.value) - Some("snapshots" at nexus + "content/repositories/snapshots") + Some("snapshots" at nexus + "snapshots") else - Some("releases" at nexus + "service/local/staging/deploy/maven2") - }, - credentials := { - Seq("SONATYPE_USER", "SONATYPE_PASSWORD").map(sys.env.get) match { - case Seq(Some(user), Some(password)) => - Seq(Credentials("Sonatype Nexus Repository Manager", "oss.sonatype.org", user, password)) - case _ => - credentials.value - } + Some("releases" at nexus + "releases") }, + credentials += Credentials( + "Sonatype Nexus Repository Manager", + "nexus-proxy.lighthouse.jhc.uk", + "dev", "jhcjhc" + ), pomIncludeRepository := { _ => false }, pomExtra := ( https://github.com/jhc-systems/sqlest @@ -140,7 +136,7 @@ lazy val sonatypeReleaseProcess = Seq( ReleaseStep(action = Command.process("publishSigned", _), enableCrossBuild = true), setNextVersion, commitNextVersion, - ReleaseStep(action = Command.process("sonatypeReleaseAll", _), enableCrossBuild = true), + ReleaseStep(action = Command.process("sonaRelease", _), enableCrossBuild = true), pushChanges ) ) diff --git a/examples/src/main/scala/sqlest/examples/Database.scala b/examples/src/main/scala/sqlest/examples/Database.scala index 03591e9..bced48b 100644 --- a/examples/src/main/scala/sqlest/examples/Database.scala +++ b/examples/src/main/scala/sqlest/examples/Database.scala @@ -1,6 +1,7 @@ package sqlest.examples import sqlest._ +import sqlest.executor.Database trait DatabaseExample { // Configure a DataSource @@ -15,7 +16,7 @@ trait DatabaseExample { // Use the DataSource and the StatementBuilder to create an implicit database // This database is used in all execute calls - implicit val database = Database.withDataSource(dataSource, statementBuilder) + implicit val database: Database = Database.withDataSource(dataSource, statementBuilder) executeRawSql("drop table fruit") executeRawSql(""" diff --git a/extractors/README.md b/extractors/README.md index 8c79e78..0ae99ba 100644 --- a/extractors/README.md +++ b/extractors/README.md @@ -28,7 +28,7 @@ libraryDependencies ++= Seq( ) ``` -sqlest-extractors is available for Scala 2.11 +sqlest-extractors is available for Scala 2.12 and 2.13 ## Overview Table data consists of multiple `Rows` of cells. diff --git a/extractors/src/main/boilerplate/sqlest/extractor/ExtractorSyntax.scala.template b/extractors/src/main/boilerplate/sqlest/extractor/ExtractorSyntax.scala.template index f5052d6..48d4c53 100644 --- a/extractors/src/main/boilerplate/sqlest/extractor/ExtractorSyntax.scala.template +++ b/extractors/src/main/boilerplate/sqlest/extractor/ExtractorSyntax.scala.template @@ -25,15 +25,15 @@ trait ExtractorSyntax[Row] { // However the extended return type is included to overcome bugs in: // - Scala compiler does not add `apply` sugar after macro expansion but it works with Dynamic // - Intellij does not macro expand whitebox macros to determine the actual return type but it does understand the return type of `applyDynamic` and `applyDynamicNamed` - def extract[A]: Dynamic { def applyDynamic(method: String)(args: Any*): Extractor[Row, A] with SimpleExtractor[Row, A]; def applyDynamicNamed(method: String)(namedArgs: (String, Any)*): Extractor[Row, A] with SimpleExtractor[Row, A] ; def apply(extractor: Extractor[Row, A] with SimpleExtractor[Row, A]): Extractor[Row, A] with SimpleExtractor[Row, A]} = + def extract[A]: Dynamic { def applyDynamic(method: String)(args: Any*): Extractor[Row, A] with SimpleExtractor[Row, A]; def applyDynamicNamed(method: String)(namedArgs: (String, Any)*): Extractor[Row, A] with SimpleExtractor[Row, A] ; def apply(extractor: Extractor[Row, A] with SimpleExtractor[Row, A]): Extractor[Row, A] with SimpleExtractor[Row, A]} = macro CaseClassExtractorMacro.apply[Row, A] -[2..22# implicit def extractTuple[Row, [#A1#]](t: Tuple1[[#Extractor[Row, A1]#]]) = +[2..22# implicit def extractTuple[Row, [#A1#]](t: Tuple1[[#Extractor[Row, A1]#]]): Tuple1Extractor[Row, [#A1#]] = new Tuple1Extractor[Row, [#A1#]]([#t._1#])# ] -[2..22# def extractTuple[Row, [#A1#]]([#e1: Extractor[Row, A1]#]) = +[2..22# def extractTuple[Row, [#A1#]]([#e1: Extractor[Row, A1]#]): Tuple1Extractor[Row, [#A1#]] = new Tuple1Extractor[Row, [#A1#]]([#e1#])# ] diff --git a/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala b/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala index 88da789..905e747 100644 --- a/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala +++ b/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala @@ -44,16 +44,17 @@ case class CaseClassExtractorMacro(c: Context) { // Construct extractor methods for this case class corresponding to each apply method val liftedApplyMethods = applyMethods.map(liftApplyMethod(_, unapplyMethod, typeOfRow, typeOfA, typeArgs, companion)) - // import scala.language.dynamics to avoid having to do so at the call site q""" import scala.language.dynamics import scala.language.experimental.macros + import scala.collection.immutable.List new Dynamic { ..$liftedApplyMethods def apply(extractor: sqlest.extractor.Extractor[$typeOfRow, $typeOfA] with sqlest.extractor.SimpleExtractor[$typeOfRow, $typeOfA]) = extractor def applyDynamic(method: String)(args: Any*): sqlest.extractor.Extractor[$typeOfRow, $typeOfA] with sqlest.extractor.SimpleExtractor[$typeOfRow, $typeOfA] = macro sqlest.extractor.AbortMacro.apply def applyDynamicNamed(method: String)(args: (String, Any)*): sqlest.extractor.Extractor[$typeOfRow, $typeOfA] with sqlest.extractor.SimpleExtractor[$typeOfRow, $typeOfA] = macro sqlest.extractor.AbortMacro.apply + def sqlestUnapplyList[A](x: List[A]) : Some[List[A]] = { Some(List.unapplySeq(x).toSeq.toList)} } """ } @@ -90,10 +91,14 @@ case class CaseClassExtractorMacro(c: Context) { val tupleExtractorParams = buildExtractorParams(applyMethod, typeOfRow, caseClassParamNames, appliedTypeArgTypes) val unapply = unapplyMethod match { - case Some(unapplyMethod) => q"Some($companion.$unapplyMethod)" - case None => q"None" + case Some(unapplyMethod) => if (unapplyMethod.toString().equals("method unapplySeq") + && (companion.toString().equals("object List"))) { + q"Some(sqlestUnapplyList)" + } else { + q"Some($companion.$unapplyMethod)" + } + case None => q"None" } - q""" def apply(..$applyParams) = new sqlest.extractor.MappedExtractor[$typeOfRow, $tupleType, $typeOfA]( new $tupleExtractor(..$tupleExtractorParams) with sqlest.extractor.ProductExtractorNames { @@ -136,12 +141,12 @@ case class CaseClassExtractorMacro(c: Context) { val liftedParamTypes = paramTypes.map(liftParam) - (paramNames, liftedParamTypes, defaultValues).zipped.map { - case (paramName, typ, defaultValue) => - if (defaultValue.isDefined) - q"val $paramName: $typ = sqlest.extractor.ConstantExtractor(${defaultValue.get})" - else - q"val $paramName: $typ" + paramNames.lazyZip(liftedParamTypes).lazyZip(defaultValues).map { + case (paramName, typ, defaultValue) => + if (defaultValue.isDefined) + q"val $paramName: $typ = sqlest.extractor.ConstantExtractor(${defaultValue.get})" + else + q"val $paramName: $typ" } } @@ -152,7 +157,7 @@ case class CaseClassExtractorMacro(c: Context) { if (applyMethod.isVarargs) treeTypes.init :+ (paramTypes.last match { - case TypeRef(_, `repeatedParamClass`, typ :: Nil) => tq"scala.collection.Seq[$typ]" + case TypeRef(_, `repeatedParamClass`, typ :: Nil) => tq"Seq[$typ]" }) else treeTypes diff --git a/extractors/src/main/scala/sqlest/extractor/Extractor.scala b/extractors/src/main/scala/sqlest/extractor/Extractor.scala index 27d1924..f96589e 100644 --- a/extractors/src/main/scala/sqlest/extractor/Extractor.scala +++ b/extractors/src/main/scala/sqlest/extractor/Extractor.scala @@ -56,17 +56,17 @@ trait SimpleExtractor[Row, A] { def extractHeadOption(rows: Iterable[Row]): Option[A] = { val rowIterator = rows.iterator if (rowIterator.hasNext) { - Some(checkNullValueAndGet(emit(initialize(rowIterator.next)))) + Some(checkNullValueAndGet(emit(initialize(rowIterator.next())))) } else None } def extractAll(rows: Iterable[Row]): List[A] = { val rowIterator = rows.iterator if (rowIterator.hasNext) { - var accumulator = Queue(checkNullValueAndGet(emit(initialize(rowIterator.next)))) + var accumulator = Queue(checkNullValueAndGet(emit(initialize(rowIterator.next())))) while (rowIterator.hasNext) - accumulator = accumulator :+ checkNullValueAndGet(emit(initialize(rowIterator.next))) + accumulator = accumulator :+ checkNullValueAndGet(emit(initialize(rowIterator.next()))) accumulator.toList } else Nil @@ -315,10 +315,10 @@ case class GroupedExtractor[Row, A, B](inner: Extractor[Row, A], groupBy: Extrac def extractHeadOption(rows: Iterable[Row]): Option[A] = { val rowIterator = rows.iterator if (rowIterator.hasNext) { - var accumulator = initialize(rowIterator.next) + var accumulator = initialize(rowIterator.next()) while (rowIterator.hasNext && accumulator.size == 1) - accumulator = accumulate(accumulator, rowIterator.next) + accumulator = accumulate(accumulator, rowIterator.next()) checkNullValueAndGet(emit(accumulator)).headOption } else None @@ -327,10 +327,10 @@ case class GroupedExtractor[Row, A, B](inner: Extractor[Row, A], groupBy: Extrac def extractAll(rows: Iterable[Row]): List[A] = { val rowIterator = rows.iterator if (rowIterator.hasNext) { - var accumulator = initialize(rowIterator.next) + var accumulator = initialize(rowIterator.next()) while (rowIterator.hasNext) - accumulator = accumulate(accumulator, rowIterator.next) + accumulator = accumulate(accumulator, rowIterator.next()) checkNullValueAndGet(emit(accumulator)) } else Nil diff --git a/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala b/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala index ac5e676..0f47ec1 100644 --- a/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala +++ b/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala @@ -16,7 +16,9 @@ package sqlest.extractor -import org.scalatest._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ +import org.scalatest.prop._ import shapeless.test.illTyped // TODO: The CaseClassExtractorMacro macro has issues with path-dependent types. @@ -34,7 +36,7 @@ case object Circle extends Shape case object Tetrahedron extends Shape case object Plane extends Shape -class CaseClassExtractorMacroSpec extends FlatSpec with Matchers with ExtractorSyntax[Tuple3[Shape, Int, String]] with PathDependenceTestData { +class CaseClassExtractorMacroSpec extends AnyFlatSpec with Matchers with ExtractorSyntax[Tuple3[Shape, Int, String]] with PathDependenceTestData { case class One(a: Int, b: String) case class Two(a: String, b: Shape) diff --git a/extractors/src/test/scala/sqlest/extractor/ExtractorSpec.scala b/extractors/src/test/scala/sqlest/extractor/ExtractorSpec.scala index 09f442b..41130dc 100644 --- a/extractors/src/test/scala/sqlest/extractor/ExtractorSpec.scala +++ b/extractors/src/test/scala/sqlest/extractor/ExtractorSpec.scala @@ -16,11 +16,13 @@ package sqlest.extractor -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ +import org.scalatest.prop._ import shapeless.test.illTyped -class ExtractorSpec extends FlatSpec with Matchers with ExtractorSyntax[Seq[Any]] { +class ExtractorSpec extends AnyFlatSpec with Matchers with ExtractorSyntax[Seq[Any]] { sealed trait Superclass { def a: Int diff --git a/project/build.properties b/project/build.properties index 133a8f1..e480c67 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.17 +sbt.version=1.11.5 diff --git a/project/plugins.sbt b/project/plugins.sbt index 12ef8ba..bd359d3 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,19 +1,20 @@ -addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.6.0") +// Dependency resolution to fix version conflicts +ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always -addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") +addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.2.1") -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "1.1") +addSbtPlugin("io.spray" % "sbt-boilerplate" % "0.6.1") -addSbtPlugin("io.spray" % "sbt-boilerplate" % "0.6.0") +addSbtPlugin("com.github.sbt" % "sbt-site" % "1.6.0") -addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "0.8.1") +addSbtPlugin("com.github.sbt" % "sbt-ghpages" % "0.8.0") -addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.5.4") +addSbtPlugin("com.github.sbt" % "sbt-git" % "2.0.1") -addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.3") +addSbtPlugin("com.github.sbt" % "sbt-release" % "1.4.0") -addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.8") +addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.5.2") -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.0") +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.11") addSbtPlugin("com.sonar-scala" % "sbt-sonar" % "2.3.0") \ No newline at end of file diff --git a/sqlest/src/main/boilerplate/sqlest/ast/TupleGroups.scala.template b/sqlest/src/main/boilerplate/sqlest/ast/TupleGroups.scala.template index c00e1b8..7933a31 100644 --- a/sqlest/src/main/boilerplate/sqlest/ast/TupleGroups.scala.template +++ b/sqlest/src/main/boilerplate/sqlest/ast/TupleGroups.scala.template @@ -18,10 +18,10 @@ package sqlest.ast trait TupleGroups { - implicit def TupleGroup0(t: Unit) = + implicit def TupleGroup0(t: Unit): TupleGroup = TupleGroup(Nil) -[# implicit def TupleGroup1(t: Tuple1[[#Column[_]#]]) = +[# implicit def TupleGroup1(t: Tuple1[[#Column[_]#]]): TupleGroup = TupleGroup(List([#ColumnGroup(t._1)#]))# ] diff --git a/sqlest/src/main/scala/sqlest/ast/ColumnType.scala b/sqlest/src/main/scala/sqlest/ast/ColumnType.scala index bbc1ca5..6143e82 100644 --- a/sqlest/src/main/scala/sqlest/ast/ColumnType.scala +++ b/sqlest/src/main/scala/sqlest/ast/ColumnType.scala @@ -61,10 +61,13 @@ case object ByteArrayColumnType extends NonNumericColumnType[Array[Byte]] */ case class OptionColumnType[A, B](nullValue: B, isNull: B => Boolean)(implicit val innerColumnType: ColumnType.Aux[A, B]) extends ColumnType[Option[A]] { type Database = B - val baseColumnType: BaseColumnType[B] = innerColumnType match { - case baseColumnType: ColumnType[A] with BaseColumnType[B] => baseColumnType - case optionColumnType: ColumnType[A] with OptionColumnType[A, B] => optionColumnType.baseColumnType - case mappedColumnType: ColumnType[A] with MappedColumnType[A, B] => mappedColumnType.baseColumnType + val baseColumnType: BaseColumnType[B] = { + def extractBaseColumnType(ct: ColumnType[_]): BaseColumnType[_] = ct match { + case base: BaseColumnType[_] => base + case opt: OptionColumnType[_, _] => opt.baseColumnType + case mapped: MappedColumnType[_, _] => mapped.baseColumnType + } + extractBaseColumnType(innerColumnType).asInstanceOf[BaseColumnType[B]] } def read(database: Option[Database]): Option[Option[A]] = { @@ -124,23 +127,26 @@ object ColumnType { // The ColumnType.Aux type provides access the Database type member on ColumnType type Aux[A, B] = ColumnType[A] { type Database = B } - implicit val booleanColumnType = BooleanColumnType - implicit val intColumnType = IntColumnType - implicit val longColumnType = LongColumnType - implicit val doubleColumnType = DoubleColumnType - implicit val bigDecimalColumnType = BigDecimalColumnType - implicit val stringColumnType = StringColumnType - implicit val dateTimeColumnType = DateTimeColumnType - implicit val localDateColumnType = LocalDateColumnType - implicit val byteArrayColumnType = ByteArrayColumnType + implicit val booleanColumnType: BooleanColumnType.type = BooleanColumnType + implicit val intColumnType: IntColumnType.type = IntColumnType + implicit val longColumnType: LongColumnType.type = LongColumnType + implicit val doubleColumnType: DoubleColumnType.type = DoubleColumnType + implicit val bigDecimalColumnType: BigDecimalColumnType.type = BigDecimalColumnType + implicit val stringColumnType: StringColumnType.type = StringColumnType + implicit val dateTimeColumnType: DateTimeColumnType.type = DateTimeColumnType + implicit val localDateColumnType: LocalDateColumnType.type = LocalDateColumnType + implicit val byteArrayColumnType: ByteArrayColumnType.type = ByteArrayColumnType implicit def materialize[A, B]: MappedColumnType[A, B] = macro MaterializeColumnTypeMacro.materializeImpl[A, B] - implicit def optionType[A, B](implicit base: ColumnType.Aux[A, B]) = OptionColumnType[A, B](base) + implicit def optionType[A, B](implicit base: ColumnType.Aux[A, B]): OptionColumnType[A, B] = OptionColumnType[A, B](base) implicit class OptionColumnTypeOps[A, B](left: ColumnType.Aux[A, B]) { - def toOptionColumnType = left match { - case option: ColumnType[A] with OptionColumnType[A, B] => option - case base => OptionColumnType.apply[A, base.Database](base) + def toOptionColumnType = { + if (left.isInstanceOf[OptionColumnType[_, _]]) { + left.asInstanceOf[OptionColumnType[A, B]] + } else { + OptionColumnType.apply[A, left.Database](left) + } } } } diff --git a/sqlest/src/main/scala/sqlest/ast/ColumnTypeEquivalence.scala b/sqlest/src/main/scala/sqlest/ast/ColumnTypeEquivalence.scala index 1d2239e..1d54d82 100644 --- a/sqlest/src/main/scala/sqlest/ast/ColumnTypeEquivalence.scala +++ b/sqlest/src/main/scala/sqlest/ast/ColumnTypeEquivalence.scala @@ -30,13 +30,13 @@ package sqlest.ast trait ColumnTypeEquivalence[A, B] object ColumnTypeEquivalence extends LowPriorityImplicits { - implicit def leftOptionColumnTypeEquivalence[A, B](implicit left: ColumnType[Option[A]], right: ColumnType[B], columnTypeEquivalence: ColumnTypeEquivalence[A, B]) = + implicit def leftOptionColumnTypeEquivalence[A, B](implicit left: ColumnType[Option[A]], right: ColumnType[B], columnTypeEquivalence: ColumnTypeEquivalence[A, B]): ColumnTypeEquivalence[Option[A], B] = new ColumnTypeEquivalence[Option[A], B] {} - implicit def rightOptionColumnTypeEquivalence[A, B](implicit left: ColumnType[A], right: ColumnType[Option[B]], columnTypeEquivalence: ColumnTypeEquivalence[A, B]) = + implicit def rightOptionColumnTypeEquivalence[A, B](implicit left: ColumnType[A], right: ColumnType[Option[B]], columnTypeEquivalence: ColumnTypeEquivalence[A, B]): ColumnTypeEquivalence[A, Option[B]] = new ColumnTypeEquivalence[A, Option[B]] {} - implicit def bothOptionColumnTypeEquivalence[A, B](implicit left: ColumnType[Option[A]], right: ColumnType[Option[B]], columnTypeEquivalence: ColumnTypeEquivalence[A, B]) = + implicit def bothOptionColumnTypeEquivalence[A, B](implicit left: ColumnType[Option[A]], right: ColumnType[Option[B]], columnTypeEquivalence: ColumnTypeEquivalence[A, B]): ColumnTypeEquivalence[Option[A], Option[B]] = new ColumnTypeEquivalence[Option[A], Option[B]] {} /** @@ -105,9 +105,9 @@ object ColumnTypeEquivalence extends LowPriorityImplicits { trait LowPriorityImplicits { // The implicit *OptionColumnTypeEquivalences will clash with this, ensure this is lower priority so options are correctly handled - implicit def nonNumericEquivalence[A, B](implicit left: ColumnType[A] { type Database = B }, right: ColumnType[A] { type Database = B }) = + implicit def nonNumericEquivalence[A, B](implicit left: ColumnType[A] { type Database = B }, right: ColumnType[A] { type Database = B }): ColumnTypeEquivalence[A, A] = new ColumnTypeEquivalence[A, A] {} - implicit def numericEquivalence[A, B](implicit left: NumericColumnType[A], right: NumericColumnType[B]) = + implicit def numericEquivalence[A, B](implicit left: NumericColumnType[A], right: NumericColumnType[B]): ColumnTypeEquivalence[A, B] = new ColumnTypeEquivalence[A, B] {} } diff --git a/sqlest/src/main/scala/sqlest/ast/syntax/CaseSyntax.scala b/sqlest/src/main/scala/sqlest/ast/syntax/CaseSyntax.scala index c30bbe2..7902df3 100644 --- a/sqlest/src/main/scala/sqlest/ast/syntax/CaseSyntax.scala +++ b/sqlest/src/main/scala/sqlest/ast/syntax/CaseSyntax.scala @@ -35,7 +35,7 @@ trait CaseSyntax { When(condition, result) implicit class CaseWhenColumnOps[A](caseWhen: CaseWhenColumn[A]) { - implicit val columnType = caseWhen.columnType + implicit val columnType: ColumnType[A] = caseWhen.columnType def when(condition: Column[Boolean], result: Column[A]) = CaseWhenColumn(caseWhen.whens :+ When(condition, result)) @@ -48,7 +48,7 @@ trait CaseSyntax { } implicit class CaseColumnColumnOps[A, B](caseColumn: CaseColumnColumn[A, B]) { - implicit val columnType = caseColumn.columnType + implicit val columnType: ColumnType[A] = caseColumn.columnType def when[C](value: Column[C], result: Column[A])(implicit equivalence: ColumnTypeEquivalence[B, C]) = CaseColumnColumn[A, B](caseColumn.column, caseColumn.mappings :+ (value, result)) @@ -60,7 +60,7 @@ trait CaseSyntax { CaseColumnElseColumn[A, B](caseColumn.column, caseColumn.mappings, result) } - implicit def defaultAliasCaseColumn[A](caseColumn: CaseColumn[A]) = AliasColumn(caseColumn, "case")(caseColumn.columnType) + implicit def defaultAliasCaseColumn[A](caseColumn: CaseColumn[A]): AliasColumn[A] = AliasColumn(caseColumn, "case")(caseColumn.columnType) } object CaseBuilder { diff --git a/sqlest/src/main/scala/sqlest/ast/syntax/ColumnSyntax.scala b/sqlest/src/main/scala/sqlest/ast/syntax/ColumnSyntax.scala index f01a4cb..6fc3a89 100644 --- a/sqlest/src/main/scala/sqlest/ast/syntax/ColumnSyntax.scala +++ b/sqlest/src/main/scala/sqlest/ast/syntax/ColumnSyntax.scala @@ -49,15 +49,22 @@ trait ColumnSyntax { /** * This implicit allows the use of `TableColumn -> Column` in setters */ - implicit def columnSetterPair[A, B](pair: (TableColumn[A], Column[B]))(implicit equivalence: ColumnTypeEquivalence[A, B]) = - Setter[A, B](pair._1, pair._2) + implicit def columnSetterPair[A, B](pair: (TableColumn[A], Column[B]))(implicit equivalence: ColumnTypeEquivalence[A, B]): Setter[A, B] = { + val (column, value) = pair + val (_, alignedValue) = ColumnTypeEquivalence.alignColumnTypes(column, value) + new Setter(column, alignedValue.asInstanceOf[Column[B]]) + } /** * This implicit allows the use of `TableColumn -> Value` in setters, * as opposed to `TableColumn -> Column` as is actually required: */ - implicit def literalSetterPair[A, B](pair: (TableColumn[A], B))(implicit valueType: ColumnType[B], equivalence: ColumnTypeEquivalence[A, B]) = - Setter[A, B](pair._1, pair._2.column) + implicit def literalSetterPair[A, B](pair: (TableColumn[A], B))(implicit valueType: ColumnType[B], equivalence: ColumnTypeEquivalence[A, B]): Setter[A, B] = { + val (column, value) = pair + val valueColumn = value.column(valueType) + val (_, alignedValue) = ColumnTypeEquivalence.alignColumnTypes(column, valueColumn) + new Setter(column, alignedValue.asInstanceOf[Column[B]]) + } implicit class AliasColumnOps[A](left: Column[A]) { def as(alias: String) = left match { @@ -74,7 +81,7 @@ trait ColumnSyntax { /** * This implicit conversion allows using as a column: a select statement which selects a single column */ - implicit def SelectColumnOps[A](select: Select[AliasedColumn[A], _ <: Relation]) = + implicit def SelectColumnOps[A](select: Select[AliasedColumn[A], _ <: Relation]): SelectColumn[A] = SelectColumn(select)(select.cols.columnType) implicit class NullableColumnsOps[A](column: Column[A]) { @@ -82,7 +89,7 @@ trait ColumnSyntax { val columnIsNull = PostfixFunctionColumn[Boolean]("is null", column) column.columnType match { - case optionColumnType: OptionColumnType[A, _] if !optionColumnType.hasNullNullValue => + case optionColumnType: OptionColumnType[A, _] @unchecked if !optionColumnType.hasNullNullValue => columnIsNull || InfixFunctionColumn[Boolean]("=", column, ConstantColumn[A](None.asInstanceOf[A])(optionColumnType)) case _ => columnIsNull @@ -93,7 +100,7 @@ trait ColumnSyntax { val columnIsNotNull = PostfixFunctionColumn[Boolean]("is not null", column) column.columnType match { - case optionColumnType: OptionColumnType[A, _] if !optionColumnType.hasNullNullValue => + case optionColumnType: OptionColumnType[A, _] @unchecked if !optionColumnType.hasNullNullValue => columnIsNotNull && InfixFunctionColumn[Boolean]("<>", column, ConstantColumn[A](None.asInstanceOf[A])(optionColumnType)) case _ => columnIsNotNull diff --git a/sqlest/src/main/scala/sqlest/ast/syntax/GroupSyntax.scala b/sqlest/src/main/scala/sqlest/ast/syntax/GroupSyntax.scala index 62f3366..008d6fd 100644 --- a/sqlest/src/main/scala/sqlest/ast/syntax/GroupSyntax.scala +++ b/sqlest/src/main/scala/sqlest/ast/syntax/GroupSyntax.scala @@ -19,7 +19,7 @@ package sqlest.ast.syntax import sqlest.ast._ trait GroupSyntax { - implicit def columnGroup(column: Column[_]) = ColumnGroup(column) + implicit def columnGroup(column: Column[_]): ColumnGroup = ColumnGroup(column) def cube(columns: Group*) = FunctionGroup("cube", columns.toList) def rollUp(columns: Group*) = FunctionGroup("rollup", columns.toList) diff --git a/sqlest/src/main/scala/sqlest/ast/syntax/OrderSyntax.scala b/sqlest/src/main/scala/sqlest/ast/syntax/OrderSyntax.scala index 7666caf..d139f6b 100644 --- a/sqlest/src/main/scala/sqlest/ast/syntax/OrderSyntax.scala +++ b/sqlest/src/main/scala/sqlest/ast/syntax/OrderSyntax.scala @@ -24,7 +24,7 @@ trait OrderSyntax { def desc = Order(convertToSortedColumn(column), false) } - implicit def orderAsc(column: Column[_]) = + implicit def orderAsc(column: Column[_]): Order = Order(convertToSortedColumn(column), true) private def convertToSortedColumn[A](column: Column[A]): Column[_] = { diff --git a/sqlest/src/main/scala/sqlest/ast/syntax/QuerySyntax.scala b/sqlest/src/main/scala/sqlest/ast/syntax/QuerySyntax.scala index 5e2e349..8b48307 100644 --- a/sqlest/src/main/scala/sqlest/ast/syntax/QuerySyntax.scala +++ b/sqlest/src/main/scala/sqlest/ast/syntax/QuerySyntax.scala @@ -25,7 +25,7 @@ trait QuerySyntax { object delete extends DeleteSyntax object merge extends MergeSyntax - implicit def selectOps[A, R <: Relation](select: Select[A, R]) = SelectOps(select) + implicit def selectOps[A, R <: Relation](select: Select[A, R]): SelectOps[A, R] = SelectOps(select) def lateral[A, R <: Relation](select: Select[A, R]) = Lateral(select) def exists[A, R <: Relation](select: Select[A, R]) = ExistsColumn(select) def notExists[A, R <: Relation](select: Select[A, R]) = NotExistsColumn(select) diff --git a/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala b/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala index 6f91d4b..95205d0 100644 --- a/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala +++ b/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala @@ -36,7 +36,11 @@ class UntypedColumnHelpers extends ColumnSyntax { def bigDecimalArgument(arg: String) = Try(BigDecimal(arg)).toOption def dateTimeArgument(arg: String) = Iso8601.unapply(arg) def localDateArgument(arg: String) = Iso8601.unapply(arg).map(new LocalDate(_)) - def byteArrayArgument(arg: String) = Try(javax.xml.bind.DatatypeConverter.parseHexBinary(arg)).toOption + def byteArrayArgument(arg: String) = Try { + // Custom hex string to byte array conversion + if (arg.length % 2 != 0) throw new IllegalArgumentException("Hex string must have even length") + arg.grouped(2).map(Integer.parseInt(_, 16).toByte).toArray + }.toOption def mappedArgument[A](arg: String, columnType: ColumnType[A]): Option[A] = (columnType match { case IntColumnType => intArgument(arg) case LongColumnType => longArgument(arg) diff --git a/sqlest/src/main/scala/sqlest/executor/Database.scala b/sqlest/src/main/scala/sqlest/executor/Database.scala index 4f8569c..46f01aa 100644 --- a/sqlest/src/main/scala/sqlest/executor/Database.scala +++ b/sqlest/src/main/scala/sqlest/executor/Database.scala @@ -123,7 +123,7 @@ trait Database { object Session { def apply(database: Database) = new Session(database) - implicit def databaseToSession(implicit database: Database) = Session(database) + implicit def databaseToSession(implicit database: Database): Session = Session(database) } class Session(database: Database) extends Logging { diff --git a/sqlest/src/main/scala/sqlest/executor/ResultSetIterator.scala b/sqlest/src/main/scala/sqlest/executor/ResultSetIterator.scala index e0ad17f..f4854d3 100644 --- a/sqlest/src/main/scala/sqlest/executor/ResultSetIterator.scala +++ b/sqlest/src/main/scala/sqlest/executor/ResultSetIterator.scala @@ -26,7 +26,7 @@ case class ResultSetIterator(resultSet: ResultSet) extends Iterator[ResultSet] { private var readNextRow = false private var hasNextRow = false - def next: ResultSet = { + def next(): ResultSet = { if (!readNextRow) resultSet.next readNextRow = false resultSet diff --git a/sqlest/src/main/scala/sqlest/sql/base/BaseStatementBuilder.scala b/sqlest/src/main/scala/sqlest/sql/base/BaseStatementBuilder.scala index 0b31f79..f8d3f3a 100644 --- a/sqlest/src/main/scala/sqlest/sql/base/BaseStatementBuilder.scala +++ b/sqlest/src/main/scala/sqlest/sql/base/BaseStatementBuilder.scala @@ -160,7 +160,10 @@ trait BaseStatementBuilder { case StringColumnType => "'" + escapeSqlString(value.toString) + "'" case DateTimeColumnType => value.toString case LocalDateColumnType => value.toString - case ByteArrayColumnType => javax.xml.bind.DatatypeConverter.printHexBinary(value.asInstanceOf[Array[Byte]]) + case ByteArrayColumnType => { + val bytes = value.asInstanceOf[Array[Byte]] + bytes.map("%02x".format(_)).mkString.toUpperCase + } case optionType: OptionColumnType[_, _] => value.asInstanceOf[Option[_]] match { case None if optionType.hasNullNullValue => "null" case None => constantSql(optionType.baseColumnType.asInstanceOf[ColumnType[Any]], optionType.nullValue) diff --git a/sqlest/src/main/scala/sqlest/sql/base/SelectStatementBuilder.scala b/sqlest/src/main/scala/sqlest/sql/base/SelectStatementBuilder.scala index da6035f..298b3c2 100644 --- a/sqlest/src/main/scala/sqlest/sql/base/SelectStatementBuilder.scala +++ b/sqlest/src/main/scala/sqlest/sql/base/SelectStatementBuilder.scala @@ -84,6 +84,7 @@ trait SelectStatementBuilder extends BaseStatementBuilder { def joinSql(relation: Relation): String = relation match { case table: Table if table.tableName == table.tableAlias => identifierSql(table.tableName) case table: Table if table.tableName != table.tableAlias => identifierSql(table.tableName) + " as " + identifierSql(table.tableAlias) + case table: Table => identifierSql(table.tableName) // catch-all for Table cases case tableFunctionApplication: TableFunctionApplication[_] => functionSql(tableFunctionApplication.tableName, tableFunctionApplication.parameterColumns) + " as " + identifierSql(tableFunctionApplication.tableAlias) case TableFunctionFromSelect(select, alias) => throw new UnsupportedOperationException case LeftJoin(left, right, condition) => joinSql(left) + " left join " + joinSql(right) + " on " + columnSql(condition) diff --git a/sqlest/src/test/scala/sqlest/TestData.scala b/sqlest/src/test/scala/sqlest/TestData.scala index c2c8542..04eedc9 100644 --- a/sqlest/src/test/scala/sqlest/TestData.scala +++ b/sqlest/src/test/scala/sqlest/TestData.scala @@ -69,7 +69,7 @@ object TestData { case class WrappedInt(inner: Int) class TableSix(alias: Option[String]) extends Table("six", alias) { // Check that the implicit TrimmedStringColumnType gets applied to the trimmedString column - implicit val tsct = TrimmedStringColumnType + implicit val tsct: TrimmedStringColumnType.type = TrimmedStringColumnType val trimmedString = column[Option[WrappedString]]("trimmedString")(BlankIsNoneColumnType) val zeroIsNoneWrappedInt = column[Option[WrappedInt]]("zeroIsNoneWrappedInt")(ZeroIsNoneColumnType[WrappedInt, Int]) val zeroIsNoneLocalDate = column[Option[LocalDate]]("zeroIsNoneDateTime")(ZeroIsNoneColumnType(YyyyMmDdColumnType)) @@ -104,5 +104,5 @@ object TestData { override def next(): Boolean = { hasNext = !hasNext; hasNext } } - implicit def resultSetIterable(resultSet: ResultSet) = ResultSetIterable(resultSet) + implicit def resultSetIterable(resultSet: ResultSet) : ResultSetIterable = ResultSetIterable(resultSet) } \ No newline at end of file diff --git a/sqlest/src/test/scala/sqlest/ast/BaseColumnTypeEquivalenceSpec.scala b/sqlest/src/test/scala/sqlest/ast/BaseColumnTypeEquivalenceSpec.scala index 8747a39..3105bc9 100644 --- a/sqlest/src/test/scala/sqlest/ast/BaseColumnTypeEquivalenceSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/BaseColumnTypeEquivalenceSpec.scala @@ -16,14 +16,14 @@ package sqlest.ast -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import shapeless.test.illTyped import sqlest._ case class ValueClassString(string: String) extends AnyVal -abstract class BaseColumnTypeEquivalenceSpec extends FlatSpec with Matchers with GlobalStringMappedColumn { +abstract class BaseColumnTypeEquivalenceSpec extends AnyFlatSpec with Matchers with GlobalStringMappedColumn { import GlobalStringMappedColumn._ case class WrappedString(string: String) diff --git a/sqlest/src/test/scala/sqlest/ast/ColumnSpec.scala b/sqlest/src/test/scala/sqlest/ast/ColumnSpec.scala index c88ea84..e9e6a84 100644 --- a/sqlest/src/test/scala/sqlest/ast/ColumnSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/ColumnSpec.scala @@ -16,19 +16,19 @@ package sqlest.ast -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import shapeless.test.illTyped import sqlest._ -class ColumnSpec extends FlatSpec with Matchers { +class ColumnSpec extends AnyFlatSpec with Matchers { sealed trait Size case object Small extends Size case object Medium extends Size case object Large extends Size object Size { - implicit val sizeColumnType = EnumerationColumnType[Size, String](Small -> "S", Medium -> "M", Large -> "L") + implicit val sizeColumnType : EnumerationColumnType[Size, String] = EnumerationColumnType[Size, String](Small -> "S", Medium -> "M", Large -> "L") } case class WrappedInt(int: Int) @@ -53,9 +53,9 @@ class ColumnSpec extends FlatSpec with Matchers { object TableOne extends TableOne(None) "option column equivalences" should "allow binary operators involving base types and their option types" in { - (literalColumn(1) =!= 2) should equal(InfixFunctionColumn[Boolean]("<>", 1, 2)) - (literalColumn(Some(1)) =!= 2) should equal(InfixFunctionColumn[Boolean]("<>", Some(1), 2)) - (literalColumn(1) =!= Option.empty[Int]) should equal(InfixFunctionColumn[Boolean]("<>", 1, Option.empty[Int])) + (literalColumn(1) =!= 2) should equal(InfixFunctionColumn[Boolean]("<>", 1 : Int, 2 : Int)) + (literalColumn(Some(1)) =!= 2) should equal(InfixFunctionColumn[Boolean]("<>", Some(1), 2: Int)) + (literalColumn(1) =!= Option.empty[Int]) should equal(InfixFunctionColumn[Boolean]("<>", 1 : Int, Option.empty[Int])) (literalColumn(Some(1)) =!= Option.empty[Int]) should equal(InfixFunctionColumn[Boolean]("<>", Some(1), Option.empty[Int])) } @@ -72,11 +72,11 @@ class ColumnSpec extends FlatSpec with Matchers { "option column equivalences" should "allow binary operators involving mapped and unmapped types" in { val expr1 = (TableOne.col1 === 1) - expr1 should equal(InfixFunctionColumn[Boolean]("=", TableOne.col1, 1)) + expr1 should equal(InfixFunctionColumn[Boolean]("=", TableOne.col1, 1 : Int)) expr1.parameter2.columnType should equal(TableOne.col1.columnType) val expr2 = (TableOne.col3 === 1) - expr2 should equal(InfixFunctionColumn[Boolean]("=", TableOne.col3, 1)) + expr2 should equal(InfixFunctionColumn[Boolean]("=", TableOne.col3, 1 : Int)) expr2.parameter2.columnType should equal(TableOne.col3.columnType) val expr3 = (TableOne.col5 === "Hi!") diff --git a/sqlest/src/test/scala/sqlest/ast/ColumnTypeEquivalenceSpec.scala b/sqlest/src/test/scala/sqlest/ast/ColumnTypeEquivalenceSpec.scala index 36f2749..c5c9bc0 100644 --- a/sqlest/src/test/scala/sqlest/ast/ColumnTypeEquivalenceSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/ColumnTypeEquivalenceSpec.scala @@ -16,8 +16,8 @@ package sqlest.ast -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import shapeless.test.illTyped import sqlest._ diff --git a/sqlest/src/test/scala/sqlest/ast/ColumnTypeSpec.scala b/sqlest/src/test/scala/sqlest/ast/ColumnTypeSpec.scala index 35aecf0..55b361c 100644 --- a/sqlest/src/test/scala/sqlest/ast/ColumnTypeSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/ColumnTypeSpec.scala @@ -16,11 +16,11 @@ package sqlest.ast -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ -class ColumnTypeSpec extends FlatSpec with Matchers { +class ColumnTypeSpec extends AnyFlatSpec with Matchers { "basic data types" should "have implicit ColumnTypes" in { implicitly[ColumnType[Boolean]] implicitly[ColumnType[Int]] diff --git a/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala b/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala index b8b3fa5..9967925 100644 --- a/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala @@ -17,10 +17,10 @@ package sqlest.ast import org.joda.time.LocalDate -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ -class MappedColumnTypeSpec extends FlatSpec with Matchers with MappedColumnTypes { +class MappedColumnTypeSpec extends AnyFlatSpec with Matchers with MappedColumnTypes { "MappedBooleanColumnType" should "convert database values to booleans" in { val BooleanIntColumnType = MappedBooleanColumnType(1, 0) diff --git a/sqlest/src/test/scala/sqlest/ast/SelectSpec.scala b/sqlest/src/test/scala/sqlest/ast/SelectSpec.scala index e56d65a..a00e1d1 100644 --- a/sqlest/src/test/scala/sqlest/ast/SelectSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/SelectSpec.scala @@ -16,11 +16,11 @@ package sqlest.ast -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ -class SelectSpec extends FlatSpec with Matchers { +class SelectSpec extends AnyFlatSpec with Matchers { class MyTable(alias: Option[String]) extends Table("mytable", alias) { val col1 = column[Int]("col1") val col2 = column[Int]("col2") diff --git a/sqlest/src/test/scala/sqlest/ast/TableSpec.scala b/sqlest/src/test/scala/sqlest/ast/TableSpec.scala index 8ba101e..3f94322 100644 --- a/sqlest/src/test/scala/sqlest/ast/TableSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/TableSpec.scala @@ -16,11 +16,11 @@ package sqlest.ast -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ -class TableSpec extends FlatSpec with Matchers { +class TableSpec extends AnyFlatSpec with Matchers { class SimpleTable(alias: Option[String]) extends Table("mytable", alias) object SimpleTable extends SimpleTable(None) diff --git a/sqlest/src/test/scala/sqlest/ast/operations/ColumnOperationsSpec.scala b/sqlest/src/test/scala/sqlest/ast/operations/ColumnOperationsSpec.scala index 7e0107e..524e5c6 100644 --- a/sqlest/src/test/scala/sqlest/ast/operations/ColumnOperationsSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/operations/ColumnOperationsSpec.scala @@ -16,12 +16,12 @@ package sqlest.ast.operations -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ import sqlest.ast.operations.ColumnOperations._ -class ColumnOperationsSpec extends FlatSpec with Matchers { +class ColumnOperationsSpec extends AnyFlatSpec with Matchers { class TableOne(alias: Option[String]) extends Table("one", alias) { val col1 = column[Int]("col1") diff --git a/sqlest/src/test/scala/sqlest/ast/syntax/AggregateFunctionSyntaxSpec.scala b/sqlest/src/test/scala/sqlest/ast/syntax/AggregateFunctionSyntaxSpec.scala index ec47583..2cc8b37 100644 --- a/sqlest/src/test/scala/sqlest/ast/syntax/AggregateFunctionSyntaxSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/syntax/AggregateFunctionSyntaxSpec.scala @@ -16,12 +16,12 @@ package sqlest.ast.syntax -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ import sqlest.ast._ -class AggrgateFunctionSyntaxSpec extends FlatSpec with Matchers { +class AggrgateFunctionSyntaxSpec extends AnyFlatSpec with Matchers { class MyTable(alias: Option[String]) extends Table("mytable", alias) { val col1 = column[Int]("col1") val col2 = column[String]("col2") diff --git a/sqlest/src/test/scala/sqlest/ast/syntax/CaseSyntaxSpec.scala b/sqlest/src/test/scala/sqlest/ast/syntax/CaseSyntaxSpec.scala index 7fd1af0..3700fe8 100644 --- a/sqlest/src/test/scala/sqlest/ast/syntax/CaseSyntaxSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/syntax/CaseSyntaxSpec.scala @@ -16,12 +16,12 @@ package sqlest.ast.syntax -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ import sqlest.ast._ -class CaseSyntaxSpec extends FlatSpec with Matchers { +class CaseSyntaxSpec extends AnyFlatSpec with Matchers { val zeroIsNoneColumnType = ZeroIsNoneColumnType[Int, Int] class MyTable(alias: Option[String]) extends Table("mytable", alias) { val col1 = column[Int]("col1") diff --git a/sqlest/src/test/scala/sqlest/ast/syntax/UpdateSyntaxSpec.scala b/sqlest/src/test/scala/sqlest/ast/syntax/UpdateSyntaxSpec.scala index 67553a5..917668c 100644 --- a/sqlest/src/test/scala/sqlest/ast/syntax/UpdateSyntaxSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/syntax/UpdateSyntaxSpec.scala @@ -16,13 +16,13 @@ package sqlest.ast.syntax -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import shapeless.test.illTyped import sqlest._ import sqlest.ast._ -class UpdateSyntaxSpec extends FlatSpec with Matchers { +class UpdateSyntaxSpec extends AnyFlatSpec with Matchers { class MyTable(alias: Option[String]) extends Table("mytable", alias) { val col1 = column[Int]("col1") val col2 = column[Int]("col2") diff --git a/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala b/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala index bebeffe..2ca4771 100644 --- a/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala +++ b/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala @@ -17,8 +17,8 @@ package sqlest.executor import org.joda.time.LocalDate -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import scala.concurrent.{ Await, Future } import scala.concurrent.duration._ import scala.util.Try @@ -28,10 +28,10 @@ import sqlest.extractor.TestResultSet import scala.concurrent.ExecutionContext.Implicits.global -class ExecutorSpec extends FlatSpec with Matchers { +class ExecutorSpec extends AnyFlatSpec with Matchers { import TestData._ - implicit def testDatabase = TestDatabase(testResultSet) + implicit def testDatabase : TestDatabase = TestDatabase(testResultSet) val selectStatement = select(TableOne.col1, TableOne.col2).from(TableOne) val updateStatement = update(TableOne).set(TableOne.col1 -> 123).where(TableOne.col2 === "12") @@ -203,7 +203,7 @@ class ExecutorSpec extends FlatSpec with Matchers { Future(updateStatement.execute) } val result = Try(Await.result(transaction, 20.seconds)) - result shouldBe 'success + result shouldBe Symbol("success") database.lastConnection.get.closed shouldBe true } @@ -213,7 +213,7 @@ class ExecutorSpec extends FlatSpec with Matchers { Future(updateStatement.execute) } val result = Try(Await.result(transaction, 20.seconds)) - result shouldBe 'success + result shouldBe Symbol("success") database.lastConnection.get.committed shouldBe true } @@ -227,7 +227,7 @@ class ExecutorSpec extends FlatSpec with Matchers { } } val result = Try(Await.result(transaction, 20.seconds)) - result shouldBe 'success + result shouldBe Symbol("success") database.lastConnection.get.closed shouldBe true database.lastConnection.get.rolledBack shouldBe true database.lastConnection.get.committed shouldBe false @@ -239,7 +239,7 @@ class ExecutorSpec extends FlatSpec with Matchers { throw new Exception("Catastrophic error") } val result = Try(Await.result(transaction, 20.seconds)) - result shouldBe 'failure + result shouldBe Symbol("failure") database.lastConnection.get.closed shouldBe true database.lastConnection.get.rolledBack shouldBe true database.lastConnection.get.committed shouldBe false @@ -251,7 +251,7 @@ class ExecutorSpec extends FlatSpec with Matchers { Future(throw new Exception("Catastrophic error")) } val result = Try(Await.result(transaction, 20.seconds)) - result shouldBe 'failure + result shouldBe Symbol("failure") database.lastConnection.get.closed shouldBe true database.lastConnection.get.rolledBack shouldBe true database.lastConnection.get.committed shouldBe false diff --git a/sqlest/src/test/scala/sqlest/extractor/BigTableSpec.scala b/sqlest/src/test/scala/sqlest/extractor/BigTableSpec.scala index 0e84b36..8eb0a25 100644 --- a/sqlest/src/test/scala/sqlest/extractor/BigTableSpec.scala +++ b/sqlest/src/test/scala/sqlest/extractor/BigTableSpec.scala @@ -18,14 +18,14 @@ package sqlest package extractor import java.sql.ResultSet -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ /** * Proof-of-concept implementation of a table, domain class and extractor * with more than 22 fields in them. It's not pretty but it works. */ -class BigTableSpec extends FlatSpec with Matchers { +class BigTableSpec extends AnyFlatSpec with Matchers { class TableOne(alias: Option[String]) extends Table("one", alias) { val col1 = column[Int]("col1") val col2 = column[Int]("col2") diff --git a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala index bc19e20..7a825ec 100644 --- a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala +++ b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala @@ -17,8 +17,8 @@ package sqlest.extractor import org.joda.time.{ DateTime, LocalDate } -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ import sqlest.ast.Setter @@ -46,7 +46,7 @@ object Multiple { case class DefaultParams(a: Int, b: String = "sweet") -class ColumnExtractorSettersSpec extends FlatSpec with Matchers { +class ColumnExtractorSettersSpec extends AnyFlatSpec with Matchers { val oneExtractor = extract[One]( a = FirstTable.col1, @@ -130,7 +130,7 @@ class ColumnExtractorSettersSpec extends FlatSpec with Matchers { )) extract[DefaultParams](FirstTable.col1, FirstTable.col2).settersFor(DefaultParams(1)) should be(List( - Setter(FirstTable.col1, 1), + Setter(FirstTable.col1, 1 : Int), Setter(FirstTable.col2, "sweet") )) } diff --git a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala index 940191e..5176136 100644 --- a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala +++ b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala @@ -17,11 +17,11 @@ package sqlest.extractor import org.joda.time.{ DateTime, LocalDate } -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ -class ColumnExtractorSpec extends FlatSpec with Matchers { +class ColumnExtractorSpec extends AnyFlatSpec with Matchers { import TestData._ case class Inner(b: Int, c: List[Int]) diff --git a/sqlest/src/test/scala/sqlest/sql/BaseStatementBuilderSpec.scala b/sqlest/src/test/scala/sqlest/sql/BaseStatementBuilderSpec.scala index 71b9ba0..612e46e 100644 --- a/sqlest/src/test/scala/sqlest/sql/BaseStatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/BaseStatementBuilderSpec.scala @@ -16,20 +16,20 @@ package sqlest.sql -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ import sqlest.ast._ -trait BaseStatementBuilderSpec extends FlatSpec with Matchers { +trait BaseStatementBuilderSpec extends AnyFlatSpec with Matchers { implicit class StringFormatOps(sql: String) { - def formatSql = sql.trim.stripMargin.split(scala.util.Properties.lineSeparator).map(_.trim).mkString(" ") + def formatSql = sql.stripMargin.linesIterator.map(s => s.trim).mkString(" ").trim } implicit def statementBuilder: StatementBuilder def sql(operation: Operation) = { val (_, generatedSql, parameters) = statementBuilder(operation) - (generatedSql, parameters.map(_.map(_.value))) + (generatedSql.formatSql, parameters.map(_.map(_.value))) } // Test data ---------------------------------- @@ -45,8 +45,8 @@ trait BaseStatementBuilderSpec extends FlatSpec with Matchers { val col2 = column[String]("col2") } object TableOne extends TableOne(None) { - implicit val tableTwoJoinCondition = JoinCondition[TableOne, TableTwo](_.col2 === _.col2) - implicit val testTableFunctionJoinCondition = JoinCondition[TableOne, TestTableFunction](_.col1 === _.col6) + implicit val tableTwoJoinCondition : JoinCondition[TableOne, TableTwo] = JoinCondition[TableOne, TableTwo](_.col2 === _.col2) + implicit val testTableFunctionJoinCondition : JoinCondition[TableOne, TestTableFunction] = JoinCondition[TableOne, TestTableFunction](_.col1 === _.col6) } class TableTwo(alias: Option[String]) extends Table("two", alias) { diff --git a/sqlest/src/test/scala/sqlest/sql/DB2StatementBuilderSpec.scala b/sqlest/src/test/scala/sqlest/sql/DB2StatementBuilderSpec.scala index 814a9c1..cef6fdc 100644 --- a/sqlest/src/test/scala/sqlest/sql/DB2StatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/DB2StatementBuilderSpec.scala @@ -16,8 +16,8 @@ package sqlest.sql -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ import sqlest.ast._ diff --git a/sqlest/src/test/scala/sqlest/sql/DeleteStatementBuilderSpec.scala b/sqlest/src/test/scala/sqlest/sql/DeleteStatementBuilderSpec.scala index d93a326..b5ea20f 100644 --- a/sqlest/src/test/scala/sqlest/sql/DeleteStatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/DeleteStatementBuilderSpec.scala @@ -16,13 +16,13 @@ package sqlest.sql -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ import sqlest.ast._ class DeleteStatementBuilderSpec extends BaseStatementBuilderSpec { - implicit def statementBuilder = new base.StatementBuilder {} + implicit def statementBuilder : StatementBuilder = new base.StatementBuilder {} "delete" should "produce the right sql" in { sql { diff --git a/sqlest/src/test/scala/sqlest/sql/H2StatementBuilderSpec.scala b/sqlest/src/test/scala/sqlest/sql/H2StatementBuilderSpec.scala index 0ce37b0..49e0601 100644 --- a/sqlest/src/test/scala/sqlest/sql/H2StatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/H2StatementBuilderSpec.scala @@ -16,8 +16,8 @@ package sqlest.sql -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ import sqlest.ast._ diff --git a/sqlest/src/test/scala/sqlest/sql/InsertStatementBuilderSpec.scala b/sqlest/src/test/scala/sqlest/sql/InsertStatementBuilderSpec.scala index 767e814..e125bfc 100644 --- a/sqlest/src/test/scala/sqlest/sql/InsertStatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/InsertStatementBuilderSpec.scala @@ -16,13 +16,13 @@ package sqlest.sql -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ import sqlest.ast.{ Setter, LiteralColumn } class InsertStatementBuilderSpec extends BaseStatementBuilderSpec { - implicit def statementBuilder = new base.StatementBuilder {} + implicit def statementBuilder : StatementBuilder = new base.StatementBuilder {} "insert" should "produce the right sql" in { sql { diff --git a/sqlest/src/test/scala/sqlest/sql/MergeStatementBuilderSpec.scala b/sqlest/src/test/scala/sqlest/sql/MergeStatementBuilderSpec.scala index 1e5edef..48f764e 100644 --- a/sqlest/src/test/scala/sqlest/sql/MergeStatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/MergeStatementBuilderSpec.scala @@ -20,7 +20,7 @@ import sqlest._ import sqlest.ast._ class MergeStatementBuilderSpec extends BaseStatementBuilderSpec { - implicit def statementBuilder = new base.StatementBuilder {} + implicit def statementBuilder : StatementBuilder = new base.StatementBuilder {} "merge" should "produce the right sql" in { diff --git a/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala b/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala index 5ec539c..64fbb91 100644 --- a/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala @@ -17,13 +17,13 @@ package sqlest.sql import org.joda.time.LocalDate -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ import sqlest.ast._ class SelectStatementBuilderSpec extends BaseStatementBuilderSpec { - implicit def statementBuilder = new base.StatementBuilder {} + implicit def statementBuilder : StatementBuilder = new base.StatementBuilder {} "empty query" should "render ok" in { sql { diff --git a/sqlest/src/test/scala/sqlest/sql/UpdateStatementBuilderSpec.scala b/sqlest/src/test/scala/sqlest/sql/UpdateStatementBuilderSpec.scala index 90f40e8..cfd9227 100644 --- a/sqlest/src/test/scala/sqlest/sql/UpdateStatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/UpdateStatementBuilderSpec.scala @@ -16,13 +16,13 @@ package sqlest.sql -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ import sqlest.ast._ class UpdateStatementBuilderSpec extends BaseStatementBuilderSpec { - implicit def statementBuilder = new base.StatementBuilder {} + implicit def statementBuilder : StatementBuilder = new base.StatementBuilder {} "update" should "produce the right sql" in { sql { diff --git a/sqlest/src/test/scala/sqlest/untyped/ExtractorFinderSpec.scala b/sqlest/src/test/scala/sqlest/untyped/ExtractorFinderSpec.scala index bbae3ca..4cbd72f 100644 --- a/sqlest/src/test/scala/sqlest/untyped/ExtractorFinderSpec.scala +++ b/sqlest/src/test/scala/sqlest/untyped/ExtractorFinderSpec.scala @@ -18,10 +18,10 @@ package sqlest.untyped import sqlest._ import sqlest.extractor.TestResultSet -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ -class ExtractorFinderSpec extends FlatSpec with Matchers { +class ExtractorFinderSpec extends AnyFlatSpec with Matchers { import TestData._ "cell extractor finder" should "find a cell extractor in a single extractor" in { diff --git a/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala b/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala index 266306d..7ec99f2 100644 --- a/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala +++ b/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala @@ -17,11 +17,11 @@ package sqlest.untyped.ast import org.joda.time._ -import org.scalatest._ -import org.scalatest.matchers._ +import org.scalatest.flatspec._ +import org.scalatest.matchers.should._ import sqlest._ -class ColumnSpec extends FlatSpec with Matchers { +class ColumnSpec extends AnyFlatSpec with Matchers { class TableOne(alias: Option[String]) extends Table("one", alias) { val intCol = column[Int]("intCol") diff --git a/version.sbt b/version.sbt index 77d6943..35e2fb4 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -version in ThisBuild := "0.8.16-SNAPSHOT" +ThisBuild / version := "0.9.8-SNAPSHOT"