Skip to content
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

Kotlin KSP Nullability Fix #718

Merged
merged 1 commit into from
Dec 13, 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
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
package com.querydsl.example.ksp

import jakarta.persistence.Entity
import jakarta.persistence.Enumerated
import jakarta.persistence.EnumType
import jakarta.persistence.Id
import jakarta.persistence.ManyToOne

@Entity
class Cat(
@Id
val id: Int,
val name: String,
val isTailUpright: Boolean
val isTailUpright: Boolean,
val fluffiness: String? = null,

@ManyToOne
val owner: Person? = null,

@Enumerated(EnumType.STRING)
val catType: CatType? = CatType.HOUSE,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.querydsl.example.ksp

enum class CatType {
HOUSE,
MAINE_COON
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ package com.querydsl.example.ksp

import jakarta.persistence.Entity
import jakarta.persistence.Id
import jakarta.persistence.OneToMany

@Entity
class Person(
@Id
val id: Int,
val name: String,

@OneToMany(mappedBy = "owner")
val cats: List<Cat>? = null,
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import com.querydsl.example.ksp.Cat
import com.querydsl.example.ksp.CatType
import com.querydsl.example.ksp.Person
import com.querydsl.example.ksp.QCat
import com.querydsl.example.ksp.QPerson
Expand Down Expand Up @@ -40,15 +41,48 @@ class Tests {
}
}

@Test
fun `create cat with owner` () {
val emf = initialize()

run {
val em = emf.createEntityManager()
em.transaction.begin()
val catOwner = Person(425, "Percy Bysshe Catownerly")
em.persist(catOwner)
em.persist(Cat(103, "Samuel Taylor Cattingridge", false, "Not so fluffy", catOwner, CatType.MAINE_COON))
em.transaction.commit()
em.close()
}

run {
val em = emf.createEntityManager()
val queryFactory = JPAQueryFactory(em)
val q = QCat.cat
val catWithOwner = queryFactory
.selectFrom(q)
.where(q.name.eq("Samuel Taylor Cattingridge"))
.fetchOne()
if (catWithOwner == null) {
fail<Any>("No owned cat was returned")
} else {
assertThat(catWithOwner.id).isEqualTo(103)
assertThat(catWithOwner.catType).isEqualTo(CatType.MAINE_COON)
assertThat(catWithOwner.owner?.id).isEqualTo(425)
}
em.close()
}
}

@Test
fun `filter entities`() {
val emf = initialize()

run {
val em = emf.createEntityManager()
em.transaction.begin()
em.persist(Cat(100, "Neville Furbottom", true))
em.persist(Cat(101, "Edgar Allan Paw", true))
em.persist(Cat(100, "Neville Furbottom", true, "Quite Fluffy"))
em.persist(Cat(101, "Edgar Allan Paw", true, null))
em.persist(Cat(102, "Admiral Meowington", false))
em.transaction.commit()
em.close()
Expand All @@ -66,6 +100,13 @@ class Tests {
assertThat(animals.size).isEqualTo(2)
assertThat(animals).contains("Neville Furbottom")
assertThat(animals).contains("Edgar Allan Paw")
val quiteFluffyAnimals = queryFactory
.selectFrom(q)
.where(q.fluffiness.eq("Quite Fluffy"))
.fetch()
.map { it.name }
assertThat(quiteFluffyAnimals.size).isEqualTo(1)
assertThat(quiteFluffyAnimals).contains("Neville Furbottom")
em.close()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class TypeExtractor(
}

private fun simpleType(type: KSType): QPropertyType.Simple? {
val className = type.toClassName()
val className = type.toClassNameSimple()
val simpleType = SimpleType.Mapper.get(className)
if (simpleType == null) {
return null
Expand All @@ -61,7 +61,7 @@ class TypeExtractor(
if (declaration is KSClassDeclaration) {
types.addAll(declaration.getAllSuperTypes())
}
val classNames = types.map { it.toClassName() }
val classNames = types.map { it.toClassNameSimple() }
return if (classNames.any { it.isMap() }) {
assertTypeArgCount(type, "map", 2)
val keyType = extract(type.arguments[0].type!!.resolve())
Expand All @@ -86,7 +86,7 @@ class TypeExtractor(
val referencedDeclaration = type.declaration
if (referencedDeclaration is KSClassDeclaration) {
return when (referencedDeclaration.classKind) {
ClassKind.ENUM_CLASS -> QPropertyType.EnumReference(type.toClassName())
ClassKind.ENUM_CLASS -> QPropertyType.EnumReference(type.toClassNameSimple())
ClassKind.CLASS, ClassKind.INTERFACE -> {
if (isEntity(referencedDeclaration)) {
return QPropertyType.ObjectReference(
Expand Down Expand Up @@ -115,7 +115,7 @@ class TypeExtractor(
Convert::class.asClassName()
)
if (property.annotations.any { userTypeAnnotations.contains(it.annotationType.resolve().toClassName()) }) {
return QPropertyType.Unknown(type.toClassName(), type.toTypeName())
return QPropertyType.Unknown(type.toClassNameSimple(), type.toTypeName())
} else {
return null
}
Expand Down Expand Up @@ -156,3 +156,15 @@ private fun ClassName.isList(): Boolean {
private fun ClassName.isArray(): Boolean {
return this == Array::class.asClassName()
}

/**
* Ignores arguments and nullability, returning simple ClassName.
*/
private fun KSType.toClassNameSimple(): ClassName {
return when (val decl = declaration) {
is KSClassDeclaration -> decl.toClassName()
is KSTypeAlias -> decl.toClassName()
is KSTypeParameter -> error("Cannot convert KSTypeParameter to ClassName: '$this'")
else -> error("Could not compute ClassName for '$this'")
}
}
Loading