在昨天的範例中的 Entity,在操作新增與列表都是沒有問題。唯在 update 時,會報 mongodb 無法轉換的問題, 今天會來解決這個問題。今天的 code 也已放置在 GitHub

Data Class 與 MongoDB 轉換問題

參考這個 issue 主要就是 Kotlin 的 data class 並沒有帶一個空的 constructor。所以要宣告 BsonCreator, field 要打上 BsonId 與 BsonProperty

data class FilmEntity @BsonCreator constructor( @BsonId var id: ObjectId? = null, @BsonProperty("title") var title: String, @BsonProperty("episodeId") var episodeId: Int, @BsonProperty("director") var director: String, @BsonProperty("releaseDate") var releaseDate: LocalDate ) : PanacheMongoEntityBase()

大家就可以用順手的 REST client 測測看。我自已是習慣 Talend API Tester 。不過現在都是 TDD 的時代了,Quarkus 這方面也是整合的很好。後面幾天再來開一篇。

Function 串串法

昨天的文章帶有點快,今天來細節分析 service 裡的一些操作。在寫程式的時候,想變數是件很花時間的事,或用巢狀操作來省掉變數,但比較不容易閱讀。其實每個變數的產生常常只是為了帶給下一個 function,在作的事情都是 A -> B,B -> C 的過程。所以可以利用 Kotlin 的 High Order Function 把連續的操作串起來。而這樣的操作其實也是符合人的思考流程。

先來看看這個例子。以 java 的風格換一個 json 再送出去,可能會這樣寫

outgoing.send(Frame.Text(Gson().toJson(JoinChat(ArrayList<ChatMessage>(), author))))

這裡 koltin 提供了 let 這個 Scope function,會把自已當作 it, 並把function 的結果當 return, 所以我們就可以把整個 code flow 反轉過來。變的符合思考 flow.

JoinChat(ArrayList<ChatMessage>(), author)
  .let{ Gson().toJson(it) }
  .let( Frame.Text(json) )
  .let{ outgoing::send(it) }

其中如果這個要執行的 function 只有一個輸入值。就可以直接當參數用 () 傳入。所以就會看到 film.let(modelToEntity) 這樣的寫法,看來是傳入參數,實際上也是,但我們傳入的是一個 function type 要作 transform 。 所以就可以看到這個 save 流水線的操作,也很好閱讀

suspend fun save(film: Film) = film.let(modelToEntity)
        .let(filmRepository::persist)
        .awaitSuspending().let(entityToModel)