Skip to content

Commit ca22c43

Browse files
authored
Introduce TypeMapper#bimap to make created related TypeMappers easier (#27)
Rather than going through the whole `extends TypeMapper` `def jdbcType` `def get` `def put`, you can take an existing `TypeMapper` and call `TypeMapper[T].bimap[V]` with two conversion functions `f: V => T` and `g: T => V`
1 parent 353776f commit ca22c43

File tree

4 files changed

+90
-9
lines changed

4 files changed

+90
-9
lines changed

docs/tutorial.md

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,20 +1334,46 @@ object CityId {
13341334
13351335
13361336
```scala
1337-
case class City2[T[_]](
1337+
case class City[T[_]](
13381338
id: T[CityId],
13391339
name: T[String],
13401340
countryCode: T[String],
13411341
district: T[String],
13421342
population: T[Long]
13431343
)
13441344
1345+
object City extends Table[City]() {
1346+
override def tableName: String = "city"
1347+
}
1348+
db.run(
1349+
City.insert.columns(
1350+
_.id := CityId(313373),
1351+
_.name := "test",
1352+
_.countryCode := "XYZ",
1353+
_.district := "district",
1354+
_.population := 1000000
1355+
)
1356+
)
1357+
1358+
db.run(City.select.filter(_.id === 313373).single) ==>
1359+
City[Sc](CityId(313373), "test", "XYZ", "district", 1000000)
1360+
```
1361+
1362+
```scala
1363+
case class City2[T[_]](
1364+
id: T[CityId2],
1365+
name: T[String],
1366+
countryCode: T[String],
1367+
district: T[String],
1368+
population: T[Long]
1369+
)
1370+
13451371
object City2 extends Table[City2]() {
13461372
override def tableName: String = "city"
13471373
}
13481374
db.run(
13491375
City2.insert.columns(
1350-
_.id := CityId(31337),
1376+
_.id := CityId2(31337),
13511377
_.name := "test",
13521378
_.countryCode := "XYZ",
13531379
_.district := "district",
@@ -1356,8 +1382,9 @@ db.run(
13561382
)
13571383
13581384
db.run(City2.select.filter(_.id === 31337).single) ==>
1359-
City2[Sc](CityId(31337), "test", "XYZ", "district", 1000000)
1360-
```
1385+
City2[Sc](CityId2(31337), "test", "XYZ", "district", 1000000)
1386+
1387+
st("customTableColumnNames") {
13611388
13621389
## Customizing Table and Column Names
13631390

scalasql/core/src/TypeMapper.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import java.util.UUID
2929
* Defaults are provided for most common Scala primitives, but you can also provide
3030
* your own by defining an `implicit val foo: TypeMapper[T]`
3131
*/
32-
trait TypeMapper[T] {
32+
trait TypeMapper[T] { outer =>
3333

3434
/**
3535
* The JDBC type of this type. Used for `setNull` which needs to know the
@@ -51,9 +51,21 @@ trait TypeMapper[T] {
5151
* How to insert a value of type [[T]] into a `PreparedStatement`
5252
*/
5353
def put(r: PreparedStatement, idx: Int, v: T): Unit
54+
55+
/**
56+
* Create a new `TypeMapper[V]` based on this `TypeMapper[T]` given the
57+
* two conversion functions `f: V => T`, `g: T => V`
58+
*/
59+
def bimap[V](f: V => T, g: T => V): TypeMapper[V] = new TypeMapper[V] {
60+
def jdbcType: JDBCType = outer.jdbcType
61+
override def castTypeString: String = outer.castTypeString
62+
def get(r: ResultSet, idx: Int): V = g(outer.get(r, idx))
63+
def put(r: PreparedStatement, idx: Int, v: V): Unit = outer.put(r, idx, f(v))
64+
}
5465
}
5566

5667
object TypeMapper {
68+
def apply[T](implicit t: TypeMapper[T]): TypeMapper[T] = t
5769

5870
/**
5971
* These definitions are workarounds for a bug in the Scala 3 compiler

scalasql/src/package.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ package object scalasql {
3636
type Expr[T] = core.Expr[T]
3737

3838
type TypeMapper[T] = core.TypeMapper[T]
39+
val TypeMapper = core.TypeMapper
3940

4041
val Config = core.Config
4142
type Config = core.Config

scalasql/test/src/WorldSqlTests.scala

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,20 +1420,62 @@ object WorldSqlTests extends TestSuite {
14201420
SqlStr.Interp.TypeInterp[CityId](CityId(1337))
14211421
// +DOCS
14221422

1423-
case class City2[T[_]](
1423+
case class City[T[_]](
14241424
id: T[CityId],
14251425
name: T[String],
14261426
countryCode: T[String],
14271427
district: T[String],
14281428
population: T[Long]
14291429
)
14301430

1431+
object City extends Table[City]() {
1432+
override def tableName: String = "city"
1433+
}
1434+
db.run(
1435+
City.insert.columns(
1436+
_.id := CityId(313373),
1437+
_.name := "test",
1438+
_.countryCode := "XYZ",
1439+
_.district := "district",
1440+
_.population := 1000000
1441+
)
1442+
)
1443+
1444+
db.run(City.select.filter(_.id === 313373).single) ==>
1445+
City[Sc](CityId(313373), "test", "XYZ", "district", 1000000)
1446+
// -DOCS
1447+
1448+
// You can also use `TypeMapper#bimap` for the common case where you want the
1449+
// new `TypeMapper` to behave the same as an existing `TypeMapper`, just with
1450+
// conversion functions to convert back and forth between the old type and new type:
1451+
1452+
case class CityId2(value: Int)
1453+
1454+
object CityId2 {
1455+
implicit def tm: TypeMapper[CityId2] = TypeMapper[Int].bimap[CityId2](
1456+
city => city.value,
1457+
int => CityId2(int)
1458+
)
1459+
}
1460+
1461+
// -DOCS
1462+
// Note sure why this is required, probably a Scalac bug
1463+
SqlStr.Interp.TypeInterp[CityId2](CityId2(1337))
1464+
// +DOCS
1465+
case class City2[T[_]](
1466+
id: T[CityId2],
1467+
name: T[String],
1468+
countryCode: T[String],
1469+
district: T[String],
1470+
population: T[Long]
1471+
)
1472+
14311473
object City2 extends Table[City2]() {
14321474
override def tableName: String = "city"
14331475
}
14341476
db.run(
14351477
City2.insert.columns(
1436-
_.id := CityId(31337),
1478+
_.id := CityId2(31337),
14371479
_.name := "test",
14381480
_.countryCode := "XYZ",
14391481
_.district := "district",
@@ -1442,8 +1484,7 @@ object WorldSqlTests extends TestSuite {
14421484
)
14431485

14441486
db.run(City2.select.filter(_.id === 31337).single) ==>
1445-
City2[Sc](CityId(31337), "test", "XYZ", "district", 1000000)
1446-
// -DOCS
1487+
City2[Sc](CityId2(31337), "test", "XYZ", "district", 1000000)
14471488
}
14481489
test("customTableColumnNames") {
14491490
// +DOCS

0 commit comments

Comments
 (0)