Skip to content

Commit

Permalink
Merge pull request #272 from nafg/Add-Scala-3
Browse files Browse the repository at this point in the history
Add Scala 3
  • Loading branch information
nafg committed Dec 8, 2023
2 parents f5cebed + 5aa644a commit 670bc84
Show file tree
Hide file tree
Showing 14 changed files with 91 additions and 108 deletions.
16 changes: 14 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.13.12]
scala: [2.13.12, 3.3.0]
java: [temurin@11]
runs-on: ${{ matrix.os }}
steps:
Expand Down Expand Up @@ -63,6 +63,8 @@ jobs:
- name: Check that codegen output hasn't changed
run: git diff --exit-code --quiet HEAD slick-additions-codegen/src/test/resources

- run: mkdir -p slick-additions-entity/.js/target

- name: Compress target directories
run: tar cf targets.tar target slick-additions-codegen/src/test/resources/target slick-additions-entity/.jvm/target slick-additions-entity/.js/target slick-additions-codegen/target project/target

Expand All @@ -79,7 +81,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.13.12]
scala: [3.3.0]
java: [temurin@11]
runs-on: ${{ matrix.os }}
steps:
Expand Down Expand Up @@ -117,6 +119,16 @@ jobs:
tar xf targets.tar
rm targets.tar
- name: Download target directories (3.3.0)
uses: actions/download-artifact@v2
with:
name: target-${{ matrix.os }}-3.3.0-${{ matrix.java }}

- name: Inflate target directories (3.3.0)
run: |
tar xf targets.tar
rm targets.tar
- env:
PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
PGP_SECRET: ${{ secrets.PGP_SECRET }}
Expand Down
1 change: 1 addition & 0 deletions .mergify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pull_request_rules:
- author=scala-steward
- author=nafg-scala-steward[bot]
- check-success=Build and Test (ubuntu-latest, 2.13.12, temurin@11)
- check-success=Build and Test (ubuntu-latest, 3.3.0, temurin@11)
actions:
queue:
name: default
22 changes: 10 additions & 12 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import sbtcrossproject.CrossPlugin.autoImport.{CrossType, crossProject}

name := "slick-additions"

ThisBuild / crossScalaVersions := Seq("2.13.12")
ThisBuild / crossScalaVersions := Seq("2.13.12", "3.3.0")
ThisBuild / scalaVersion := (ThisBuild / crossScalaVersions).value.last
ThisBuild / organization := "io.github.nafg"
ThisBuild / scalacOptions ++= Seq("-deprecation", "-unchecked")
Expand All @@ -17,15 +17,14 @@ val slickVersion = "3.5.0-M5"
lazy val `slick-additions` =
(project in file("."))
.dependsOn(`slick-additions-entity`.jvm)
.aggregate(`slick-additions-entity`.jvm, `slick-additions-entity`.js, `slick-additions-codegen`)
// .aggregate(`slick-additions-entity`.jvm, `slick-additions-entity`.js, `slick-additions-codegen`)
.settings(
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided",
"com.typesafe.slick" %% "slick" % slickVersion,
"com.lihaoyi" %% "sourcecode" % "0.3.1",
"org.scalatest" %% "scalatest" % "3.2.17" % "test",
"com.h2database" % "h2" % "2.2.224" % "test",
"ch.qos.logback" % "logback-classic" % "1.4.14" % "test"
"org.scalatest" %% "scalatest" % "3.2.17" % "test",
"com.h2database" % "h2" % "2.2.224" % "test",
"ch.qos.logback" % "logback-classic" % "1.4.14" % "test"
)
)

