From 44453e0bf30ce7890eec869022a12f9aa002ca87 Mon Sep 17 00:00:00 2001 From: martin Date: Thu, 24 Jul 2025 14:19:02 +0100 Subject: [PATCH 01/22] upgrade plugins and build tools --- .scalafmt.conf | 13 +++++++++ build.sbt | 60 +++++++++++++++++++--------------------- project/build.properties | 2 +- project/plugins.sbt | 23 +++++++++------ 4 files changed, 56 insertions(+), 42 deletions(-) create mode 100644 .scalafmt.conf diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..0d42898 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,13 @@ +version = "3.7.15" +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/build.sbt b/build.sbt index 1a2ecdc..1fad580 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.5") ).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.12.5", + "org.joda" % "joda-convert" % "2.2.3" ) ) 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.2.224") .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.11", + crossScalaVersions := List("2.12.18", "2.13.11"), scalacOptions ++= Seq( "-deprecation", "-encoding", "UTF-8", @@ -54,39 +49,40 @@ lazy val commonSettings = SbtScalariform.scalariformSettings ++ publishingSettin "-language:higherKinds", "-language:implicitConversions", "-unchecked", - "-Xfatal-warnings", - "-Xfuture" + "-Xfatal-warnings" ), - 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.17" % "test", + "com.chuusai" %% "shapeless" % "2.3.10" % "test", + "com.h2database" % "h2" % "2.2.224" % "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/" if (isSnapshot.value) diff --git a/project/build.properties b/project/build.properties index 133a8f1..04267b1 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.17 +sbt.version=1.9.9 diff --git a/project/plugins.sbt b/project/plugins.sbt index 12ef8ba..692aafc 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,19 +1,24 @@ -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("org.scalameta" % "sbt-scalafmt" % "2.5.2") -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "1.1") +addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.2.1") -addSbtPlugin("io.spray" % "sbt-boilerplate" % "0.6.0") +addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.10.0") -addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "0.8.1") +addSbtPlugin("io.spray" % "sbt-boilerplate" % "0.6.1") -addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.5.4") +addSbtPlugin("com.github.sbt" % "sbt-site" % "1.6.0") -addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.3") +addSbtPlugin("com.github.sbt" % "sbt-ghpages" % "0.8.0") -addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.8") +addSbtPlugin("com.github.sbt" % "sbt-git" % "2.0.1") -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.0") +addSbtPlugin("com.github.sbt" % "sbt-release" % "1.4.0") + +addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.5.2") + +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.11") addSbtPlugin("com.sonar-scala" % "sbt-sonar" % "2.3.0") \ No newline at end of file From 5c6a5d3749a43ed82e7b70e8f76a9385405aa762 Mon Sep 17 00:00:00 2001 From: martin Date: Thu, 24 Jul 2025 14:54:46 +0100 Subject: [PATCH 02/22] scala upgrade - by copiolot --- .../main/scala/sqlest/examples/Database.scala | 3 +- .../extractor/ExtractorSyntax.scala.template | 6 +-- .../extractor/CaseClassExtractorMacro.scala | 2 +- .../scala/sqlest/extractor/Extractor.scala | 14 +++---- .../sqlest/ast/TupleGroups.scala.template | 4 +- .../main/scala/sqlest/ast/ColumnType.scala | 40 +++++++++++-------- .../sqlest/ast/ColumnTypeEquivalence.scala | 10 ++--- .../scala/sqlest/ast/syntax/CaseSyntax.scala | 6 +-- .../sqlest/ast/syntax/ColumnSyntax.scala | 21 ++++++---- .../scala/sqlest/ast/syntax/GroupSyntax.scala | 2 +- .../scala/sqlest/ast/syntax/OrderSyntax.scala | 2 +- .../scala/sqlest/ast/syntax/QuerySyntax.scala | 2 +- .../ast/syntax/UntypedColumnSyntax.scala | 6 ++- .../main/scala/sqlest/executor/Database.scala | 2 +- .../sqlest/executor/ResultSetIterator.scala | 2 +- .../sql/base/BaseStatementBuilder.scala | 5 ++- .../sql/base/SelectStatementBuilder.scala | 1 + 17 files changed, 75 insertions(+), 53 deletions(-) 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/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..329db29 100644 --- a/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala +++ b/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala @@ -136,7 +136,7 @@ case class CaseClassExtractorMacro(c: Context) { val liftedParamTypes = paramTypes.map(liftParam) - (paramNames, liftedParamTypes, defaultValues).zipped.map { + paramNames.lazyZip(liftedParamTypes).lazyZip(defaultValues).map { case (paramName, typ, defaultValue) => if (defaultValue.isDefined) q"val $paramName: $typ = sqlest.extractor.ConstantExtractor(${defaultValue.get})" 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/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) From 5a81322dbc4a26f9b47ef983695fbb3fee9381b7 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Fri, 26 Sep 2025 16:20:52 +0100 Subject: [PATCH 03/22] Checkpoint before the weekend - still lots of errors to fix --- .gitignore | 1 + README.md | 2 +- build.sbt | 37 +++++++++---------- extractors/README.md | 2 +- .../CaseClassExtractorMacroSpec.scala | 7 +++- .../sqlest/extractor/ExtractorSpec.scala | 8 ++-- project/build.properties | 2 +- project/plugins.sbt | 4 +- sqlest/src/test/scala/sqlest/TestData.scala | 4 +- .../ast/BaseColumnTypeEquivalenceSpec.scala | 6 +-- .../test/scala/sqlest/ast/ColumnSpec.scala | 8 ++-- .../ast/ColumnTypeEquivalenceSpec.scala | 4 +- .../scala/sqlest/ast/ColumnTypeSpec.scala | 6 +-- .../sqlest/ast/MappedColumnTypesSpec.scala | 6 +-- .../test/scala/sqlest/ast/SelectSpec.scala | 6 +-- .../src/test/scala/sqlest/ast/TableSpec.scala | 6 +-- .../ast/operations/ColumnOperationsSpec.scala | 6 +-- .../syntax/AggregateFunctionSyntaxSpec.scala | 6 +-- .../sqlest/ast/syntax/CaseSyntaxSpec.scala | 6 +-- .../sqlest/ast/syntax/UpdateSyntaxSpec.scala | 6 +-- .../scala/sqlest/executor/ExecutorSpec.scala | 18 ++++----- .../scala/sqlest/extractor/BigTableSpec.scala | 6 +-- .../ColumnExtractorSettersSpec.scala | 6 +-- .../extractor/ColumnExtractorSpec.scala | 6 +-- .../sqlest/sql/BaseStatementBuilderSpec.scala | 10 ++--- .../sqlest/sql/DB2StatementBuilderSpec.scala | 4 +- .../sql/DeleteStatementBuilderSpec.scala | 6 +-- .../sqlest/sql/H2StatementBuilderSpec.scala | 4 +- .../sql/InsertStatementBuilderSpec.scala | 6 +-- .../sql/MergeStatementBuilderSpec.scala | 2 +- .../sql/SelectStatementBuilderSpec.scala | 6 +-- .../sql/UpdateStatementBuilderSpec.scala | 6 +-- .../sqlest/untyped/ExtractorFinderSpec.scala | 6 +-- .../scala/sqlest/untyped/ast/ColumnSpec.scala | 6 +-- version.sbt | 2 +- 35 files changed, 114 insertions(+), 113 deletions(-) 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/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 1fad580..aa34918 100644 --- a/build.sbt +++ b/build.sbt @@ -26,21 +26,21 @@ lazy val extractors = (project in file("extractors")) mdocOut := file("extractors"), libraryDependencies ++= Seq( "org.scala-lang" % "scala-reflect" % scalaVersion.value, - "joda-time" % "joda-time" % "2.12.5", - "org.joda" % "joda-convert" % "2.2.3" + "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" % "2.2.224") + .settings(libraryDependencies += "com.h2database" % "h2" % "2.3.232") .dependsOn(sqlest) lazy val commonSettings = publishingSettings ++ Seq( organization := "uk.co.jhc", - scalaVersion := "2.13.11", - crossScalaVersions := List("2.12.18", "2.13.11"), + scalaVersion := "2.13.15", + crossScalaVersions := List("2.12.18", "2.13.15"), scalacOptions ++= Seq( "-deprecation", "-encoding", "UTF-8", @@ -57,9 +57,9 @@ lazy val commonSettings = publishingSettings ++ Seq( lazy val sqlestSettings = commonSettings ++ scaladocSettings ++ mdocSettings ++ Seq( mdocVariables := Map("VERSION" -> version.value), libraryDependencies ++= Seq( - "org.scalatest" %% "scalatest" % "3.2.17" % "test", - "com.chuusai" %% "shapeless" % "2.3.10" % "test", - "com.h2database" % "h2" % "2.2.224" % "test" + "org.scalatest" %% "scalatest" % "3.2.18" % "test", + "com.chuusai" %% "shapeless" % "2.3.12" % "test", + "com.h2database" % "h2" % "2.3.232" % "test" ) ) @@ -84,20 +84,17 @@ lazy val publishingSettings = sonatypeReleaseProcess ++ Seq( publishMavenStyle := true, 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 @@ -136,7 +133,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/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/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala b/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala index ac5e676..1786f8e 100644 --- a/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala +++ b/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala @@ -16,7 +16,10 @@ package sqlest.extractor -import org.scalatest._ +import org.scalatest.flatspec._ +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 +37,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 04267b1..e480c67 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.9.9 +sbt.version=1.11.5 diff --git a/project/plugins.sbt b/project/plugins.sbt index 692aafc..985bc43 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,12 +1,10 @@ // Dependency resolution to fix version conflicts ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.5") addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.2.1") -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.10.0") - addSbtPlugin("io.spray" % "sbt-boilerplate" % "0.6.1") addSbtPlugin("com.github.sbt" % "sbt-site" % "1.6.0") 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..cb2b9fc 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) 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..085362d 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, 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..f06a89a 100644 --- a/sqlest/src/test/scala/sqlest/sql/BaseStatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/BaseStatementBuilderSpec.scala @@ -16,12 +16,12 @@ 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(" ") } @@ -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..b0b9d99 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -version in ThisBuild := "0.8.16-SNAPSHOT" +ThisBuild / version := "0.9.4-SNAPSHOT" From d907d407ab4950bb0e3b9fce566b0d6ab284a1fb Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Tue, 30 Sep 2025 17:02:57 +0100 Subject: [PATCH 04/22] Checkpoint with some problematic tests commented out, just to see if they really matter --- build.sbt | 5 ++++- .../extractor/CaseClassExtractorMacro.scala | 2 +- .../CaseClassExtractorMacroSpec.scala | 2 +- .../test/scala/sqlest/ast/ColumnSpec.scala | 10 +++++----- .../ColumnExtractorSettersSpec.scala | 10 +++++----- .../extractor/ColumnExtractorSpec.scala | 20 +++++++++---------- .../sqlest/sql/BaseStatementBuilderSpec.scala | 4 ++-- 7 files changed, 28 insertions(+), 25 deletions(-) diff --git a/build.sbt b/build.sbt index aa34918..0cee30d 100644 --- a/build.sbt +++ b/build.sbt @@ -49,7 +49,10 @@ lazy val commonSettings = publishingSettings ++ Seq( "-language:higherKinds", "-language:implicitConversions", "-unchecked", - "-Xfatal-warnings" + "-Xfatal-warnings"//, +// "-Ystatistics:typer", +// "-Xlog-implicit-conversions", +// "-Xlog-implicits" ), coverageExcludedPackages := "sqlest.examples" ) diff --git a/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala b/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala index 329db29..581a5c6 100644 --- a/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala +++ b/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala @@ -152,7 +152,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/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala b/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala index 1786f8e..e5bf881 100644 --- a/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala +++ b/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala @@ -136,7 +136,7 @@ class CaseClassExtractorMacroSpec extends AnyFlatSpec with Matchers with Extract extract[ReversedTypeParamClass[String, Int]](intExtractor, stringExtractor) extract[DuplicateTypeParamClass[Int]](intExtractor, intExtractor) extract[MixedTypeParamClass[Int]](stringExtractor, intExtractor) - extract[List[String]](stringExtractor, stringExtractor) +// extract[List[String]](stringExtractor, stringExtractor) extract[Map[Int, String]](intExtractor -> stringExtractor, intExtractor -> stringExtractor) } diff --git a/sqlest/src/test/scala/sqlest/ast/ColumnSpec.scala b/sqlest/src/test/scala/sqlest/ast/ColumnSpec.scala index cb2b9fc..e9e6a84 100644 --- a/sqlest/src/test/scala/sqlest/ast/ColumnSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/ColumnSpec.scala @@ -53,9 +53,9 @@ class ColumnSpec extends AnyFlatSpec 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 AnyFlatSpec 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/extractor/ColumnExtractorSettersSpec.scala b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala index 085362d..c0f4dee 100644 --- a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala +++ b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala @@ -130,7 +130,7 @@ class ColumnExtractorSettersSpec extends AnyFlatSpec 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") )) } @@ -155,10 +155,10 @@ class ColumnExtractorSettersSpec extends AnyFlatSpec with Matchers { Setter(FirstTable.col5, 3) )) - extract[List[Int]](FirstTable.col1, FirstTable.col5).settersFor(List(1, 3)) should be(List( - Setter(FirstTable.col1, 1), - Setter(FirstTable.col5, 3) - )) +// extract[List[Int]](FirstTable.col1, FirstTable.col5).settersFor(List(1, 3)) should be(List( +// Setter(FirstTable.col1, 1), +// Setter(FirstTable.col5, 3) +// )) } it should "return setters for case class with type parameters" in { diff --git a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala index 5176136..a02d9ef 100644 --- a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala +++ b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala @@ -152,16 +152,16 @@ class ColumnExtractorSpec extends AnyFlatSpec with Matchers { TypeParamClass("e", -1) )) - val extractor2 = extract[List[String]](TableOne.col2, TableTwo.col2) - extractor2.extractHeadOption(testResultSet) should equal(Some( - List("a", "b") - )) - - extractor2.extractAll(testResultSet) should equal(List( - List("a", "b"), - List("c", "d"), - List("e", "f") - )) +// val extractor2 = extract[List[String]](TableOne.col2, TableTwo.col2) +// extractor2.extractHeadOption(testResultSet) should equal(Some( +// List("a", "b") +// )) + +// extractor2.extractAll(testResultSet) should equal(List( +// List("a", "b"), +// List("c", "d"), +// List("e", "f") +// )) val extractor3 = extract[ReversedTypeParamClass[String, Int]](TableOne.col1, TableOne.col2) extractor3.extractHeadOption(testResultSet) should equal(Some( diff --git a/sqlest/src/test/scala/sqlest/sql/BaseStatementBuilderSpec.scala b/sqlest/src/test/scala/sqlest/sql/BaseStatementBuilderSpec.scala index f06a89a..612e46e 100644 --- a/sqlest/src/test/scala/sqlest/sql/BaseStatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/BaseStatementBuilderSpec.scala @@ -23,13 +23,13 @@ import sqlest.ast._ 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 ---------------------------------- From 49c75d7b8eb4f984fb9e1f2ecd21967c02ce8c0f Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Tue, 7 Oct 2025 16:06:43 +0100 Subject: [PATCH 05/22] Update versions --- build.sbt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/build.sbt b/build.sbt index 0cee30d..9b31469 100644 --- a/build.sbt +++ b/build.sbt @@ -14,7 +14,7 @@ lazy val sqlest = (project in file("sqlest")) .settings( mdocIn := file("docs") / "sqlest", mdocOut := file("."), - libraryDependencies ++= Seq("com.typesafe.scala-logging" %% "scala-logging" % "3.9.5") + libraryDependencies ++= Seq("com.typesafe.scala-logging" %% "scala-logging" % "3.9.6") ).dependsOn(extractors) lazy val extractors = (project in file("extractors")) @@ -34,13 +34,13 @@ lazy val extractors = (project in file("extractors")) lazy val examples = (project in file("examples")) .settings(commonSettings: _*) .settings(noPublishSettings: _*) - .settings(libraryDependencies += "com.h2database" % "h2" % "2.3.232") + .settings(libraryDependencies += "com.h2database" % "h2" % "2.4.240") .dependsOn(sqlest) lazy val commonSettings = publishingSettings ++ Seq( organization := "uk.co.jhc", - scalaVersion := "2.13.15", - crossScalaVersions := List("2.12.18", "2.13.15"), + scalaVersion := "2.13.16", + crossScalaVersions := List("2.12.15", "2.13.16"), scalacOptions ++= Seq( "-deprecation", "-encoding", "UTF-8", @@ -60,9 +60,9 @@ lazy val commonSettings = publishingSettings ++ Seq( lazy val sqlestSettings = commonSettings ++ scaladocSettings ++ mdocSettings ++ Seq( mdocVariables := Map("VERSION" -> version.value), libraryDependencies ++= Seq( - "org.scalatest" %% "scalatest" % "3.2.18" % "test", - "com.chuusai" %% "shapeless" % "2.3.12" % "test", - "com.h2database" % "h2" % "2.3.232" % "test" + "org.scalatest" %% "scalatest" % "3.2.19" % "test", + "com.chuusai" %% "shapeless" % "2.3.13" % "test", + "com.h2database" % "h2" % "2.4.240" % "test" ) ) From f0a6bc3cc578fe54e126c93494e025cd6dd4bdcf Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Mon, 13 Oct 2025 14:14:59 +0100 Subject: [PATCH 06/22] Update scalafmt and remove unused plugin --- .scalafmt.conf | 2 +- project/plugins.sbt | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 0d42898..af99174 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = "3.7.15" +version = "3.9.10" runner.dialect = scala213 maxColumn = 120 align.preset = more diff --git a/project/plugins.sbt b/project/plugins.sbt index 985bc43..bd359d3 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,8 +1,6 @@ // Dependency resolution to fix version conflicts ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.5") - addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.2.1") addSbtPlugin("io.spray" % "sbt-boilerplate" % "0.6.1") From df36e3a84ec26a856d4c4ddb8664e74ad14fb6eb Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Tue, 14 Oct 2025 14:27:47 +0100 Subject: [PATCH 07/22] Add sqlestUnapplyList method to fix issue with List.unapplySeq in 2.13 --- .../extractor/CaseClassExtractorMacro.scala | 23 +++++++++++-------- .../CaseClassExtractorMacroSpec.scala | 3 +-- .../ColumnExtractorSettersSpec.scala | 8 +++---- .../extractor/ColumnExtractorSpec.scala | 20 ++++++++-------- 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala b/extractors/src/main/scala/sqlest/extractor/CaseClassExtractorMacro.scala index 581a5c6..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 { @@ -137,11 +142,11 @@ case class CaseClassExtractorMacro(c: Context) { val liftedParamTypes = paramTypes.map(liftParam) 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" + case (paramName, typ, defaultValue) => + if (defaultValue.isDefined) + q"val $paramName: $typ = sqlest.extractor.ConstantExtractor(${defaultValue.get})" + else + q"val $paramName: $typ" } } diff --git a/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala b/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala index e5bf881..0f47ec1 100644 --- a/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala +++ b/extractors/src/test/scala/sqlest/extractor/CaseClassExtractorMacroSpec.scala @@ -16,7 +16,6 @@ package sqlest.extractor -import org.scalatest.flatspec._ import org.scalatest.flatspec._ import org.scalatest.matchers.should._ import org.scalatest.prop._ @@ -136,7 +135,7 @@ class CaseClassExtractorMacroSpec extends AnyFlatSpec with Matchers with Extract extract[ReversedTypeParamClass[String, Int]](intExtractor, stringExtractor) extract[DuplicateTypeParamClass[Int]](intExtractor, intExtractor) extract[MixedTypeParamClass[Int]](stringExtractor, intExtractor) -// extract[List[String]](stringExtractor, stringExtractor) + extract[List[String]](stringExtractor, stringExtractor) extract[Map[Int, String]](intExtractor -> stringExtractor, intExtractor -> stringExtractor) } diff --git a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala index c0f4dee..7a825ec 100644 --- a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala +++ b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala @@ -155,10 +155,10 @@ class ColumnExtractorSettersSpec extends AnyFlatSpec with Matchers { Setter(FirstTable.col5, 3) )) -// extract[List[Int]](FirstTable.col1, FirstTable.col5).settersFor(List(1, 3)) should be(List( -// Setter(FirstTable.col1, 1), -// Setter(FirstTable.col5, 3) -// )) + extract[List[Int]](FirstTable.col1, FirstTable.col5).settersFor(List(1, 3)) should be(List( + Setter(FirstTable.col1, 1), + Setter(FirstTable.col5, 3) + )) } it should "return setters for case class with type parameters" in { diff --git a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala index a02d9ef..5176136 100644 --- a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala +++ b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala @@ -152,16 +152,16 @@ class ColumnExtractorSpec extends AnyFlatSpec with Matchers { TypeParamClass("e", -1) )) -// val extractor2 = extract[List[String]](TableOne.col2, TableTwo.col2) -// extractor2.extractHeadOption(testResultSet) should equal(Some( -// List("a", "b") -// )) - -// extractor2.extractAll(testResultSet) should equal(List( -// List("a", "b"), -// List("c", "d"), -// List("e", "f") -// )) + val extractor2 = extract[List[String]](TableOne.col2, TableTwo.col2) + extractor2.extractHeadOption(testResultSet) should equal(Some( + List("a", "b") + )) + + extractor2.extractAll(testResultSet) should equal(List( + List("a", "b"), + List("c", "d"), + List("e", "f") + )) val extractor3 = extract[ReversedTypeParamClass[String, Int]](TableOne.col1, TableOne.col2) extractor3.extractHeadOption(testResultSet) should equal(Some( From 43dff19d8f8a425eefc9cc2f43299840bbfc6a41 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Tue, 21 Oct 2025 08:45:59 +0100 Subject: [PATCH 08/22] Replace joda with java time --- .../scala/sqlest/extractor/Extractor.scala | 1 - sqlest/src/main/scala/sqlest/ast/Column.scala | 6 ++--- .../main/scala/sqlest/ast/ColumnType.scala | 4 ++-- .../scala/sqlest/ast/MappedColumnTypes.scala | 18 +++++++------- .../ast/syntax/UntypedColumnSyntax.scala | 4 ++-- .../main/scala/sqlest/executor/Database.scala | 24 +++++++++---------- .../sqlest/extractor/IndexedExtractor.scala | 6 ++--- .../src/main/scala/sqlest/util/Iso8601.scala | 24 +++++++++---------- sqlest/src/test/scala/sqlest/TestData.scala | 6 ++--- .../sqlest/ast/MappedColumnTypesSpec.scala | 14 +++++------ .../scala/sqlest/executor/ExecutorSpec.scala | 4 ++-- .../ColumnExtractorSettersSpec.scala | 2 +- .../extractor/ColumnExtractorSpec.scala | 14 +++++------ .../sql/SelectStatementBuilderSpec.scala | 2 +- .../scala/sqlest/untyped/ast/ColumnSpec.scala | 8 ++++--- 15 files changed, 68 insertions(+), 69 deletions(-) diff --git a/extractors/src/main/scala/sqlest/extractor/Extractor.scala b/extractors/src/main/scala/sqlest/extractor/Extractor.scala index f96589e..a651303 100644 --- a/extractors/src/main/scala/sqlest/extractor/Extractor.scala +++ b/extractors/src/main/scala/sqlest/extractor/Extractor.scala @@ -16,7 +16,6 @@ package sqlest.extractor -import org.joda.time.DateTime import scala.collection.immutable.{ Queue, ListMap } sealed trait Extractor[Row, A] extends ChoiceExtractorSyntax[Row, A] { diff --git a/sqlest/src/main/scala/sqlest/ast/Column.scala b/sqlest/src/main/scala/sqlest/ast/Column.scala index 14594c7..913fc53 100644 --- a/sqlest/src/main/scala/sqlest/ast/Column.scala +++ b/sqlest/src/main/scala/sqlest/ast/Column.scala @@ -17,7 +17,7 @@ package sqlest.ast import java.sql.ResultSet -import org.joda.time.{ DateTime, LocalDate } +import java.time.{LocalDateTime, LocalDate} import sqlest.extractor.CellExtractor /** @@ -111,8 +111,8 @@ sealed trait AliasedColumn[A] extends Column[A] with CellExtractor[ResultSet, A] case BigDecimalColumnType => Option(resultSet.getBigDecimal(columnAlias)).map(BigDecimal.apply) case BooleanColumnType => checkNull(resultSet.getBoolean(columnAlias)) case StringColumnType => checkNull(resultSet.getString(columnAlias)) - case DateTimeColumnType => checkNull(new DateTime(resultSet.getTimestamp(columnAlias))) - case LocalDateColumnType => checkNull(new LocalDate(resultSet.getDate(columnAlias))) + case DateTimeColumnType => checkNull(resultSet.getTimestamp(columnAlias).toLocalDateTime) + case LocalDateColumnType => checkNull(resultSet.getDate(columnAlias).toLocalDate) case ByteArrayColumnType => checkNull(resultSet.getBytes(columnAlias)) } } diff --git a/sqlest/src/main/scala/sqlest/ast/ColumnType.scala b/sqlest/src/main/scala/sqlest/ast/ColumnType.scala index 6143e82..7376ef3 100644 --- a/sqlest/src/main/scala/sqlest/ast/ColumnType.scala +++ b/sqlest/src/main/scala/sqlest/ast/ColumnType.scala @@ -16,7 +16,7 @@ package sqlest.ast -import org.joda.time.{ DateTime, LocalDate } +import java.time.{ LocalDateTime, LocalDate } import scala.language.experimental.macros import scala.reflect.macros.whitebox.Context @@ -50,7 +50,7 @@ case object BigDecimalColumnType extends NumericColumnType[BigDecimal] case object BooleanColumnType extends NonNumericColumnType[Boolean] case object StringColumnType extends NonNumericColumnType[String] -case object DateTimeColumnType extends NonNumericColumnType[DateTime] +case object DateTimeColumnType extends NonNumericColumnType[LocalDateTime] case object LocalDateColumnType extends NonNumericColumnType[LocalDate] case object ByteArrayColumnType extends NonNumericColumnType[Array[Byte]] diff --git a/sqlest/src/main/scala/sqlest/ast/MappedColumnTypes.scala b/sqlest/src/main/scala/sqlest/ast/MappedColumnTypes.scala index f02c8c0..7d3b1de 100644 --- a/sqlest/src/main/scala/sqlest/ast/MappedColumnTypes.scala +++ b/sqlest/src/main/scala/sqlest/ast/MappedColumnTypes.scala @@ -16,7 +16,7 @@ package sqlest.ast -import org.joda.time.{ DateTime, LocalDate } +import java.time.{ LocalDateTime, LocalDate } /** Standard set of MappedColumnTypes for various column types: */ trait MappedColumnTypes @@ -145,23 +145,23 @@ trait LocalDateMappedColumnTypes { val month = (database % 10000) / 100 val day = database % 100 - new LocalDate(year, month, day) + LocalDate.of(year, month, day) } def mappedWrite(value: LocalDate) = - value.getYear * 10000 + value.getMonthOfYear * 100 + value.getDayOfMonth + value.getYear * 10000 + value.getMonthValue * 100 + value.getDayOfMonth } - case object LocalDateFromDateTimeColumnType extends MappedColumnType[LocalDate, DateTime] { + case object LocalDateFromDateTimeColumnType extends MappedColumnType[LocalDate, LocalDateTime] { val baseColumnType = DateTimeColumnType - def mappedRead(database: DateTime) = database.toLocalDate - def mappedWrite(value: LocalDate) = value.toDateTimeAtStartOfDay + def mappedRead(database: LocalDateTime) = database.toLocalDate + def mappedWrite(value: LocalDate) = value.atStartOfDay } - case object DateTimeFromLocalDateColumnType extends MappedColumnType[DateTime, LocalDate] { + case object DateTimeFromLocalDateColumnType extends MappedColumnType[LocalDateTime, LocalDate] { val baseColumnType = LocalDateColumnType - def mappedRead(database: LocalDate) = database.toDateTimeAtStartOfDay - def mappedWrite(value: DateTime) = value.toLocalDate + def mappedRead(database: LocalDate) = database.atStartOfDay + def mappedWrite(value: LocalDateTime) = value.toLocalDate } } diff --git a/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala b/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala index 95205d0..62e67e8 100644 --- a/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala +++ b/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala @@ -16,7 +16,7 @@ package sqlest.ast.syntax -import org.joda.time.{ DateTime, LocalDate } +import java.time.{ LocalDateTime, LocalDate } import scala.reflect.runtime.{ universe => ru } import scala.util.Try import sqlest.ast._ @@ -35,7 +35,7 @@ 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 localDateArgument(arg: String) = Try(Iso8601.unapply(arg).get.toLocalDate).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") diff --git a/sqlest/src/main/scala/sqlest/executor/Database.scala b/sqlest/src/main/scala/sqlest/executor/Database.scala index 46f01aa..9cb2e5a 100644 --- a/sqlest/src/main/scala/sqlest/executor/Database.scala +++ b/sqlest/src/main/scala/sqlest/executor/Database.scala @@ -23,7 +23,7 @@ import sqlest.util.Logging import java.sql.{ Connection, Date => JdbcDate, DriverManager, ResultSet, PreparedStatement, Statement, SQLException, Timestamp => JdbcTimestamp, Types => JdbcTypes } import javax.sql.DataSource -import org.joda.time.{ DateTime, LocalDate } +import java.time.{ LocalDateTime, LocalDate } import scala.concurrent.{ ExecutionContext, Future } import scala.util.{ DynamicVariable, Try, Success, Failure } import scala.util.control.NonFatal @@ -142,7 +142,7 @@ class Session(database: Database) extends Logging { def executeSelect[A](select: Select[_, _])(extractor: ResultSet => A): A = withConnection { connection => val (preprocessedSelect, sql, argumentLists) = database.statementBuilder(select) - val startTime = new DateTime + val startTime = LocalDateTime.now try { val preparedStatement = prepareStatement(connection, preprocessedSelect, sql, argumentLists) try { @@ -150,8 +150,8 @@ class Session(database: Database) extends Logging { val resultSet = preparedStatement.executeQuery try { val result = extractor(resultSet) - val endTime = new DateTime - logger.info(s"Ran sql in ${endTime.getMillis - startTime.getMillis}ms: ${logDetails(connection, sql, argumentLists)} with queryTimeout ${database.queryTimeout}") + val endTime = LocalDateTime.now + logger.info(s"Ran sql in ${(endTime.getNano - startTime.getNano) / 100000}ms: ${logDetails(connection, sql, argumentLists)} with queryTimeout ${database.queryTimeout}") result } finally { try { @@ -213,8 +213,8 @@ class Session(database: Database) extends Logging { case BigDecimalColumnType => statement.setBigDecimal(index, value.asInstanceOf[BigDecimal].bigDecimal) case StringColumnType => statement.setString(index, value.asInstanceOf[String]) case ByteArrayColumnType => statement.setBytes(index, value.asInstanceOf[Array[Byte]]) - case DateTimeColumnType => statement.setTimestamp(index, new JdbcTimestamp(value.asInstanceOf[DateTime].getMillis)) - case LocalDateColumnType => statement.setDate(index, new JdbcDate(value.asInstanceOf[LocalDate].toDate.getTime)) + case DateTimeColumnType => statement.setTimestamp(index, new JdbcTimestamp(value.asInstanceOf[LocalDateTime].getNano / 100000)) + case LocalDateColumnType => statement.setDate(index, new JdbcDate(value.asInstanceOf[LocalDate].atStartOfDay.getNano / 100000)) case mappedType: MappedColumnType[A, _] => setArgument(statement, index, mappedType.baseColumnType, mappedType.write(value.asInstanceOf[A])) case optionType: OptionColumnType[_, _] => value.asInstanceOf[Option[_]] match { case None if optionType.hasNullNullValue => @@ -331,15 +331,15 @@ case class Transaction(database: Database) extends Session(database) { def executeCommand(command: Command): Int = withConnection { connection => val (preprocessedCommand, sql, argumentLists) = database.statementBuilder(command) - val startTime = new DateTime + val startTime = LocalDateTime.now try { val preparedStatement = prepareStatement(connection, preprocessedCommand, sql, argumentLists) try { preparedStatement.setQueryTimeout(database.commandTimeout) val result = preparedStatement.executeBatch.sum - val endTime = new DateTime - logger.info(s"Ran sql in ${endTime.getMillis - startTime.getMillis}ms: ${logDetails(connection, sql, argumentLists)}") + val endTime = LocalDateTime.now + logger.info(s"Ran sql in ${(endTime.getNano - startTime.getNano) / 100000}ms: ${logDetails(connection, sql, argumentLists)}") result } finally { try { @@ -358,7 +358,7 @@ case class Transaction(database: Database) extends Session(database) { def executeInsertReturningKeys[T](command: Insert)(implicit columnType: ColumnType[T]): List[T] = withConnection { connection => val (preprocessedCommand, sql, argumentLists) = database.statementBuilder(command) - val startTime = new DateTime + val startTime = LocalDateTime.now try { val preparedStatement = prepareStatement( connection, @@ -372,8 +372,8 @@ case class Transaction(database: Database) extends Session(database) { val result = preparedStatement.executeUpdate val rs = preparedStatement.getGeneratedKeys val keys = IndexedExtractor[T](1).extractAll(ResultSetIterable(rs)) - val endTime = new DateTime - logger.info(s"Ran sql in ${endTime.getMillis - startTime.getMillis}ms: ${logDetails(connection, sql, argumentLists)}") + val endTime = LocalDateTime.now + logger.info(s"Ran sql in ${(endTime.getNano - startTime.getNano) / 100000}ms: ${logDetails(connection, sql, argumentLists)}") keys } finally { try { diff --git a/sqlest/src/main/scala/sqlest/extractor/IndexedExtractor.scala b/sqlest/src/main/scala/sqlest/extractor/IndexedExtractor.scala index 6a13d56..522740d 100644 --- a/sqlest/src/main/scala/sqlest/extractor/IndexedExtractor.scala +++ b/sqlest/src/main/scala/sqlest/extractor/IndexedExtractor.scala @@ -2,7 +2,7 @@ package sqlest.extractor import sqlest.ast._ import java.sql.ResultSet -import org.joda.time.{ DateTime, LocalDate } +import java.time.{ LocalDateTime, LocalDate } /** * An extractor that has an index associated with it. @@ -31,8 +31,8 @@ case class IndexedExtractor[A](index: Int)(implicit val columnType: ColumnType[A case BigDecimalColumnType => Option(resultSet.getBigDecimal(index)).map(BigDecimal.apply) case BooleanColumnType => checkNull(resultSet.getBoolean(index)) case StringColumnType => checkNull(resultSet.getString(index)) - case DateTimeColumnType => checkNull(new DateTime(resultSet.getTimestamp(index))) - case LocalDateColumnType => checkNull(new LocalDate(resultSet.getDate(index))) + case DateTimeColumnType => checkNull(resultSet.getTimestamp(index).toLocalDateTime) + case LocalDateColumnType => checkNull(resultSet.getDate(index).toLocalDate) case ByteArrayColumnType => checkNull(resultSet.getBytes(index)) } } diff --git a/sqlest/src/main/scala/sqlest/util/Iso8601.scala b/sqlest/src/main/scala/sqlest/util/Iso8601.scala index 5fcf602..4294b32 100644 --- a/sqlest/src/main/scala/sqlest/util/Iso8601.scala +++ b/sqlest/src/main/scala/sqlest/util/Iso8601.scala @@ -16,30 +16,28 @@ package sqlest.util -import org.joda.time._ -import org.joda.time.format._ +import java.time._ +import java.time.format.DateTimeFormatter import scala.util.Try object Iso8601 { // We can read two formats: with and without milliseconds: - // yyyy-mm-ddThh:mm:ss.ssssZ - val msFormat = ISODateTimeFormat.dateTime() + val msFormat = DateTimeFormatter.ISO_LOCAL_DATE_TIME - // yyyy-mm-ddThh:mm:ssZ - val secsFormat = ISODateTimeFormat.dateTimeNoMillis() + val secsFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME // yyyy-MM-dd - val dateFormat = ISODateTimeFormat.date() + val dateFormat = DateTimeFormatter.ISO_LOCAL_DATE // We write in seconds format by default: val defaultFormat = msFormat - def unapply(str: String): Option[DateTime] = - Try(msFormat parseDateTime str).toOption orElse - Try(secsFormat parseDateTime str).toOption orElse - Try(dateFormat parseDateTime str).toOption + def unapply(str: String): Option[LocalDateTime] = + Try(LocalDateTime parse (str, msFormat)).toOption orElse + Try(LocalDateTime parse (str, secsFormat)).toOption orElse + Try((LocalDate parse (str, dateFormat)).atStartOfDay).toOption - def apply(date: DateTime) = - defaultFormat.print(date withZone DateTimeZone.UTC) + def apply(date: LocalDateTime) = + defaultFormat.format(date atZone ZoneId.of("UTC")) } diff --git a/sqlest/src/test/scala/sqlest/TestData.scala b/sqlest/src/test/scala/sqlest/TestData.scala index 04eedc9..494458b 100644 --- a/sqlest/src/test/scala/sqlest/TestData.scala +++ b/sqlest/src/test/scala/sqlest/TestData.scala @@ -17,7 +17,7 @@ package sqlest import java.sql.ResultSet -import org.joda.time.{ DateTime, LocalDate } +import java.time.{ LocalDateTime, LocalDate } import sqlest.extractor.TestResultSet import sqlest.executor.ResultSetIterable import sqlest.extractor.AbstractResultSet @@ -57,7 +57,7 @@ object TestData { val bigDecimalCol = column[BigDecimal]("bigDecimalCol") val booleanColumn = column[Boolean]("booleanColumn") val stringColumn = column[String]("stringColumn") - val dateTimeCol = column[DateTime]("dateTimeCol") + val dateTimeCol = column[LocalDateTime]("dateTimeCol") val localDateCol = column[LocalDate]("localDateCol") val byteArrayCol = column[Array[Byte]]("byteArrayCol") @@ -74,7 +74,7 @@ object TestData { val zeroIsNoneWrappedInt = column[Option[WrappedInt]]("zeroIsNoneWrappedInt")(ZeroIsNoneColumnType[WrappedInt, Int]) val zeroIsNoneLocalDate = column[Option[LocalDate]]("zeroIsNoneDateTime")(ZeroIsNoneColumnType(YyyyMmDdColumnType)) val localDateFromDateTime = column[LocalDate]("localDateFromDateTime")(LocalDateFromDateTimeColumnType) - val dateTimeFromLocalDate = column[DateTime]("dateTimeFromLocalDate")(DateTimeFromLocalDateColumnType) + val dateTimeFromLocalDate = column[LocalDateTime]("dateTimeFromLocalDate")(DateTimeFromLocalDateColumnType) def columns = List(trimmedString, zeroIsNoneWrappedInt, zeroIsNoneLocalDate, localDateFromDateTime, dateTimeFromLocalDate) } object TableSix extends TableSix(None) diff --git a/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala b/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala index 9967925..f4b42fd 100644 --- a/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala @@ -16,7 +16,7 @@ package sqlest.ast -import org.joda.time.LocalDate +import java.time.LocalDate import org.scalatest.flatspec._ import org.scalatest.matchers.should._ @@ -105,10 +105,10 @@ class MappedColumnTypeSpec extends AnyFlatSpec with Matchers with MappedColumnTy } "YyyyMmDdColumnType" should "convert integers to date times" in { - YyyyMmDdColumnType.write(new LocalDate(1999, 12, 31)) should be(19991231) - YyyyMmDdColumnType.write(new LocalDate(2000, 1, 1)) should be(20000101) - YyyyMmDdColumnType.read(Some(19991231)) should be(Some(new LocalDate(1999, 12, 31))) - YyyyMmDdColumnType.read(Some(20000101)) should be(Some(new LocalDate(2000, 1, 1))) + YyyyMmDdColumnType.write(LocalDate.of(1999, 12, 31)) should be(19991231) + YyyyMmDdColumnType.write(LocalDate.of(2000, 1, 1)) should be(20000101) + YyyyMmDdColumnType.read(Some(19991231)) should be(Some(LocalDate.of(1999, 12, 31))) + YyyyMmDdColumnType.read(Some(20000101)) should be(Some(LocalDate.of(2000, 1, 1))) } "MappedColumnType.compose" should "compose read and write operations" in { @@ -127,8 +127,8 @@ class MappedColumnTypeSpec extends AnyFlatSpec with Matchers with MappedColumnTy val chainedComposedMappedColumn = YyyyMmDdColumnType.compose( MappedBooleanColumnType( - new LocalDate(1999, 12, 31), - new LocalDate(2000, 1, 1) + LocalDate.of(1999, 12, 31), + LocalDate.of(2000, 1, 1) ).compose( MappedColumnType[Option[Int], Boolean]( db => if (db) Some(1) else None, diff --git a/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala b/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala index 2ca4771..32301b3 100644 --- a/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala +++ b/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala @@ -16,7 +16,7 @@ package sqlest.executor -import org.joda.time.LocalDate +import java.time.LocalDate import org.scalatest.flatspec._ import org.scalatest.matchers.should._ import scala.concurrent.{ Await, Future } @@ -57,7 +57,7 @@ class ExecutorSpec extends AnyFlatSpec with Matchers { val mappedOptionSelectStatement2 = { select(TableSix.zeroIsNoneLocalDate) .from(TableSix) - .where(TableSix.zeroIsNoneLocalDate === Some(new LocalDate(2015, 1, 1))) + .where(TableSix.zeroIsNoneLocalDate === Some(LocalDate.of(2015, 1, 1))) } val deleteStatement = delete.from(TableOne).where(TableOne.col2 === "12") diff --git a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala index 7a825ec..06a1cb7 100644 --- a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala +++ b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala @@ -16,7 +16,7 @@ package sqlest.extractor -import org.joda.time.{ DateTime, LocalDate } +import java.time.{ LocalDateTime, LocalDate } import org.scalatest.flatspec._ import org.scalatest.matchers.should._ import sqlest._ diff --git a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala index 5176136..fc2ff2d 100644 --- a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala +++ b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala @@ -16,7 +16,7 @@ package sqlest.extractor -import org.joda.time.{ DateTime, LocalDate } +import java.time.{ LocalDateTime, LocalDate } import org.scalatest.flatspec._ import org.scalatest.matchers.should._ import sqlest._ @@ -48,8 +48,8 @@ class ColumnExtractorSpec extends AnyFlatSpec with Matchers { TableFive.bigDecimalCol.extractHeadOption(results) should be(Some(BigDecimal(2.818))) TableFive.booleanColumn.extractHeadOption(results) should be(Some(true)) TableFive.stringColumn.extractHeadOption(results) should be(Some("Hello mars")) - TableFive.dateTimeCol.extractHeadOption(results) should be(Some(new DateTime(timestamp))) - TableFive.localDateCol.extractHeadOption(results) should be(Some(new LocalDate(date))) + TableFive.dateTimeCol.extractHeadOption(results) should be(Some(timestamp.toLocalDateTime)) + TableFive.localDateCol.extractHeadOption(results) should be(Some(date.toLocalDate)) TableFive.byteArrayCol.extractHeadOption(results).map(_.toList) should be(Some(Array[Byte](1, 127).toList)) } @@ -73,13 +73,13 @@ class ColumnExtractorSpec extends AnyFlatSpec with Matchers { ) extractor.extractHeadOption(testResultSet) should equal(Some( - (Some(WrappedString("test")), Some(WrappedInt(5)), Some(new LocalDate(2015, 1, 1)), new LocalDate(date), new DateTime(date).withTimeAtStartOfDay) + (Some(WrappedString("test")), Some(WrappedInt(5)), Some(LocalDate.of(2015, 1, 1)), date.toLocalDate, date.toLocalDate.atStartOfDay) )) extractor.extractAll(testResultSet) should equal(List( - (Some(WrappedString("test")), Some(WrappedInt(5)), Some(new LocalDate(2015, 1, 1)), new LocalDate(date), new DateTime(date).withTimeAtStartOfDay), - (Some(WrappedString(" test")), None, Some(new LocalDate(2100, 1, 1)), new LocalDate(date), new DateTime(date).withTimeAtStartOfDay), - (None, None, None, new LocalDate(date), new DateTime(date).withTimeAtStartOfDay) + (Some(WrappedString("test")), Some(WrappedInt(5)), Some(LocalDate.of(2015, 1, 1)), date.toLocalDate, date.toLocalDate.atStartOfDay), + (Some(WrappedString(" test")), None, Some(LocalDate.of(2100, 1, 1)), date.toLocalDate, date.toLocalDate.atStartOfDay), + (None, None, None, date.toLocalDate, date.toLocalDate.atStartOfDay) )) } diff --git a/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala b/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala index 64fbb91..c8f9b08 100644 --- a/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala @@ -16,7 +16,7 @@ package sqlest.sql -import org.joda.time.LocalDate +import java.time.LocalDate import org.scalatest.flatspec._ import org.scalatest.matchers.should._ import sqlest._ diff --git a/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala b/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala index 7ec99f2..2862768 100644 --- a/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala +++ b/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala @@ -16,7 +16,7 @@ package sqlest.untyped.ast -import org.joda.time._ +import java.time._ import org.scalatest.flatspec._ import org.scalatest.matchers.should._ import sqlest._ @@ -30,7 +30,7 @@ class ColumnSpec extends AnyFlatSpec with Matchers { val bigDecimalCol = column[BigDecimal]("Col") val booleanCol = column[Boolean]("Col") val stringCol = column[String]("Col") - val dateTimeCol = column[DateTime]("Col") + val dateTimeCol = column[LocalDateTime]("Col") val mappedCol = column[Int]("Col")(MappedColumnType[Int, String](_.toInt, _.toString)) } @@ -43,7 +43,9 @@ class ColumnSpec extends AnyFlatSpec with Matchers { (TableOne.bigDecimalCol untypedEq "1") should equal(Some(TableOne.bigDecimalCol === 1)) (TableOne.booleanCol untypedEq "true") should equal(Some(TableOne.booleanCol === true)) (TableOne.stringCol untypedEq "abc") should equal(Some(TableOne.stringCol === "abc")) - (TableOne.dateTimeCol untypedEq "2014-01-01T09:00:00.000Z") should equal(Some(TableOne.dateTimeCol === new DateTime(2014, 1, 1, 9, 0, 0, 0))) + (TableOne.dateTimeCol untypedEq "2014-01-01T09:00:00.000Z") should equal(Some(TableOne.dateTimeCol === LocalDateTime.of(2014, 1, 1, 9, 0, 0, 0))) + (TableOne.dateTimeCol untypedEq "2015-01-01T09:00:00Z") should equal(Some(TableOne.dateTimeCol === LocalDateTime.of(2015, 1, 1, 9, 0, 0, 0))) + (TableOne.dateTimeCol untypedEq "2016-01-01T09:00:00") should equal(Some(TableOne.dateTimeCol === LocalDateTime.of(2016, 1, 1, 9, 0, 0, 0))) // TODO // (TableOne.mappedCol untypedEq "2") should equal(Some(TableOne.mappedCol === 2)) } From 2cdc4bb84d88216783685c841e65c7b9c5846084 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Tue, 21 Oct 2025 08:59:46 +0100 Subject: [PATCH 09/22] And remove joda dependencies --- build.sbt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build.sbt b/build.sbt index 9b31469..7e6cf6d 100644 --- a/build.sbt +++ b/build.sbt @@ -25,9 +25,7 @@ lazy val extractors = (project in file("extractors")) mdocIn := file("docs") / "extractors", mdocOut := file("extractors"), libraryDependencies ++= Seq( - "org.scala-lang" % "scala-reflect" % scalaVersion.value, - "joda-time" % "joda-time" % "2.14.0", - "org.joda" % "joda-convert" % "3.0.1" + "org.scala-lang" % "scala-reflect" % scalaVersion.value ) ) From 8079fa0095987d1bfd6d30bce7cb55d8e74e4dd6 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Tue, 11 Nov 2025 13:51:31 +0000 Subject: [PATCH 10/22] Remove cross version --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 7e6cf6d..919f82a 100644 --- a/build.sbt +++ b/build.sbt @@ -38,7 +38,7 @@ lazy val examples = (project in file("examples")) lazy val commonSettings = publishingSettings ++ Seq( organization := "uk.co.jhc", scalaVersion := "2.13.16", - crossScalaVersions := List("2.12.15", "2.13.16"), + crossScalaVersions := List("2.13.16"), scalacOptions ++= Seq( "-deprecation", "-encoding", "UTF-8", From 4f9e45369c4a1e10389c3775b3053c12d8bd48c9 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Tue, 11 Nov 2025 13:54:04 +0000 Subject: [PATCH 11/22] Setting version to 0.9.4 --- version.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sbt b/version.sbt index b0b9d99..95ed248 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.9.4-SNAPSHOT" +ThisBuild / version := "0.9.4" From 8652294e311e111cf9fc5477374eb5a37943a575 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Tue, 11 Nov 2025 13:55:23 +0000 Subject: [PATCH 12/22] Setting version to 0.9.5-SNAPSHOT --- version.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sbt b/version.sbt index 95ed248..3146b55 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.9.4" +ThisBuild / version := "0.9.5-SNAPSHOT" From 537a5c3c0ce20e266dcbd1d7d64df99118417910 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Thu, 13 Nov 2025 12:28:20 +0000 Subject: [PATCH 13/22] Fix npe on date and time columns --- sqlest/src/main/scala/sqlest/ast/Column.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sqlest/src/main/scala/sqlest/ast/Column.scala b/sqlest/src/main/scala/sqlest/ast/Column.scala index 913fc53..771bde5 100644 --- a/sqlest/src/main/scala/sqlest/ast/Column.scala +++ b/sqlest/src/main/scala/sqlest/ast/Column.scala @@ -16,10 +16,10 @@ package sqlest.ast -import java.sql.ResultSet -import java.time.{LocalDateTime, LocalDate} import sqlest.extractor.CellExtractor +import java.sql.ResultSet + /** * A column, column literal, or column expression. * @@ -111,8 +111,8 @@ sealed trait AliasedColumn[A] extends Column[A] with CellExtractor[ResultSet, A] case BigDecimalColumnType => Option(resultSet.getBigDecimal(columnAlias)).map(BigDecimal.apply) case BooleanColumnType => checkNull(resultSet.getBoolean(columnAlias)) case StringColumnType => checkNull(resultSet.getString(columnAlias)) - case DateTimeColumnType => checkNull(resultSet.getTimestamp(columnAlias).toLocalDateTime) - case LocalDateColumnType => checkNull(resultSet.getDate(columnAlias).toLocalDate) + case DateTimeColumnType => Option(resultSet.getTimestamp(columnAlias)).map(t => t.toLocalDateTime) + case LocalDateColumnType => Option(resultSet.getDate(columnAlias)).map(d => d.toLocalDate) case ByteArrayColumnType => checkNull(resultSet.getBytes(columnAlias)) } } From 62230446d3d8ab384fb78519f484c7c104fbb592 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Thu, 13 Nov 2025 12:30:22 +0000 Subject: [PATCH 14/22] Setting version to 0.9.5 --- version.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sbt b/version.sbt index 3146b55..3fbc1dd 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.9.5-SNAPSHOT" +ThisBuild / version := "0.9.5" From cbf49c7c9e9e7e16ad37ed25934b6023386bdc78 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Thu, 13 Nov 2025 12:35:39 +0000 Subject: [PATCH 15/22] Revert "Setting version to 0.9.5" This reverts commit 62230446d3d8ab384fb78519f484c7c104fbb592. --- version.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sbt b/version.sbt index 3fbc1dd..3146b55 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.9.5" +ThisBuild / version := "0.9.5-SNAPSHOT" From f50c35ab9a6d534a78e742a3a84e50a94d078ceb Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Thu, 13 Nov 2025 12:37:08 +0000 Subject: [PATCH 16/22] Setting version to 0.9.5 --- version.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sbt b/version.sbt index 3146b55..3fbc1dd 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.9.5-SNAPSHOT" +ThisBuild / version := "0.9.5" From 4f2949431475840eb9366c0ab37a5272d8e454c1 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Thu, 13 Nov 2025 12:38:33 +0000 Subject: [PATCH 17/22] Setting version to 0.9.6-SNAPSHOT --- version.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sbt b/version.sbt index 3fbc1dd..e3f6f70 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.9.5" +ThisBuild / version := "0.9.6-SNAPSHOT" From c941a88f94de9055591c8561cce03d80c20252a3 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Fri, 14 Nov 2025 10:55:30 +0000 Subject: [PATCH 18/22] Make sure date and time patterns are consistent (will modify application services next) --- sqlest/src/main/scala/sqlest/util/Iso8601.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlest/src/main/scala/sqlest/util/Iso8601.scala b/sqlest/src/main/scala/sqlest/util/Iso8601.scala index 4294b32..5d67c6b 100644 --- a/sqlest/src/main/scala/sqlest/util/Iso8601.scala +++ b/sqlest/src/main/scala/sqlest/util/Iso8601.scala @@ -23,12 +23,12 @@ import scala.util.Try object Iso8601 { // We can read two formats: with and without milliseconds: - val msFormat = DateTimeFormatter.ISO_LOCAL_DATE_TIME + val msFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[VV]") - val secsFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME + val secsFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[VV]") // yyyy-MM-dd - val dateFormat = DateTimeFormatter.ISO_LOCAL_DATE + val dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd") // We write in seconds format by default: val defaultFormat = msFormat From 518cc58911d71c18ad6f5adf3dd641c931bd7958 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Fri, 14 Nov 2025 10:59:00 +0000 Subject: [PATCH 19/22] Setting version to 0.9.6 --- version.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sbt b/version.sbt index e3f6f70..6d388e9 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.9.6-SNAPSHOT" +ThisBuild / version := "0.9.6" From 4f606fc367d87184ae967e3d00942a5670a9fd37 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Fri, 14 Nov 2025 10:59:59 +0000 Subject: [PATCH 20/22] Setting version to 0.9.7-SNAPSHOT --- version.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sbt b/version.sbt index 6d388e9..b28c56d 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.9.6" +ThisBuild / version := "0.9.7-SNAPSHOT" From 9b8670e320e93c6ea1c15fc05feac3205e96821f Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Tue, 18 Nov 2025 16:29:37 +0000 Subject: [PATCH 21/22] Setting version to 0.9.7 --- build.sbt | 4 +++- .../scala/sqlest/extractor/Extractor.scala | 1 + sqlest/src/main/scala/sqlest/ast/Column.scala | 8 +++---- .../main/scala/sqlest/ast/ColumnType.scala | 4 ++-- .../scala/sqlest/ast/MappedColumnTypes.scala | 18 +++++++------- .../ast/syntax/UntypedColumnSyntax.scala | 4 ++-- .../main/scala/sqlest/executor/Database.scala | 24 +++++++++---------- .../sqlest/extractor/IndexedExtractor.scala | 6 ++--- .../src/main/scala/sqlest/util/Iso8601.scala | 24 ++++++++++--------- sqlest/src/test/scala/sqlest/TestData.scala | 6 ++--- .../sqlest/ast/MappedColumnTypesSpec.scala | 14 +++++------ .../scala/sqlest/executor/ExecutorSpec.scala | 4 ++-- .../ColumnExtractorSettersSpec.scala | 2 +- .../extractor/ColumnExtractorSpec.scala | 14 +++++------ .../sql/SelectStatementBuilderSpec.scala | 2 +- .../scala/sqlest/untyped/ast/ColumnSpec.scala | 8 +++---- version.sbt | 2 +- 17 files changed, 74 insertions(+), 71 deletions(-) diff --git a/build.sbt b/build.sbt index 919f82a..c44ed37 100644 --- a/build.sbt +++ b/build.sbt @@ -25,7 +25,9 @@ lazy val extractors = (project in file("extractors")) mdocIn := file("docs") / "extractors", mdocOut := file("extractors"), libraryDependencies ++= Seq( - "org.scala-lang" % "scala-reflect" % scalaVersion.value + "org.scala-lang" % "scala-reflect" % scalaVersion.value, + "joda-time" % "joda-time" % "2.14.0", + "org.joda" % "joda-convert" % "3.0.1" ) ) diff --git a/extractors/src/main/scala/sqlest/extractor/Extractor.scala b/extractors/src/main/scala/sqlest/extractor/Extractor.scala index a651303..f96589e 100644 --- a/extractors/src/main/scala/sqlest/extractor/Extractor.scala +++ b/extractors/src/main/scala/sqlest/extractor/Extractor.scala @@ -16,6 +16,7 @@ package sqlest.extractor +import org.joda.time.DateTime import scala.collection.immutable.{ Queue, ListMap } sealed trait Extractor[Row, A] extends ChoiceExtractorSyntax[Row, A] { diff --git a/sqlest/src/main/scala/sqlest/ast/Column.scala b/sqlest/src/main/scala/sqlest/ast/Column.scala index 771bde5..14594c7 100644 --- a/sqlest/src/main/scala/sqlest/ast/Column.scala +++ b/sqlest/src/main/scala/sqlest/ast/Column.scala @@ -16,9 +16,9 @@ package sqlest.ast -import sqlest.extractor.CellExtractor - import java.sql.ResultSet +import org.joda.time.{ DateTime, LocalDate } +import sqlest.extractor.CellExtractor /** * A column, column literal, or column expression. @@ -111,8 +111,8 @@ sealed trait AliasedColumn[A] extends Column[A] with CellExtractor[ResultSet, A] case BigDecimalColumnType => Option(resultSet.getBigDecimal(columnAlias)).map(BigDecimal.apply) case BooleanColumnType => checkNull(resultSet.getBoolean(columnAlias)) case StringColumnType => checkNull(resultSet.getString(columnAlias)) - case DateTimeColumnType => Option(resultSet.getTimestamp(columnAlias)).map(t => t.toLocalDateTime) - case LocalDateColumnType => Option(resultSet.getDate(columnAlias)).map(d => d.toLocalDate) + case DateTimeColumnType => checkNull(new DateTime(resultSet.getTimestamp(columnAlias))) + case LocalDateColumnType => checkNull(new LocalDate(resultSet.getDate(columnAlias))) case ByteArrayColumnType => checkNull(resultSet.getBytes(columnAlias)) } } diff --git a/sqlest/src/main/scala/sqlest/ast/ColumnType.scala b/sqlest/src/main/scala/sqlest/ast/ColumnType.scala index 7376ef3..6143e82 100644 --- a/sqlest/src/main/scala/sqlest/ast/ColumnType.scala +++ b/sqlest/src/main/scala/sqlest/ast/ColumnType.scala @@ -16,7 +16,7 @@ package sqlest.ast -import java.time.{ LocalDateTime, LocalDate } +import org.joda.time.{ DateTime, LocalDate } import scala.language.experimental.macros import scala.reflect.macros.whitebox.Context @@ -50,7 +50,7 @@ case object BigDecimalColumnType extends NumericColumnType[BigDecimal] case object BooleanColumnType extends NonNumericColumnType[Boolean] case object StringColumnType extends NonNumericColumnType[String] -case object DateTimeColumnType extends NonNumericColumnType[LocalDateTime] +case object DateTimeColumnType extends NonNumericColumnType[DateTime] case object LocalDateColumnType extends NonNumericColumnType[LocalDate] case object ByteArrayColumnType extends NonNumericColumnType[Array[Byte]] diff --git a/sqlest/src/main/scala/sqlest/ast/MappedColumnTypes.scala b/sqlest/src/main/scala/sqlest/ast/MappedColumnTypes.scala index 7d3b1de..f02c8c0 100644 --- a/sqlest/src/main/scala/sqlest/ast/MappedColumnTypes.scala +++ b/sqlest/src/main/scala/sqlest/ast/MappedColumnTypes.scala @@ -16,7 +16,7 @@ package sqlest.ast -import java.time.{ LocalDateTime, LocalDate } +import org.joda.time.{ DateTime, LocalDate } /** Standard set of MappedColumnTypes for various column types: */ trait MappedColumnTypes @@ -145,23 +145,23 @@ trait LocalDateMappedColumnTypes { val month = (database % 10000) / 100 val day = database % 100 - LocalDate.of(year, month, day) + new LocalDate(year, month, day) } def mappedWrite(value: LocalDate) = - value.getYear * 10000 + value.getMonthValue * 100 + value.getDayOfMonth + value.getYear * 10000 + value.getMonthOfYear * 100 + value.getDayOfMonth } - case object LocalDateFromDateTimeColumnType extends MappedColumnType[LocalDate, LocalDateTime] { + case object LocalDateFromDateTimeColumnType extends MappedColumnType[LocalDate, DateTime] { val baseColumnType = DateTimeColumnType - def mappedRead(database: LocalDateTime) = database.toLocalDate - def mappedWrite(value: LocalDate) = value.atStartOfDay + def mappedRead(database: DateTime) = database.toLocalDate + def mappedWrite(value: LocalDate) = value.toDateTimeAtStartOfDay } - case object DateTimeFromLocalDateColumnType extends MappedColumnType[LocalDateTime, LocalDate] { + case object DateTimeFromLocalDateColumnType extends MappedColumnType[DateTime, LocalDate] { val baseColumnType = LocalDateColumnType - def mappedRead(database: LocalDate) = database.atStartOfDay - def mappedWrite(value: LocalDateTime) = value.toLocalDate + def mappedRead(database: LocalDate) = database.toDateTimeAtStartOfDay + def mappedWrite(value: DateTime) = value.toLocalDate } } diff --git a/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala b/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala index 62e67e8..95205d0 100644 --- a/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala +++ b/sqlest/src/main/scala/sqlest/ast/syntax/UntypedColumnSyntax.scala @@ -16,7 +16,7 @@ package sqlest.ast.syntax -import java.time.{ LocalDateTime, LocalDate } +import org.joda.time.{ DateTime, LocalDate } import scala.reflect.runtime.{ universe => ru } import scala.util.Try import sqlest.ast._ @@ -35,7 +35,7 @@ class UntypedColumnHelpers extends ColumnSyntax { } def bigDecimalArgument(arg: String) = Try(BigDecimal(arg)).toOption def dateTimeArgument(arg: String) = Iso8601.unapply(arg) - def localDateArgument(arg: String) = Try(Iso8601.unapply(arg).get.toLocalDate).toOption + def localDateArgument(arg: String) = Iso8601.unapply(arg).map(new LocalDate(_)) 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") diff --git a/sqlest/src/main/scala/sqlest/executor/Database.scala b/sqlest/src/main/scala/sqlest/executor/Database.scala index 9cb2e5a..46f01aa 100644 --- a/sqlest/src/main/scala/sqlest/executor/Database.scala +++ b/sqlest/src/main/scala/sqlest/executor/Database.scala @@ -23,7 +23,7 @@ import sqlest.util.Logging import java.sql.{ Connection, Date => JdbcDate, DriverManager, ResultSet, PreparedStatement, Statement, SQLException, Timestamp => JdbcTimestamp, Types => JdbcTypes } import javax.sql.DataSource -import java.time.{ LocalDateTime, LocalDate } +import org.joda.time.{ DateTime, LocalDate } import scala.concurrent.{ ExecutionContext, Future } import scala.util.{ DynamicVariable, Try, Success, Failure } import scala.util.control.NonFatal @@ -142,7 +142,7 @@ class Session(database: Database) extends Logging { def executeSelect[A](select: Select[_, _])(extractor: ResultSet => A): A = withConnection { connection => val (preprocessedSelect, sql, argumentLists) = database.statementBuilder(select) - val startTime = LocalDateTime.now + val startTime = new DateTime try { val preparedStatement = prepareStatement(connection, preprocessedSelect, sql, argumentLists) try { @@ -150,8 +150,8 @@ class Session(database: Database) extends Logging { val resultSet = preparedStatement.executeQuery try { val result = extractor(resultSet) - val endTime = LocalDateTime.now - logger.info(s"Ran sql in ${(endTime.getNano - startTime.getNano) / 100000}ms: ${logDetails(connection, sql, argumentLists)} with queryTimeout ${database.queryTimeout}") + val endTime = new DateTime + logger.info(s"Ran sql in ${endTime.getMillis - startTime.getMillis}ms: ${logDetails(connection, sql, argumentLists)} with queryTimeout ${database.queryTimeout}") result } finally { try { @@ -213,8 +213,8 @@ class Session(database: Database) extends Logging { case BigDecimalColumnType => statement.setBigDecimal(index, value.asInstanceOf[BigDecimal].bigDecimal) case StringColumnType => statement.setString(index, value.asInstanceOf[String]) case ByteArrayColumnType => statement.setBytes(index, value.asInstanceOf[Array[Byte]]) - case DateTimeColumnType => statement.setTimestamp(index, new JdbcTimestamp(value.asInstanceOf[LocalDateTime].getNano / 100000)) - case LocalDateColumnType => statement.setDate(index, new JdbcDate(value.asInstanceOf[LocalDate].atStartOfDay.getNano / 100000)) + case DateTimeColumnType => statement.setTimestamp(index, new JdbcTimestamp(value.asInstanceOf[DateTime].getMillis)) + case LocalDateColumnType => statement.setDate(index, new JdbcDate(value.asInstanceOf[LocalDate].toDate.getTime)) case mappedType: MappedColumnType[A, _] => setArgument(statement, index, mappedType.baseColumnType, mappedType.write(value.asInstanceOf[A])) case optionType: OptionColumnType[_, _] => value.asInstanceOf[Option[_]] match { case None if optionType.hasNullNullValue => @@ -331,15 +331,15 @@ case class Transaction(database: Database) extends Session(database) { def executeCommand(command: Command): Int = withConnection { connection => val (preprocessedCommand, sql, argumentLists) = database.statementBuilder(command) - val startTime = LocalDateTime.now + val startTime = new DateTime try { val preparedStatement = prepareStatement(connection, preprocessedCommand, sql, argumentLists) try { preparedStatement.setQueryTimeout(database.commandTimeout) val result = preparedStatement.executeBatch.sum - val endTime = LocalDateTime.now - logger.info(s"Ran sql in ${(endTime.getNano - startTime.getNano) / 100000}ms: ${logDetails(connection, sql, argumentLists)}") + val endTime = new DateTime + logger.info(s"Ran sql in ${endTime.getMillis - startTime.getMillis}ms: ${logDetails(connection, sql, argumentLists)}") result } finally { try { @@ -358,7 +358,7 @@ case class Transaction(database: Database) extends Session(database) { def executeInsertReturningKeys[T](command: Insert)(implicit columnType: ColumnType[T]): List[T] = withConnection { connection => val (preprocessedCommand, sql, argumentLists) = database.statementBuilder(command) - val startTime = LocalDateTime.now + val startTime = new DateTime try { val preparedStatement = prepareStatement( connection, @@ -372,8 +372,8 @@ case class Transaction(database: Database) extends Session(database) { val result = preparedStatement.executeUpdate val rs = preparedStatement.getGeneratedKeys val keys = IndexedExtractor[T](1).extractAll(ResultSetIterable(rs)) - val endTime = LocalDateTime.now - logger.info(s"Ran sql in ${(endTime.getNano - startTime.getNano) / 100000}ms: ${logDetails(connection, sql, argumentLists)}") + val endTime = new DateTime + logger.info(s"Ran sql in ${endTime.getMillis - startTime.getMillis}ms: ${logDetails(connection, sql, argumentLists)}") keys } finally { try { diff --git a/sqlest/src/main/scala/sqlest/extractor/IndexedExtractor.scala b/sqlest/src/main/scala/sqlest/extractor/IndexedExtractor.scala index 522740d..6a13d56 100644 --- a/sqlest/src/main/scala/sqlest/extractor/IndexedExtractor.scala +++ b/sqlest/src/main/scala/sqlest/extractor/IndexedExtractor.scala @@ -2,7 +2,7 @@ package sqlest.extractor import sqlest.ast._ import java.sql.ResultSet -import java.time.{ LocalDateTime, LocalDate } +import org.joda.time.{ DateTime, LocalDate } /** * An extractor that has an index associated with it. @@ -31,8 +31,8 @@ case class IndexedExtractor[A](index: Int)(implicit val columnType: ColumnType[A case BigDecimalColumnType => Option(resultSet.getBigDecimal(index)).map(BigDecimal.apply) case BooleanColumnType => checkNull(resultSet.getBoolean(index)) case StringColumnType => checkNull(resultSet.getString(index)) - case DateTimeColumnType => checkNull(resultSet.getTimestamp(index).toLocalDateTime) - case LocalDateColumnType => checkNull(resultSet.getDate(index).toLocalDate) + case DateTimeColumnType => checkNull(new DateTime(resultSet.getTimestamp(index))) + case LocalDateColumnType => checkNull(new LocalDate(resultSet.getDate(index))) case ByteArrayColumnType => checkNull(resultSet.getBytes(index)) } } diff --git a/sqlest/src/main/scala/sqlest/util/Iso8601.scala b/sqlest/src/main/scala/sqlest/util/Iso8601.scala index 5d67c6b..5fcf602 100644 --- a/sqlest/src/main/scala/sqlest/util/Iso8601.scala +++ b/sqlest/src/main/scala/sqlest/util/Iso8601.scala @@ -16,28 +16,30 @@ package sqlest.util -import java.time._ -import java.time.format.DateTimeFormatter +import org.joda.time._ +import org.joda.time.format._ import scala.util.Try object Iso8601 { // We can read two formats: with and without milliseconds: - val msFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[VV]") + // yyyy-mm-ddThh:mm:ss.ssssZ + val msFormat = ISODateTimeFormat.dateTime() - val secsFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[VV]") + // yyyy-mm-ddThh:mm:ssZ + val secsFormat = ISODateTimeFormat.dateTimeNoMillis() // yyyy-MM-dd - val dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd") + val dateFormat = ISODateTimeFormat.date() // We write in seconds format by default: val defaultFormat = msFormat - def unapply(str: String): Option[LocalDateTime] = - Try(LocalDateTime parse (str, msFormat)).toOption orElse - Try(LocalDateTime parse (str, secsFormat)).toOption orElse - Try((LocalDate parse (str, dateFormat)).atStartOfDay).toOption + def unapply(str: String): Option[DateTime] = + Try(msFormat parseDateTime str).toOption orElse + Try(secsFormat parseDateTime str).toOption orElse + Try(dateFormat parseDateTime str).toOption - def apply(date: LocalDateTime) = - defaultFormat.format(date atZone ZoneId.of("UTC")) + def apply(date: DateTime) = + defaultFormat.print(date withZone DateTimeZone.UTC) } diff --git a/sqlest/src/test/scala/sqlest/TestData.scala b/sqlest/src/test/scala/sqlest/TestData.scala index 494458b..04eedc9 100644 --- a/sqlest/src/test/scala/sqlest/TestData.scala +++ b/sqlest/src/test/scala/sqlest/TestData.scala @@ -17,7 +17,7 @@ package sqlest import java.sql.ResultSet -import java.time.{ LocalDateTime, LocalDate } +import org.joda.time.{ DateTime, LocalDate } import sqlest.extractor.TestResultSet import sqlest.executor.ResultSetIterable import sqlest.extractor.AbstractResultSet @@ -57,7 +57,7 @@ object TestData { val bigDecimalCol = column[BigDecimal]("bigDecimalCol") val booleanColumn = column[Boolean]("booleanColumn") val stringColumn = column[String]("stringColumn") - val dateTimeCol = column[LocalDateTime]("dateTimeCol") + val dateTimeCol = column[DateTime]("dateTimeCol") val localDateCol = column[LocalDate]("localDateCol") val byteArrayCol = column[Array[Byte]]("byteArrayCol") @@ -74,7 +74,7 @@ object TestData { val zeroIsNoneWrappedInt = column[Option[WrappedInt]]("zeroIsNoneWrappedInt")(ZeroIsNoneColumnType[WrappedInt, Int]) val zeroIsNoneLocalDate = column[Option[LocalDate]]("zeroIsNoneDateTime")(ZeroIsNoneColumnType(YyyyMmDdColumnType)) val localDateFromDateTime = column[LocalDate]("localDateFromDateTime")(LocalDateFromDateTimeColumnType) - val dateTimeFromLocalDate = column[LocalDateTime]("dateTimeFromLocalDate")(DateTimeFromLocalDateColumnType) + val dateTimeFromLocalDate = column[DateTime]("dateTimeFromLocalDate")(DateTimeFromLocalDateColumnType) def columns = List(trimmedString, zeroIsNoneWrappedInt, zeroIsNoneLocalDate, localDateFromDateTime, dateTimeFromLocalDate) } object TableSix extends TableSix(None) diff --git a/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala b/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala index f4b42fd..9967925 100644 --- a/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala +++ b/sqlest/src/test/scala/sqlest/ast/MappedColumnTypesSpec.scala @@ -16,7 +16,7 @@ package sqlest.ast -import java.time.LocalDate +import org.joda.time.LocalDate import org.scalatest.flatspec._ import org.scalatest.matchers.should._ @@ -105,10 +105,10 @@ class MappedColumnTypeSpec extends AnyFlatSpec with Matchers with MappedColumnTy } "YyyyMmDdColumnType" should "convert integers to date times" in { - YyyyMmDdColumnType.write(LocalDate.of(1999, 12, 31)) should be(19991231) - YyyyMmDdColumnType.write(LocalDate.of(2000, 1, 1)) should be(20000101) - YyyyMmDdColumnType.read(Some(19991231)) should be(Some(LocalDate.of(1999, 12, 31))) - YyyyMmDdColumnType.read(Some(20000101)) should be(Some(LocalDate.of(2000, 1, 1))) + YyyyMmDdColumnType.write(new LocalDate(1999, 12, 31)) should be(19991231) + YyyyMmDdColumnType.write(new LocalDate(2000, 1, 1)) should be(20000101) + YyyyMmDdColumnType.read(Some(19991231)) should be(Some(new LocalDate(1999, 12, 31))) + YyyyMmDdColumnType.read(Some(20000101)) should be(Some(new LocalDate(2000, 1, 1))) } "MappedColumnType.compose" should "compose read and write operations" in { @@ -127,8 +127,8 @@ class MappedColumnTypeSpec extends AnyFlatSpec with Matchers with MappedColumnTy val chainedComposedMappedColumn = YyyyMmDdColumnType.compose( MappedBooleanColumnType( - LocalDate.of(1999, 12, 31), - LocalDate.of(2000, 1, 1) + new LocalDate(1999, 12, 31), + new LocalDate(2000, 1, 1) ).compose( MappedColumnType[Option[Int], Boolean]( db => if (db) Some(1) else None, diff --git a/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala b/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala index 32301b3..2ca4771 100644 --- a/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala +++ b/sqlest/src/test/scala/sqlest/executor/ExecutorSpec.scala @@ -16,7 +16,7 @@ package sqlest.executor -import java.time.LocalDate +import org.joda.time.LocalDate import org.scalatest.flatspec._ import org.scalatest.matchers.should._ import scala.concurrent.{ Await, Future } @@ -57,7 +57,7 @@ class ExecutorSpec extends AnyFlatSpec with Matchers { val mappedOptionSelectStatement2 = { select(TableSix.zeroIsNoneLocalDate) .from(TableSix) - .where(TableSix.zeroIsNoneLocalDate === Some(LocalDate.of(2015, 1, 1))) + .where(TableSix.zeroIsNoneLocalDate === Some(new LocalDate(2015, 1, 1))) } val deleteStatement = delete.from(TableOne).where(TableOne.col2 === "12") diff --git a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala index 06a1cb7..7a825ec 100644 --- a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala +++ b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSettersSpec.scala @@ -16,7 +16,7 @@ package sqlest.extractor -import java.time.{ LocalDateTime, LocalDate } +import org.joda.time.{ DateTime, LocalDate } import org.scalatest.flatspec._ import org.scalatest.matchers.should._ import sqlest._ diff --git a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala index fc2ff2d..5176136 100644 --- a/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala +++ b/sqlest/src/test/scala/sqlest/extractor/ColumnExtractorSpec.scala @@ -16,7 +16,7 @@ package sqlest.extractor -import java.time.{ LocalDateTime, LocalDate } +import org.joda.time.{ DateTime, LocalDate } import org.scalatest.flatspec._ import org.scalatest.matchers.should._ import sqlest._ @@ -48,8 +48,8 @@ class ColumnExtractorSpec extends AnyFlatSpec with Matchers { TableFive.bigDecimalCol.extractHeadOption(results) should be(Some(BigDecimal(2.818))) TableFive.booleanColumn.extractHeadOption(results) should be(Some(true)) TableFive.stringColumn.extractHeadOption(results) should be(Some("Hello mars")) - TableFive.dateTimeCol.extractHeadOption(results) should be(Some(timestamp.toLocalDateTime)) - TableFive.localDateCol.extractHeadOption(results) should be(Some(date.toLocalDate)) + TableFive.dateTimeCol.extractHeadOption(results) should be(Some(new DateTime(timestamp))) + TableFive.localDateCol.extractHeadOption(results) should be(Some(new LocalDate(date))) TableFive.byteArrayCol.extractHeadOption(results).map(_.toList) should be(Some(Array[Byte](1, 127).toList)) } @@ -73,13 +73,13 @@ class ColumnExtractorSpec extends AnyFlatSpec with Matchers { ) extractor.extractHeadOption(testResultSet) should equal(Some( - (Some(WrappedString("test")), Some(WrappedInt(5)), Some(LocalDate.of(2015, 1, 1)), date.toLocalDate, date.toLocalDate.atStartOfDay) + (Some(WrappedString("test")), Some(WrappedInt(5)), Some(new LocalDate(2015, 1, 1)), new LocalDate(date), new DateTime(date).withTimeAtStartOfDay) )) extractor.extractAll(testResultSet) should equal(List( - (Some(WrappedString("test")), Some(WrappedInt(5)), Some(LocalDate.of(2015, 1, 1)), date.toLocalDate, date.toLocalDate.atStartOfDay), - (Some(WrappedString(" test")), None, Some(LocalDate.of(2100, 1, 1)), date.toLocalDate, date.toLocalDate.atStartOfDay), - (None, None, None, date.toLocalDate, date.toLocalDate.atStartOfDay) + (Some(WrappedString("test")), Some(WrappedInt(5)), Some(new LocalDate(2015, 1, 1)), new LocalDate(date), new DateTime(date).withTimeAtStartOfDay), + (Some(WrappedString(" test")), None, Some(new LocalDate(2100, 1, 1)), new LocalDate(date), new DateTime(date).withTimeAtStartOfDay), + (None, None, None, new LocalDate(date), new DateTime(date).withTimeAtStartOfDay) )) } diff --git a/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala b/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala index c8f9b08..64fbb91 100644 --- a/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala +++ b/sqlest/src/test/scala/sqlest/sql/SelectStatementBuilderSpec.scala @@ -16,7 +16,7 @@ package sqlest.sql -import java.time.LocalDate +import org.joda.time.LocalDate import org.scalatest.flatspec._ import org.scalatest.matchers.should._ import sqlest._ diff --git a/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala b/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala index 2862768..7ec99f2 100644 --- a/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala +++ b/sqlest/src/test/scala/sqlest/untyped/ast/ColumnSpec.scala @@ -16,7 +16,7 @@ package sqlest.untyped.ast -import java.time._ +import org.joda.time._ import org.scalatest.flatspec._ import org.scalatest.matchers.should._ import sqlest._ @@ -30,7 +30,7 @@ class ColumnSpec extends AnyFlatSpec with Matchers { val bigDecimalCol = column[BigDecimal]("Col") val booleanCol = column[Boolean]("Col") val stringCol = column[String]("Col") - val dateTimeCol = column[LocalDateTime]("Col") + val dateTimeCol = column[DateTime]("Col") val mappedCol = column[Int]("Col")(MappedColumnType[Int, String](_.toInt, _.toString)) } @@ -43,9 +43,7 @@ class ColumnSpec extends AnyFlatSpec with Matchers { (TableOne.bigDecimalCol untypedEq "1") should equal(Some(TableOne.bigDecimalCol === 1)) (TableOne.booleanCol untypedEq "true") should equal(Some(TableOne.booleanCol === true)) (TableOne.stringCol untypedEq "abc") should equal(Some(TableOne.stringCol === "abc")) - (TableOne.dateTimeCol untypedEq "2014-01-01T09:00:00.000Z") should equal(Some(TableOne.dateTimeCol === LocalDateTime.of(2014, 1, 1, 9, 0, 0, 0))) - (TableOne.dateTimeCol untypedEq "2015-01-01T09:00:00Z") should equal(Some(TableOne.dateTimeCol === LocalDateTime.of(2015, 1, 1, 9, 0, 0, 0))) - (TableOne.dateTimeCol untypedEq "2016-01-01T09:00:00") should equal(Some(TableOne.dateTimeCol === LocalDateTime.of(2016, 1, 1, 9, 0, 0, 0))) + (TableOne.dateTimeCol untypedEq "2014-01-01T09:00:00.000Z") should equal(Some(TableOne.dateTimeCol === new DateTime(2014, 1, 1, 9, 0, 0, 0))) // TODO // (TableOne.mappedCol untypedEq "2") should equal(Some(TableOne.mappedCol === 2)) } diff --git a/version.sbt b/version.sbt index b28c56d..1e2c4fe 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.9.7-SNAPSHOT" +ThisBuild / version := "0.9.7" From 4dd16d2b0855009ae3403210e0d91a2ab90e2d78 Mon Sep 17 00:00:00 2001 From: Graeme Oswald Date: Tue, 18 Nov 2025 16:30:40 +0000 Subject: [PATCH 22/22] Setting version to 0.9.8-SNAPSHOT --- version.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sbt b/version.sbt index 1e2c4fe..35e2fb4 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.9.7" +ThisBuild / version := "0.9.8-SNAPSHOT"