Skip to content

Introduce TypeMapper#bimap to make created related TypeMappers easier #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 31 additions & 4 deletions docs/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -1334,20 +1334,46 @@ object CityId {


```scala
case class City2[T[_]](
case class City[T[_]](
id: T[CityId],
name: T[String],
countryCode: T[String],
district: T[String],
population: T[Long]
)

object City extends Table[City]() {
override def tableName: String = "city"
}
db.run(
City.insert.columns(
_.id := CityId(313373),
_.name := "test",
_.countryCode := "XYZ",
_.district := "district",
_.population := 1000000
)
)

db.run(City.select.filter(_.id === 313373).single) ==>
City[Sc](CityId(313373), "test", "XYZ", "district", 1000000)
```

```scala
case class City2[T[_]](
id: T[CityId2],
name: T[String],
countryCode: T[String],
district: T[String],
population: T[Long]
)

object City2 extends Table[City2]() {
override def tableName: String = "city"
}
db.run(
City2.insert.columns(
_.id := CityId(31337),
_.id := CityId2(31337),
_.name := "test",
_.countryCode := "XYZ",
_.district := "district",
Expand All @@ -1356,8 +1382,9 @@ db.run(
)

db.run(City2.select.filter(_.id === 31337).single) ==>
City2[Sc](CityId(31337), "test", "XYZ", "district", 1000000)
```
City2[Sc](CityId2(31337), "test", "XYZ", "district", 1000000)

st("customTableColumnNames") {

## Customizing Table and Column Names

Expand Down
14 changes: 13 additions & 1 deletion scalasql/core/src/TypeMapper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import java.util.UUID
* Defaults are provided for most common Scala primitives, but you can also provide
* your own by defining an `implicit val foo: TypeMapper[T]`
*/
trait TypeMapper[T] {
trait TypeMapper[T] { outer =>

/**
* The JDBC type of this type. Used for `setNull` which needs to know the
Expand All @@ -51,9 +51,21 @@ trait TypeMapper[T] {
* How to insert a value of type [[T]] into a `PreparedStatement`
*/
def put(r: PreparedStatement, idx: Int, v: T): Unit

/**
* Create a new `TypeMapper[V]` based on this `TypeMapper[T]` given the
* two conversion functions `f: V => T`, `g: T => V`
*/
def bimap[V](f: V => T, g: T => V): TypeMapper[V] = new TypeMapper[V] {
def jdbcType: JDBCType = outer.jdbcType
override def castTypeString: String = outer.castTypeString
def get(r: ResultSet, idx: Int): V = g(outer.get(r, idx))
def put(r: PreparedStatement, idx: Int, v: V): Unit = outer.put(r, idx, f(v))
}
}

object TypeMapper {
def apply[T](implicit t: TypeMapper[T]): TypeMapper[T] = t

/**
* These definitions are workarounds for a bug in the Scala 3 compiler
Expand Down
1 change: 1 addition & 0 deletions scalasql/src/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ package object scalasql {
type Expr[T] = core.Expr[T]

type TypeMapper[T] = core.TypeMapper[T]
val TypeMapper = core.TypeMapper

val Config = core.Config
type Config = core.Config
Expand Down
49 changes: 45 additions & 4 deletions scalasql/test/src/WorldSqlTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1420,20 +1420,62 @@ object WorldSqlTests extends TestSuite {
SqlStr.Interp.TypeInterp[CityId](CityId(1337))
// +DOCS

case class City2[T[_]](
case class City[T[_]](
id: T[CityId],
name: T[String],
countryCode: T[String],
district: T[String],
population: T[Long]
)

object City extends Table[City]() {
override def tableName: String = "city"
}
db.run(
City.insert.columns(
_.id := CityId(313373),
_.name := "test",
_.countryCode := "XYZ",
_.district := "district",
_.population := 1000000
)
)

db.run(City.select.filter(_.id === 313373).single) ==>
City[Sc](CityId(313373), "test", "XYZ", "district", 1000000)
// -DOCS

// You can also use `TypeMapper#bimap` for the common case where you want the
// new `TypeMapper` to behave the same as an existing `TypeMapper`, just with
// conversion functions to convert back and forth between the old type and new type:

case class CityId2(value: Int)

object CityId2 {
implicit def tm: TypeMapper[CityId2] = TypeMapper[Int].bimap[CityId2](
city => city.value,
int => CityId2(int)
)
}

// -DOCS
// Note sure why this is required, probably a Scalac bug
SqlStr.Interp.TypeInterp[CityId2](CityId2(1337))
// +DOCS
case class City2[T[_]](
id: T[CityId2],
name: T[String],
countryCode: T[String],
district: T[String],
population: T[Long]
)

object City2 extends Table[City2]() {
override def tableName: String = "city"
}
db.run(
City2.insert.columns(
_.id := CityId(31337),
_.id := CityId2(31337),
_.name := "test",
_.countryCode := "XYZ",
_.district := "district",
Expand All @@ -1442,8 +1484,7 @@ object WorldSqlTests extends TestSuite {
)

db.run(City2.select.filter(_.id === 31337).single) ==>
City2[Sc](CityId(31337), "test", "XYZ", "district", 1000000)
// -DOCS
City2[Sc](CityId2(31337), "test", "XYZ", "district", 1000000)
}
test("customTableColumnNames") {
// +DOCS
Expand Down
Loading