Skip to content

Commit

Permalink
Update document
Browse files Browse the repository at this point in the history
  • Loading branch information
takapi327 committed Dec 31, 2024
1 parent 0a82bd7 commit b7e4e53
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 435 deletions.
4 changes: 2 additions & 2 deletions docs/src/main/mdoc/ja/migration-notes.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{%
laika.title = Migration Notes
laika.title = マイグレーションノート
laika.metadata.language = ja
%}

# Migration Notes (Upgrading to 0.3.x from 0.2.x)
# マイグレーションノート (0.2.xから0.3.xへの移行)

## パッケージ

Expand Down
110 changes: 104 additions & 6 deletions docs/src/main/mdoc/ja/tutorial/Custom-Data-Type.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,135 @@ enum Status(val done: Boolean, val name: String):
これによりstatementにカスタム型をバインドすることができるようになります。

```scala 3
given Encoder[Status] with
override def encode(status: Status): Boolean = status.done
given Encoder[Status] = Encoder[Boolean].contramap(_.done)
```

カスタム型は他のパラメーターと同じようにstatementにバインドすることができます。

```scala
val program1: Executor[IO, Int] =
val program1: DBIO[Int] =
sql"INSERT INTO user (name, email, status) VALUES (${ "user 1" }, ${ "[email protected]" }, ${ Status.Active })".update
```

これでstatementにカスタム型をバインドすることができるようになりました。

また、Encoderは複数の型を合成して新しい型を作成することができます。

```scala 3
val encoder: Encoder[(Int, String)] = Encoder[Int] *: Encoder[String]
```

合成した型は任意のクラスに変換することもできます。

```scala 3
case class Status(code: Int, name: String)
given Encoder[Status] = (Encoder[Int] *: Encoder[String]).to[Status]
```

## Decoder

ldbcではパラメーターの他に実行結果から独自の型を取得するための`Decoder`も提供しています。

`Decoder`を実装することでstatementの実行結果から独自の型を取得することができます。

以下のコード例では、`Decoder.Elem`を使用して単一のデータ型を取得する方法を示しています。
以下のコード例では、`Decoder`を使用して単一のデータ型を取得する方法を示しています。

```scala 3
given Decoder.Elem[Status] = Decoder.Elem.mapping[Boolean, Status] {
given Decoder[Status] = Decoder[Boolean].map {
case true => Status.Active
case false => Status.InActive
}
```

```scala 3
val program2: Executor[IO, (String, String, Status)] =
val program2: DBIO[(String, String, Status)] =
sql"SELECT name, email, status FROM user WHERE id = 1".query[(String, String, Status)].unsafe
```

これでstatementの実行結果からカスタム型を取得することができるようになりました。

Decoderも複数の型を合成して新しい型を作成することができます。

```scala 3
val decoder: Decoder[(Int, String)] = Decoder[Int] *: Decoder[String]
```

合成した型は任意のクラスに変換することもできます。

```scala 3
case class Status(code: Int, name: String)
given Decoder[Status] = (Decoder[Int] *: Decoder[String]).to[Status]
```

## Codec

`Encoder``Decoder`を組み合わせた`Codec`を使用することでstatementに受け渡す値とstatementの実行結果から独自の型を取得することができます。

以下のコード例では、`Codec`を使用して先ほどの`Encoder``Decoder`を組み合わせた方法を示しています。

```scala 3
given Codec[Status] = Codec[Boolean].imap(_.done)(Status(_))
```

Codecも複数の型を合成して新しい型を作成することができます。

```scala 3
val codec: Codec[(Int, String)] = Codec[Int] *: Codec[String]
```

合成した型は任意のクラスに変換することもできます。

```scala 3
case class Status(code: Int, name: String)
given Codec[Status] = (Codec[Int] *: Codec[String]).to[Status]
```

Codecは、`Encoder``Decoder`を組み合わせたものであるため、それぞれの型への変換処理を行うことができます。

```scala 3
val encoder: Encoder[Status] = Codec[Status].asEncoder
val decoder: Decoder[Status] = Codec[Status].asDecoder
```

`Codec`, `Encoder`, `Decoder`はそれぞれ合成することができるため、複数の型を組み合わせて新しい型を作成することができます。

これにより、ユーザーは取得したレコードをネストした階層データに変換できます。

```scala
case class City(id: Int, name: String, countryCode: String)
case class Country(code: String, name: String)
case class CityWithCountry(city: City, country: Country)

sql"SELECT city.Id, city.Name, city.CountryCode, country.Code, country.Name FROM city JOIN country ON city.CountryCode = country.Code".query[CityWithCountry]
```

Codecを始め`Encoder``Decoder`は暗黙的に解決されるため、ユーザーはこれらの型を明示的に指定する必要はありません。

しかし、モデル内に多くのプロパティがある場合、暗黙的な検索は失敗する可能性があります。

```shell
[error] |Implicit search problem too large.
[error] |an implicit search was terminated with failure after trying 100000 expressions.
[error] |The root candidate for the search was:
[error] |
[error] | given instance given_Decoder_P in object Decoder for ldbc.dsl.codec.Decoder[City]}
```

