Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
44453e0
upgrade plugins and build tools
msillence Jul 24, 2025
5c6a5d3
scala upgrade - by copiolot
msillence Jul 24, 2025
5a81322
Checkpoint before the weekend - still lots of errors to fix
Oswald-Graeme Sep 26, 2025
d907d40
Checkpoint with some problematic tests commented out, just to see if …
Oswald-Graeme Sep 30, 2025
49c75d7
Update versions
Oswald-Graeme Oct 7, 2025
f0a6bc3
Update scalafmt and remove unused plugin
Oswald-Graeme Oct 13, 2025
df36e3a
Add sqlestUnapplyList method to fix issue with List.unapplySeq in 2.13
Oswald-Graeme Oct 14, 2025
43dff19
Replace joda with java time
Graeme-Oswald Oct 21, 2025
2cdc4bb
And remove joda dependencies
Graeme-Oswald Oct 21, 2025
8079fa0
Remove cross version
Graeme-Oswald Nov 11, 2025
4f9e453
Setting version to 0.9.4
Graeme-Oswald Nov 11, 2025
8652294
Setting version to 0.9.5-SNAPSHOT
Graeme-Oswald Nov 11, 2025
537a5c3
Fix npe on date and time columns
Graeme-Oswald Nov 13, 2025
6223044
Setting version to 0.9.5
Graeme-Oswald Nov 13, 2025
cbf49c7
Revert "Setting version to 0.9.5"
Graeme-Oswald Nov 13, 2025
f50c35a
Setting version to 0.9.5
Graeme-Oswald Nov 13, 2025
4f29494
Setting version to 0.9.6-SNAPSHOT
Graeme-Oswald Nov 13, 2025
c941a88
Make sure date and time patterns are consistent (will modify applicat…
Graeme-Oswald Nov 14, 2025
518cc58
Setting version to 0.9.6
Graeme-Oswald Nov 14, 2025
4f606fc
Setting version to 0.9.7-SNAPSHOT
Graeme-Oswald Nov 14, 2025
9b8670e
Setting version to 0.9.7
Graeme-Oswald Nov 18, 2025
4dd16d2
Setting version to 0.9.8-SNAPSHOT
Graeme-Oswald Nov 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ target/
project/.ensimeextractors/.scannerwork/
sqlest/.scannerwork/
extractors/.scannerwork/
.bsp/
13 changes: 13 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version = "3.9.10"
runner.dialect = scala213
maxColumn = 120
align.preset = more
continuationIndent.defnSite = 2
assumeStandardLibraryStripMargin = true
docstrings.style = Asterisk
lineEndings = preserve
includeCurlyBraceInSelectChains = false
danglingParentheses.preset = true
optIn.annotationNewlines = true
newlines.alwaysBeforeMultilineDef = false
rewrite.rules = [SortImports, RedundantBraces]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
84 changes: 40 additions & 44 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -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: _*)
Expand All @@ -17,35 +12,35 @@ lazy val sqlest = (project in file("sqlest"))
.settings(moduleName := "sqlest")
.settings(sqlestSettings: _*)
.settings(
tutSourceDirectory := file("docs") / "sqlest",
tutTargetDirectory := file("."),
libraryDependencies ++= Seq("com.typesafe.scala-logging" %% "scala-logging" % "3.5.0")
mdocIn := file("docs") / "sqlest",
mdocOut := file("."),
libraryDependencies ++= Seq("com.typesafe.scala-logging" %% "scala-logging" % "3.9.6")
).dependsOn(extractors)

lazy val extractors = (project in file("extractors"))
.enablePlugins(spray.boilerplate.BoilerplatePlugin)
.settings(moduleName := "sqlest-extractors")
.settings(sqlestSettings: _*)
.settings(
tutSourceDirectory := file("docs") / "extractors",
tutTargetDirectory := file("extractors"),
mdocIn := file("docs") / "extractors",
mdocOut := file("extractors"),
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"joda-time" % "joda-time" % "2.3",
"org.joda" % "joda-convert" % "1.6"
"joda-time" % "joda-time" % "2.14.0",
"org.joda" % "joda-convert" % "3.0.1"
)
)

lazy val examples = (project in file("examples"))
.settings(commonSettings: _*)
.settings(noPublishSettings: _*)
.settings(libraryDependencies += "com.h2database" % "h2" % "1.4.180")
.settings(libraryDependencies += "com.h2database" % "h2" % "2.4.240")
.dependsOn(sqlest)

