The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

シンプルになったMongoDB with PanacheとKotlin

MongoDBは、広く利用されている有名なNoSQLデータベースです。MongoDB with Panacheは、このよく知られたフレームワークの上に新しいレイヤーを提供します。このガイドでは、 MongoDB with Panache についてはすでに説明されているため詳細については説明しません。このガイドでは、KotlinベースのQuarkusアプリケーションでMongoDB with Panacheを使用するために必要なKotlin固有の変更点について説明します。

最初に:一例

MongoDB with Panacheガイドで見たように、これによってエンティティやリポジトリ(DAOとも呼ばれる)の機能を、自動的に提供される機能で拡張することができます。Kotlin を使っている場合は、Java 版と同じようなアプローチになりますが、若干の変更があります。エンティティをPanache対応にするには、次のように定義します。

class Person: PanacheMongoEntity {
    lateinit var name: String
    lateinit var birth: LocalDate
    lateinit var status: Status
}

ご覧のように、私たちのエンティティーはシンプルなままです。しかし、Java版とは少し違いがあります。Kotlin 言語は Java のように静的メソッドの概念をサポートしていません。その代わり、 コンパニオンオブジェクト を使わなければなりません。

class Person : PanacheMongoEntity() {
    companion object: PanacheMongoCompanion<Person> {  (1)
        fun findByName(name: String) = find("name", name).firstResult()
        fun findAlive() = list("status", Status.Alive)
        fun deleteStefs() = delete("name", "Stef")
    }

    lateinit var name: String  (2)
    lateinit var birth: LocalDate
    lateinit var status: Status
}
1 コンパニオンオブジェクトは、特定のインスタンスに関連しないすべてのメソッドを保持し、特定の型にバインドされた一般的な管理とクエリを可能にします。
2 ここでは選択肢がありますが、 lateinit の方法を選びました。これにより、これらのフィールドを非 null と宣言しておけば、 コンストラクタ (コードには表れていません) や MongoDB POJO コーデックがデータベースからデータを読み込む際に適切に割り当てられることがわかります。
これらの型は、これらのチュートリアルで述べられているJavaの型とは異なります。Kotlinをサポートするために、Panacheのすべての型は io.quarkus.mongodb.panache.kotlin パッケージに含まれています。このサブパッケージでは、JavaとKotlinの型を区別することができ、1つのプロジェクトで両方を明確に使用することができます。

Kotlin版では、単純に active record pattern の機能を companion object に追加しました。このわずかな変更を別にすれば、私たちは、Java側の世界から簡単にマップする方法で私たちの型を使用して作業することができます。

リポジトリパターンの使用

エンティティの定義

リポジトリパターンを使用する場合は、エンティティを通常のPOJOとして定義することができます。

class Person {
    var id: ObjectId? = null; // used by MongoDB for the _id field
    lateinit var name: String
    lateinit var birth: LocalDate
    lateinit var status: Status
}

リポジトリの定義

リポジトリを使用する場合、 PanacheMongoRepository を実装させることで、アクティブレコードパターンとまったく同じ便利なメソッドをリポジトリに注入することができます。

@ApplicationScoped
class PersonRepository: PanacheMongoRepository<Person> {
     fun findByName(name: String) = find("name", name).firstResult()
     fun findAlive() = list("status", Status.Alive)
     fun deleteStefs() = delete("name", "Stef")
}

PanacheMongoEntityBase で定義されているすべての操作は、あなたのリポジトリで利用できます。そのため、これを使用することは、注入する必要があることを除けば、active record パターンを使用することとまったく同じです。

@Inject
lateinit var personRepository: PersonRepository

@GET
fun count() = personRepository.count()

最も便利な操作

リポジトリを書くことで実行可能な最も一般的な操作は以下の通りです。

// creating a person
var person = Person()
person.name = "Stef"
person.birth = LocalDate.of(1910, Month.FEBRUARY, 1)
person.status = Status.Alive

// persist it: if you keep the default ObjectId ID field, it will be populated by the MongoDB driver
personRepository.persist(person)

person.status = Status.Dead;

// Your must call update() in order to send your entity modifications to MongoDB
personRepository.update(person);


// delete it
personRepository.delete(person);

// getting a list of all Person entities
val allPersons = personRepository.listAll()

// finding a specific person by ID
// here we build a new ObjectId, but you can also retrieve it from the existing entity after being persisted
ObjectId personId = new ObjectId(idAsString);
person = personRepository.findById(personId) ?: throw Exception("No person with that ID")

// finding all living persons
val livingPersons = personRepository.list("status", Status.Alive)

// counting all persons
val countAll = personRepository.count()

// counting all living persons
val countAlive = personRepository.count("status", Status.Alive)

// delete all living persons
personRepository.delete("status", Status.Alive)

// delete all persons
personRepository.deleteAll()

// delete by id
val deleted = personRepository.deleteById(personId)

// set the name of all living persons to 'Mortal'
var updated = personRepository.update("name", "Mortal").where("status", Status.Alive)

すべての list メソッドは、同等の stream バージョンがあります。

val persons = personRepository.streamAll();
val namesButEmmanuels = persons
    .map { it.name.toLowerCase() }
    .filter { it != "emmanuel" }

より詳しい例については、 Java版を参照してください。どちらのAPIも同じで、Kotlin開発者がより自然に感じられるようにKotlin特有の調整を行っている以外は、同じように動作します。これらの調整には、nullabilityの使用方法の改善や、APIメソッドに Optional を使用しないことなどが含まれます。

MongoDB with Panacheのセットアップと設定

MongoDB with PanacheをKotlinで使い始めるには、一般的にはJavaのチュートリアルで説明した手順を踏むことができます。プロジェクトの設定で最も大きな変更点は、インクルードするQuarkusのアーティファクトです。もちろん、必要であればJavaバージョンを残すこともできますが、Kotlin APIだけが必要であれば、代わりに以下の依存関係をインクルードします。

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-mongodb-panache-kotlin</artifactId>  (1)
</dependency>
1 最後に -kotlin が追加されていることに注意してください。一般的にはこのバージョンだけが必要ですが、もしあなたのプロジェクトがJavaとKotlinの両方のコードを使うのであれば、両方の成果物を安全に含めることができます。
build.gradle
implementation("io.quarkus:quarkus-mongodb-panache-kotlin") (1)
1 最後に -kotlin が追加されていることに注意してください。一般的にはこのバージョンだけが必要ですが、もしあなたのプロジェクトがJavaとKotlinの両方のコードを使うのであれば、両方の成果物を安全に含めることができます。