このような場合は、コンパイルオプションの検索制限を上げると問題が解決することがあります。

```scala
scalacOptions += "-Ximplicit-search-limit:100000"
```

しかし、オプションでの制限拡張はコンパイル時間の増幅につながる可能性があります。その場合は、以下のように手動で任意の型を構築することで解決することもできます。

```scala 3
given Decoder[City] = (Decoder[Int] *: Decoder[String] *: Decoder[Int] *: ....).to[City]
given Encoder[City] = (Encoder[Int] *: Encoder[String] *: Encoder[Int] *: ....).to[City]
```

もしくは、`Codec`を使用して`Encoder``Decoder`を組み合わせることで解決することもできます。

```scala 3
given Codec[City] = (Codec[Int] *: Codec[String] *: Codec[Int] *: ....).to[City]
```
8 changes: 4 additions & 4 deletions docs/src/main/mdoc/ja/tutorial/Database-Operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,18 @@ val write = sql"INSERT INTO `table`(`c1`, `c2`) VALUES ('column 1', 'column 2')"

`transaction`メソッドを使用することで複数のデータベース接続処理を1つのトランザクションにまとめることができます。

ldbcは`Executor[F, A]`という形式でデータベースへの接続処理を組むことになる。 Executorはモナドなので、for内包を使って2つの小さなプログラムを1つの大きなプログラムにすることができる。
ldbcは`DBIO[A]`という形式でデータベースへの接続処理を組むことになる。 DBIOはモナドなので、for内包を使って2つの小さなプログラムを1つの大きなプログラムにすることができる。

```scala
val program: Executor[IO, (List[Int], Option[Int], Int)] =
```scala 3
val program: DBIO[(List[Int], Option[Int], Int)] =
for
result1 <- sql"SELECT 1".query[Int].to[List]
result2 <- sql"SELECT 2".query[Int].to[Option]
result3 <- sql"SELECT 3".query[Int].unsafe
yield (result1, result2, result3)
```

1つのプログラムとなった`Executor``transaction`メソッドで1つのトランザクションでまとめて処理を行うことができます。
1つのプログラムとなった`DBIO``transaction`メソッドで1つのトランザクションでまとめて処理を行うことができます。

```scala
val transaction = program.transaction(connection)
Expand Down
8 changes: 4 additions & 4 deletions docs/src/main/mdoc/ja/tutorial/Error-Handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

## 例外について

ある操作が成功するかどうかは、ネットワークの健全性、テーブルの現在の内容、ロックの状態など、予測できない要因に依存します。そのため、`EitherT[Executor, Throwable, A]`のような論理和ですべてを計算するか、明示的に捕捉されるまで例外の伝播を許可するかを決めなければならない。つまり、ldbcのアクション(ターゲット・モナドに変換される)が実行されると、例外が発生する可能性がある。
ある操作が成功するかどうかは、ネットワークの健全性、テーブルの現在の内容、ロックの状態など、予測できない要因に依存します。そのため、`EitherT[DBIO, Throwable, A]`のような論理和ですべてを計算するか、明示的に捕捉されるまで例外の伝播を許可するかを決めなければならない。つまり、ldbcのアクション(ターゲット・モナドに変換される)が実行されると、例外が発生する可能性がある。

発生しやすい例外は主に3種類ある

Expand All @@ -19,7 +19,7 @@

## モナド・エラーと派生コンバイネーター

すべてのldbcモナドは、`MonadError[?[_], Throwable]`を拡張したAsyncインスタンスを提供する。つまり、Executorなどは以下のようなプリミティブな操作を持つことになる
すべてのldbcモナドは、`MonadError[?[_], Throwable]`を拡張したAsyncインスタンスを提供する。つまり、DBIOなどは以下のようなプリミティブな操作を持つことになる

- raiseError: 例外を発生させる (Throwableを`M[A]`に変換する)
- handleErrorWith: 例外を処理する (`M[A]``M[B]`に変換する)
Expand All @@ -28,10 +28,10 @@
つまり、どんなldbcプログラムでも`attempt`を加えるだけで例外を捕捉することができるのだ。

```scala
val program = Executor.pure[IO, Int](1)
val program = DBIO.pure[IO, Int](1)

program.attempt
// Executor[IO, Either[Throwable, Int]]
// DBIO[IO, Either[Throwable, Int]]
```

`attempt``raiseError`コンビネータから、Catsのドキュメントで説明されているように、他の多くの操作を派生させることができます。
5 changes: 4 additions & 1 deletion docs/src/main/mdoc/ja/tutorial/Schema-Code-Generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,10 @@ object Japan extends CountryCode:
override val code: Int = 1
trait CustomMapping: // 任意の名前
given Conversion[INT[Int], CountryCode] = DataType.mappingp[INT[Int], CountryCode]
given Codec[CountryCode] = Codec[Int].imap {
case 1 => Japan
case _ => throw new Exception("Not found")
}(_.code)
```

カスタマイズを行うためのymlファイルに実装を行なった`CustomMapping`traitを設定し、対象のカラムの型をCountryCodeに変換してあげます。
Expand Down
Loading

0 comments on commit b7e4e53

Please sign in to comment.