lazy val commonSettings = SbtScalariform.scalariformSettings ++ publishingSettings ++ Seq(
lazy val commonSettings = publishingSettings ++ Seq(
organization := "uk.co.jhc",
scalaVersion := "2.12.1",
crossScalaVersions := List("2.11.8", "2.12.1"),
scalaVersion := "2.13.16",
crossScalaVersions := List("2.13.16"),
scalacOptions ++= Seq(
"-deprecation",
"-encoding", "UTF-8",
Expand All @@ -54,54 +49,55 @@ lazy val commonSettings = SbtScalariform.scalariformSettings ++ publishingSettin
"-language:higherKinds",
"-language:implicitConversions",
"-unchecked",
"-Xfatal-warnings",
"-Xfuture"
"-Xfatal-warnings"//,
// "-Ystatistics:typer",
// "-Xlog-implicit-conversions",
// "-Xlog-implicits"
),
coverageExcludedPackages := "sqlest.examples",
ScalariformKeys.preferences := ScalariformKeys.preferences.value
.setPreference(DanglingCloseParenthesis, Preserve)
coverageExcludedPackages := "sqlest.examples"
)

lazy val sqlestSettings = commonSettings ++ scaladocSettings ++ tutSettings ++ Seq(
tutNameFilter := """README.md""".r,
lazy val sqlestSettings = commonSettings ++ scaladocSettings ++ mdocSettings ++ Seq(
mdocVariables := Map("VERSION" -> version.value),
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.0.1" % "test",
"com.chuusai" %% "shapeless" % "2.3.2" % "test",
"com.h2database" % "h2" % "1.4.180" % "test"
"org.scalatest" %% "scalatest" % "3.2.19" % "test",
"com.chuusai" %% "shapeless" % "2.3.13" % "test",
"com.h2database" % "h2" % "2.4.240" % "test"
)
)

lazy val noPublishSettings = Seq(
publish := (),
publishLocal := (),
publish / skip := true,
publishLocal / skip := true,
publishArtifact := false
)

lazy val scaladocSettings = SbtSite.site.settings ++ SbtSite.site.includeScaladoc() ++ SbtGhPages.ghpages.settings ++ Seq(
lazy val scaladocSettings = Seq(
gitRemoteRepo := "git@github.com:jhc-systems/sqlest.git"
)

lazy val mdocSettings = Seq(
mdocExtraArguments := Seq("--no-link-hygiene")
)

lazy val publishingSettings = sonatypeReleaseProcess ++ Seq(
// Publishing - http://www.scala-sbt.org/0.13/docs/Using-Sonatype.html
releaseCrossBuild := true,
releasePublishArtifactsAction := PgpKeys.publishSigned.value,
publishMavenStyle := true,
publishArtifact in Test := false,
Test / publishArtifact := false,
publishTo := {
val nexus = "https://oss.sonatype.org/"
val nexus = "https://nexus-proxy.lighthouse.jhc.uk/nexus/content/repositories/"
if (isSnapshot.value)
Some("snapshots" at nexus + "content/repositories/snapshots")
Some("snapshots" at nexus + "snapshots")
else
Some("releases" at nexus + "service/local/staging/deploy/maven2")
},
credentials := {
Seq("SONATYPE_USER", "SONATYPE_PASSWORD").map(sys.env.get) match {
case Seq(Some(user), Some(password)) =>
Seq(Credentials("Sonatype Nexus Repository Manager", "oss.sonatype.org", user, password))
case _ =>
credentials.value
}
Some("releases" at nexus + "releases")
},
credentials += Credentials(
"Sonatype Nexus Repository Manager",
"nexus-proxy.lighthouse.jhc.uk",
"dev", "jhcjhc"
),
pomIncludeRepository := { _ => false },
pomExtra := (
<url>https://github.com/jhc-systems/sqlest</url>
Expand Down Expand Up @@ -140,7 +136,7 @@ lazy val sonatypeReleaseProcess = Seq(
ReleaseStep(action = Command.process("publishSigned", _), enableCrossBuild = true),
setNextVersion,
commitNextVersion,
ReleaseStep(action = Command.process("sonatypeReleaseAll", _), enableCrossBuild = true),
ReleaseStep(action = Command.process("sonaRelease", _), enableCrossBuild = true),
pushChanges
)
)
3 changes: 2 additions & 1 deletion examples/src/main/scala/sqlest/examples/Database.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sqlest.examples

import sqlest._
import sqlest.executor.Database

trait DatabaseExample {
// Configure a DataSource
Expand All @@ -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("""
Expand Down
2 changes: 1 addition & 1 deletion extractors/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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#])#

]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)}
}
"""
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -136,12 +141,12 @@ case class CaseClassExtractorMacro(c: Context) {

val liftedParamTypes = paramTypes.map(liftParam)

(paramNames, liftedParamTypes, defaultValues).zipped.map {
case (paramName, typ, defaultValue) =>
if (defaultValue.isDefined)
q"val $paramName: $typ = sqlest.extractor.ConstantExtractor(${defaultValue.get})"
else
q"val $paramName: $typ"
paramNames.lazyZip(liftedParamTypes).lazyZip(defaultValues).map {
case (paramName, typ, defaultValue) =>
if (defaultValue.isDefined)
q"val $paramName: $typ = sqlest.extractor.ConstantExtractor(${defaultValue.get})"
else
q"val $paramName: $typ"
}
}

Expand All @@ -152,7 +157,7 @@ case class CaseClassExtractorMacro(c: Context) {
if (applyMethod.isVarargs)
treeTypes.init :+
(paramTypes.last match {
case TypeRef(_, `repeatedParamClass`, typ :: Nil) => tq"scala.collection.Seq[$typ]"
case TypeRef(_, `repeatedParamClass`, typ :: Nil) => tq"Seq[$typ]"
})
else treeTypes

Expand Down
14 changes: 7 additions & 7 deletions extractors/src/main/scala/sqlest/extractor/Extractor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

package sqlest.extractor

import org.scalatest._
import org.scalatest.flatspec._
import org.scalatest.matchers.should._
import org.scalatest.prop._
import shapeless.test.illTyped

// TODO: The CaseClassExtractorMacro macro has issues with path-dependent types.
Expand All @@ -34,7 +36,7 @@ case object Circle extends Shape
case object Tetrahedron extends Shape
case object Plane extends Shape

class CaseClassExtractorMacroSpec extends FlatSpec with Matchers with ExtractorSyntax[Tuple3[Shape, Int, String]] with PathDependenceTestData {
class CaseClassExtractorMacroSpec extends AnyFlatSpec with Matchers with ExtractorSyntax[Tuple3[Shape, Int, String]] with PathDependenceTestData {

case class One(a: Int, b: String)
case class Two(a: String, b: Shape)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=0.13.17
sbt.version=1.11.5
Loading