Expand All @@ -34,8 +33,10 @@ lazy val `slick-additions-codegen` =
.settings(
libraryDependencies ++= Seq(
"com.typesafe.slick" %% "slick-hikaricp" % slickVersion,
"org.scalameta" %% "scalameta" % "4.8.14",
"org.scalameta" %% "scalafmt-core" % "3.7.17",
("org.scalameta" %% "scalameta" % "4.8.14")
.cross(CrossVersion.for3Use2_13).exclude("org.scala-lang.modules", "scala-collection-compat_2.13"),
("org.scalameta" %% "scalafmt-core" % "3.7.17")
.cross(CrossVersion.for3Use2_13).exclude("org.scala-lang.modules", "scala-collection-compat_2.13"),
"com.h2database" % "h2" % "2.2.224" % "test",
"org.scalatest" %% "scalatest" % "3.2.17" % "test"
)
Expand All @@ -48,10 +49,7 @@ lazy val `test-codegen` =
.settings(
publish / skip := true,
Compile / unmanagedSourceDirectories := Seq(baseDirectory.value),
scalacOptions += "-Ymacro-annotations",
libraryDependencies ++= Seq(
"com.typesafe.slick" %% "slick" % slickVersion,
"io.circe" %% "circe-generic" % "0.14.5",
"dev.optics" %% "monocle-macro" % "3.2.0"
"com.typesafe.slick" %% "slick" % slickVersion
)
)
3 changes: 2 additions & 1 deletion ci.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ inThisBuild(List(
"git diff --exit-code --quiet HEAD slick-additions-codegen/src/test/resources"
),
name = Some("Check that codegen output hasn't changed")
)
),
WorkflowStep.Run(List("mkdir -p slick-additions-entity/.js/target"))
),
githubWorkflowPublishTargetBranches := Seq(RefPredicate.StartsWith(Ref.Tag("v"))),
githubWorkflowPublish := Seq(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,17 @@ trait BaseCodeGenerator {
private def toTermRef0(last: String, revInit: List[String]): Term.Ref =
recursePathTerm[Term.Name, Term.Ref](revInit, term"$last")(_.termSelect(_))

protected def toTermRef(s: String): Term.Ref = {
val last :: revInit = s.split('.').toList.reverse
toTermRef0(last, revInit)
}
protected def toTermRef(s: String): Term.Ref =
s.split('.').toList.reverse match {
case Nil => term"$s"
case last :: revInit => toTermRef0(last, revInit)
}

protected def toTypeRef(s: String): Type.Ref = {
val last :: revInit = s.split('.').toList.reverse
recursePathTerm[Type.Name, Type.Ref](revInit, typ"$last")(_.typeSelect(_))
}
protected def toTypeRef(s: String): Type.Ref =
s.split('.').toList.reverse match {
case Nil => typ"$s"
case last :: revInit => recursePathTerm[Type.Name, Type.Ref](revInit, typ"$last")(_.typeSelect(_))
}

protected def imports(strings: List[String]): List[Stat] =
if (strings.isEmpty)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,19 @@ class TablesCodeGenerator extends BaseCodeGenerator {
.typeApply(rowClassType)

def mkMapping(rowClassName: String, mappingName: String, columns: List[ColumnConfig]) = {
val companion = Term.Name(rowClassName)
val rowClassType = Type.Name(rowClassName)
val terms = columns.map(_.tableFieldTerm)
val numCols = columns.length
val (tuple, factory, extractor) =
val companion = Term.Name(rowClassName)
val rowClassType = Type.Name(rowClassName)
val terms = columns.map(_.tableFieldTerm)
val numCols = columns.length
val rhs =
if (numCols == 1)
(terms.head, companion.termSelect("apply"), companion.termSelect("unapply"))
terms.head
.termSelect("mapTo")
.termApplyType(rowClassType)
else if (numCols <= 22)
(
Term.Tuple(terms),
Term.Eta(companion.termSelect("apply")).termSelect("tupled"),
companion.termSelect("unapply")
)
Term.Tuple(terms)
.termSelect("mapTo")
.termApplyType(rowClassType)
else {
@tailrec
def group22[A](values: List[A])(group: List[A] => A): A =
Expand Down Expand Up @@ -64,13 +64,13 @@ class TablesCodeGenerator extends BaseCodeGenerator {
term"Some".termApply(res)
)

(group22[Term](terms)(Term.Tuple(_)), fac, extractor)
group22[Term](terms)(Term.Tuple(_))
.termSelect("<>")
.termApply(fac, extractor)
}

defDef(mappingName, declaredType = Some(mappingType(rowClassType)))()(
tuple
.termSelect("<>")
.termApply(factory, extractor)
rhs
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package entity
import slick.additions.entity.Lookup, io.circe.generic.JsonCodec,
monocle.macros.Lenses
@JsonCodec @Lenses case class ColorsRow(name: String)
object ColorsRow
@JsonCodec @Lenses case class PeopleRow(
import slick.additions.entity.Lookup
case class ColorsRow(name: String)
case class PeopleRow(
first: String,
last: String,
city: String = "New York",
Expand All @@ -28,4 +26,3 @@ object ColorsRow
col23: Option[Int] = None,
col24: Option[Int] = None
)
object PeopleRow
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ object TableModules {
override def keyColumnName = "id"
val name = column[String]("name")
def mapping: slick.lifted.MappedProjection[ColorsRow] =
name.<>(ColorsRow.apply, ColorsRow.unapply)
name.mapTo[ColorsRow]
}
}
object People extends EntityTableModule[Long, PeopleRow]("people") {
Expand Down
10 changes: 0 additions & 10 deletions slick-additions-codegen/src/test/resources/entity/package.scala

This file was deleted.

7 changes: 3 additions & 4 deletions slick-additions-codegen/src/test/resources/plain/Tables.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import slick.jdbc.H2Profile.api._
object Tables {
class Colors(_tableTag: Tag)
extends Table[ColorsRow](_tableTag, Some("PUBLIC"), "colors") {
val id = column[Long]("id")
val name = column[String]("name")
def * : slick.lifted.ProvenShape[ColorsRow] =
(id, name).<>((ColorsRow.apply _).tupled, ColorsRow.unapply)
val id = column[Long]("id")
val name = column[String]("name")
def * : slick.lifted.ProvenShape[ColorsRow] = (id, name).mapTo[ColorsRow]
}
lazy val Colors = TableQuery[Colors]
class People(_tableTag: Tag)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package slick.additions.codegen

import slick.additions.codegen.extra.circe.CirceJsonCodecModelsCodeGenerator
import slick.additions.codegen.extra.monocle.MonocleLensesModelsCodeGenerator


case class CodeGeneration(generator: BaseCodeGenerator, rules: GenerationRules) {
def pkgName = rules.packageName
val filename: String = s"${pkgName}/${rules.container}.scala"
Expand All @@ -19,7 +15,7 @@ object CodeGeneration
new TestGenerationRules("TableModules", "entity") with EntityGenerationRules
),
CodeGeneration(
new KeylessModelsCodeGenerator with MonocleLensesModelsCodeGenerator with CirceJsonCodecModelsCodeGenerator,
new KeylessModelsCodeGenerator,
new TestGenerationRules("Models", "entity") with EntityGenerationRules
)
)
Expand Down
30 changes: 8 additions & 22 deletions src/main/scala/slick/additions/AdditionsProfile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import scala.language.implicitConversions
import slick.additions.entity._
import slick.ast._
import slick.jdbc.JdbcProfile
import slick.lifted.{AbstractTable, ForeignKeyQuery, MappedProjection, RepShape}
import slick.lifted.{AbstractTable, ForeignKeyQuery, MappedProjection, RepShape, Shape}

import sourcecode.Name

Expand All @@ -17,10 +17,6 @@ trait AdditionsProfile { this: JdbcProfile =>
implicit def lookupBaseColumnType[K: BaseColumnType, A]: BaseColumnType[Lookup[K, A]] =
MappedColumnType.base[Lookup[K, A], K](_.key, EntityKey(_))

type Ent[T <: EntityTableBase] = Entity[T#Key, T#Value]
type KEnt[T <: EntityTableBase] = KeyedEntity[T#Key, T#Value]
def Ent[T <: EntityTableBase](value: T#Value) = new KeylessEntity[T#Key, T#Value](value)

trait KeyedTableBase { keyedTable: Table[_] =>
type Key
def keyColumnName = "id"
Expand Down Expand Up @@ -81,14 +77,11 @@ trait AdditionsProfile { this: JdbcProfile =>
override def lookupQuery(lookup: Lookup) = this.filter(_.key === lookup.key)
override def lookupValue(a: KeyedEntity[K, V]) = a.value

implicit val mappingRepShape: Shape[FlatShapeLevel, MappedProjection[V], V, MappedProjection[V]] =
RepShape[FlatShapeLevel, MappedProjection[V], V]

def forInsertQuery[E, C[_]](q: Query[T, E, C]) = q.map(_.mapping)

def insert(v: V)(implicit ec: ExecutionContext): DBIO[SavedEntity[K, V]] = insert(Ent(v): Ent)

def insert(e: Ent)(implicit ec: ExecutionContext): DBIO[SavedEntity[K, V]] = {
def insert(e: Ent)(implicit ec: ExecutionContext): DBIO[SavedEntity[K, V]] = {
// Insert it and get the new or old key
val action = e match {
case ke: this.KEnt =>
Expand All @@ -98,6 +91,7 @@ trait AdditionsProfile { this: JdbcProfile =>
}
action.map(SavedEntity(_, e.value))
}

def update(ke: KEnt)(implicit ec: ExecutionContext): DBIO[SavedEntity[K, V]] =
forInsertQuery(lookupQuery(ke)).update(ke.value)
.map(_ => SavedEntity(ke.key, ke.value))
Expand Down Expand Up @@ -164,22 +158,14 @@ trait AdditionsProfile { this: JdbcProfile =>

type Row <: BaseEntRow

import scala.reflect.runtime.universe._


protected def rowClassMirror: ClassMirror = {
val m = runtimeMirror(this.getClass.getClassLoader)
val thisAsSymbol = m.moduleSymbol(this.getClass)
m.reflectClass(thisAsSymbol.info.member(TypeName("Row")).asClass)
protected def rowClass: Class[_] = {
val className = this.getClass.getName + "$Row"
Class.forName(className, true, this.getClass.getClassLoader)
}

protected def rowConstructorMirror: MethodMirror =
rowClassMirror.reflectConstructor(rowClassMirror.symbol.primaryConstructor.asMethod)
protected def rowConstructor = rowClass.getDeclaredConstructors.head

protected def mkRow: Tag => Row = {
val ctor = rowConstructorMirror
tag => ctor.apply(tag).asInstanceOf[Row]
}
protected def mkRow(tag: Tag): Row = rowConstructor.newInstance(tag).asInstanceOf[Row]

class TableQuery extends EntTableQuery[K, V, Row](mkRow)

Expand Down
43 changes: 22 additions & 21 deletions src/test/scala/slick/additions/KeyedTableTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,43 @@ package slick.additions

import scala.concurrent.ExecutionContext.Implicits.global

import slick.additions.test.TestsCommon
import slick.additions.test.TestProfile.api._
import slick.additions.test.TestsCommon

import org.scalatest.concurrent.IntegrationPatience
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers


class KeyedTableTests extends AnyFunSuite with Matchers with TestsCommon with IntegrationPatience {
case class Phone(kind: String, number: String, person: Option[People.Lookup] = None)
class Phones(tag: Tag) extends EntityTable[Long, Phone](tag, "phones") {
def tableQuery = Phones
def person = column[Option[People.Lookup]]("person_id")
def kind = column[String]("kind")
def number = column[String]("number")
def mapping = (kind, number, person).mapTo[Phone]
}
object Phones extends EntTableQuery[Long, Phone, Phones](new Phones(_))

case class Person(first: String, last: String)
class People(tag: Tag) extends EntityTable[Long, Person](tag, "people") {
def tableQuery = People
case class Phone(kind: String, number: String, person: Option[People.Lookup] = None)
class Phones(tag: Tag) extends EntityTable[Long, Phone](tag, "phones") {
def tableQuery = Phones
def person = column[Option[People.Lookup]]("person_id")
def kind = column[String]("kind")
def number = column[String]("number")
def mapping = (kind, number, person).mapTo[Phone]
}
object Phones extends EntTableQuery[Long, Phone, Phones](new Phones(_)) {
def countAction(phone: Phone) = Phones.filter(_.number === phone.number).length.result
}

def first = column[String]("first")
def last = column[String]("last")
case class Person(first: String, last: String)
class People(tag: Tag) extends EntityTable[Long, Person](tag, "people") {
def tableQuery = People

def mapping = (first, last).mapTo[Person]
}
def first = column[String]("first")
def last = column[String]("last")

object People extends EntTableQuery[Long, Person, People](new People(_))
def mapping = (first, last).mapTo[Person]
}
object People extends EntTableQuery[Long, Person, People](new People(_))

class KeyedTableTests extends AnyFunSuite with Matchers with TestsCommon with IntegrationPatience {
val schema = Phones.schema ++ People.schema

test("EntTableQuery#insert(KeylessEntity) does not insert twice [regression]") {
val phone = Phone("main", "1407124383")
val countAction = Phones.filter(_.number === phone.number).length.result
val countAction = Phones.countAction(phone)
assert(db.run(countAction).futureValue == 0)
assert(db.run(Phones.insert(phone) >> countAction).futureValue == 1)
}
Expand Down

0 comments on commit 670bc84

Please sign in to comment.