-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add typealiases for generate table def criteria queries #109
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| package com.faire.yawn | ||
|
|
||
| import com.faire.yawn.YawnTestUtils.assertGeneratedFile | ||
| import com.faire.yawn.criteria.query.JoinTypeSafeCriteriaQuery | ||
| import com.faire.yawn.criteria.query.ProjectedTypeSafeCriteriaQuery | ||
| import com.faire.yawn.criteria.query.TypeSafeCriteriaQuery | ||
| import org.assertj.core.api.Assertions.assertThat | ||
| import org.junit.jupiter.api.Test | ||
| import kotlin.reflect.KVisibility | ||
| import kotlin.reflect.typeOf | ||
|
|
||
| internal class YawnEntityProcessorTypeAliasesTest { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could we also add a very simple test on
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good call, can do |
||
| @Test | ||
| fun `generates type aliases for TableDef`() { | ||
| assertThat(typeOf<EntityWithElementCollectionTableDefType>()).isEqualTo( | ||
| typeOf<EntityWithElementCollectionTableDef<EntityWithElementCollection>>(), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun `generates type aliases for TypeSafeCriteriaQuery`() { | ||
| assertThat(typeOf<EntityWithElementCollectionCriteriaQuery>()).isEqualTo( | ||
| typeOf< | ||
| TypeSafeCriteriaQuery< | ||
| EntityWithElementCollection, | ||
| EntityWithElementCollectionTableDef<EntityWithElementCollection>, | ||
| >, | ||
| >(), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun `generates type aliases for JoinTypeSafeCriteriaQuery`() { | ||
| assertThat(typeOf<EntityWithElementCollectionJoinCriteriaQuery>()).isEqualTo( | ||
| typeOf< | ||
| JoinTypeSafeCriteriaQuery< | ||
| EntityWithElementCollection, | ||
| EntityWithElementCollection, | ||
| EntityWithElementCollectionTableDef<EntityWithElementCollection>, | ||
| >, | ||
| >(), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun `generates type aliases for ProjectedTypeSafeCriteriaQuery`() { | ||
| assertThat(typeOf<EntityWithElementCollectionProjectedCriteriaQuery<String>>()).isEqualTo( | ||
| typeOf<ProjectedTypeSafeCriteriaQuery<EntityWithElementCollection, *, *, String>>(), | ||
| ) | ||
|
|
||
| assertThat(typeOf<EntityWithElementCollectionProjectedCriteriaQuery<Boolean>>()).isEqualTo( | ||
| typeOf<ProjectedTypeSafeCriteriaQuery<EntityWithElementCollection, *, *, Boolean>>(), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun `visibility of type aliases is correct`() { | ||
| assertGeneratedFile<InternalEmptyEntityTable> { | ||
| containsTypeAlias("InternalEmptyEntityTableDefType", KVisibility.INTERNAL) | ||
| containsTypeAlias("InternalEmptyEntityCriteriaQuery", KVisibility.INTERNAL) | ||
| containsTypeAlias("InternalEmptyEntityJoinCriteriaQuery", KVisibility.INTERNAL) | ||
| containsTypeAlias("InternalEmptyEntityProjectedCriteriaQuery", KVisibility.INTERNAL) | ||
| } | ||
|
|
||
| assertGeneratedFile<PublicEmptyEntityTable> { | ||
| containsTypeAlias("PublicEmptyEntityTableDefType", KVisibility.PUBLIC) | ||
| containsTypeAlias("PublicEmptyEntityCriteriaQuery", KVisibility.PUBLIC) | ||
| containsTypeAlias("PublicEmptyEntityJoinCriteriaQuery", KVisibility.PUBLIC) | ||
| containsTypeAlias("PublicEmptyEntityProjectedCriteriaQuery", KVisibility.PUBLIC) | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package com.faire.yawn.generators.typealiases | ||
|
|
||
| import com.faire.ksp.getUniqueSimpleName | ||
| import com.faire.yawn.criteria.query.JoinTypeSafeCriteriaQuery | ||
| import com.squareup.kotlinpoet.ClassName | ||
| import com.squareup.kotlinpoet.ParameterizedTypeName | ||
| import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy | ||
| import com.squareup.kotlinpoet.asClassName | ||
|
|
||
| /** | ||
| * Generates: `typealias DbBookJoinCriteriaQuery = JoinTypeSafeCriteriaQuery<DbBook, DbBook, DbBookTableDef<DbBook>>` | ||
| */ | ||
| internal object JoinTypeSafeCriteriaQueryTypeAliasGenerator : YawnTableDefTypeAliasGenerator { | ||
| override fun getName(entityType: ClassName): String = "${entityType.getUniqueSimpleName()}JoinCriteriaQuery" | ||
|
|
||
| override fun getType(entityType: ClassName, tableDefType: ParameterizedTypeName): ParameterizedTypeName { | ||
| return JoinTypeSafeCriteriaQuery::class.asClassName().parameterizedBy( | ||
| entityType, | ||
| entityType, | ||
| tableDefType, | ||
| ) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package com.faire.yawn.generators.typealiases | ||
|
|
||
| import com.faire.ksp.getUniqueSimpleName | ||
| import com.faire.yawn.criteria.query.ProjectedTypeSafeCriteriaQuery | ||
| import com.faire.yawn.util.YawnContext | ||
| import com.squareup.kotlinpoet.ANY | ||
| import com.squareup.kotlinpoet.ClassName | ||
| import com.squareup.kotlinpoet.ParameterizedTypeName | ||
| import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy | ||
| import com.squareup.kotlinpoet.STAR | ||
| import com.squareup.kotlinpoet.TypeAliasSpec | ||
| import com.squareup.kotlinpoet.TypeVariableName | ||
| import com.squareup.kotlinpoet.asClassName | ||
|
|
||
| /** | ||
| * Generates: `typealias DbBookProjectedCriteriaQuery<PROJECTION> = ProjectedTypeSafeCriteriaQuery<DbBook, *, *, PROJECTION>` | ||
| */ | ||
| internal object ProjectedTypeSafeCriteriaQueryTypeAliasGenerator : YawnTableDefTypeAliasGenerator { | ||
| private val projectionTypeVariable = TypeVariableName("PROJECTION", ANY.copy(nullable = true)) | ||
|
|
||
| override fun getName(entityType: ClassName): String = "${entityType.getUniqueSimpleName()}ProjectedCriteriaQuery" | ||
|
|
||
| override fun getType(entityType: ClassName, tableDefType: ParameterizedTypeName): ParameterizedTypeName { | ||
| return ProjectedTypeSafeCriteriaQuery::class.asClassName().parameterizedBy( | ||
| entityType, | ||
| STAR, | ||
| STAR, | ||
| projectionTypeVariable, | ||
| ) | ||
| } | ||
|
|
||
| override fun TypeAliasSpec.Builder.additionalTypeAliasBuilder(yawnContext: YawnContext): TypeAliasSpec.Builder { | ||
| return addTypeVariable(projectionTypeVariable) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.faire.yawn.generators.typealiases | ||
|
|
||
| import com.faire.ksp.getUniqueSimpleName | ||
| import com.squareup.kotlinpoet.ClassName | ||
| import com.squareup.kotlinpoet.ParameterizedTypeName | ||
|
|
||
| /** | ||
| * Generates: `typealias DbBookTableDefType = DbBookTableDef<DbBook>` | ||
| */ | ||
| internal object TableDefTypeAliasGenerator : YawnTableDefTypeAliasGenerator { | ||
| override fun getName(entityType: ClassName): String = "${entityType.getUniqueSimpleName()}TableDefType" | ||
|
|
||
| override fun getType( | ||
| entityType: ClassName, | ||
| tableDefType: ParameterizedTypeName, | ||
| ): ParameterizedTypeName = tableDefType | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package com.faire.yawn.generators.typealiases | ||
|
|
||
| import com.faire.ksp.getUniqueSimpleName | ||
| import com.faire.yawn.criteria.query.TypeSafeCriteriaQuery | ||
| import com.squareup.kotlinpoet.ClassName | ||
| import com.squareup.kotlinpoet.ParameterizedTypeName | ||
| import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy | ||
| import com.squareup.kotlinpoet.asClassName | ||
|
|
||
| /** | ||
| * Generates: `typealias DbBookCriteriaQuery = TypeSafeCriteriaQuery<DbBook, DbBookTableDef<DbBook>>` | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would it be cleaner to have this be constructed using the previous simpler ones (like
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Depends how deep the nesting goes. As written, I'd expect this is a bit easier to reason, if we leverage the type aliases across the generated code then I would say we should use the aliases.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I thought about this too. I lean towards not nesting the aliases to make it more grokkable for someone trying to determine what resolved type the typealias is aliasing. I think it'll be generally simpler to reason about and easier to maintain if we still with referencing the base types throughout the generated code, and only provide the typealiases for convenience to the end user
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed with this fully! IMO the typealiases should just be convenience, Yawn should use its types directly internally for clarity |
||
| */ | ||
| internal object TypeSafeCriteriaQueryTypeAliasGenerator : YawnTableDefTypeAliasGenerator { | ||
| override fun getName(entityType: ClassName): String = "${entityType.getUniqueSimpleName()}CriteriaQuery" | ||
|
|
||
| override fun getType( | ||
| entityType: ClassName, | ||
| tableDefType: ParameterizedTypeName, | ||
| ): ParameterizedTypeName = TypeSafeCriteriaQuery::class.asClassName().parameterizedBy(entityType, tableDefType) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package com.faire.yawn.generators.typealiases | ||
|
|
||
| import com.faire.ksp.getEffectiveVisibility | ||
| import com.faire.yawn.util.YawnContext | ||
| import com.squareup.kotlinpoet.ClassName | ||
| import com.squareup.kotlinpoet.ParameterizedTypeName | ||
| import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy | ||
| import com.squareup.kotlinpoet.TypeAliasSpec | ||
| import com.squareup.kotlinpoet.ksp.toClassName | ||
|
|
||
| /** | ||
| * [YawnTypeAliasGenerator] for [com.faire.yawn.YawnTableDef]s and related types. | ||
| */ | ||
| internal interface YawnTableDefTypeAliasGenerator : YawnTypeAliasGenerator { | ||
| override fun generate(yawnContext: YawnContext): TypeAliasSpec { | ||
| val entityType = yawnContext.classDeclaration.toClassName() | ||
| val tableDefType = yawnContext.newClassName.parameterizedBy(entityType) | ||
| val visibility = yawnContext.classDeclaration.getEffectiveVisibility() | ||
|
|
||
| val typeAliasName = getName(entityType) | ||
| val typeAliasType = getType(entityType, tableDefType) | ||
|
|
||
| return TypeAliasSpec.builder(typeAliasName, typeAliasType) | ||
| .addModifiers(visibility) | ||
| .additionalTypeAliasBuilder(yawnContext) | ||
| .build() | ||
| } | ||
|
|
||
| fun getName(entityType: ClassName): String | ||
|
|
||
| fun getType(entityType: ClassName, tableDefType: ParameterizedTypeName): ParameterizedTypeName | ||
|
|
||
| fun TypeAliasSpec.Builder.additionalTypeAliasBuilder(yawnContext: YawnContext): TypeAliasSpec.Builder = this | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package com.faire.yawn.generators.typealiases | ||
|
|
||
| import com.faire.yawn.util.YawnContext | ||
| import com.squareup.kotlinpoet.TypeAliasSpec | ||
|
|
||
| /** | ||
| * These typealias generators are used to generate typealiases for generated content. | ||
| * | ||
| * For example, | ||
| * ``` | ||
| * typealias DbBookCriteriaQuery = TypeSafeCriteriaQuery<DbBook, DbBookTableDef<DbBook>> | ||
| * ``` | ||
| */ | ||
| internal interface YawnTypeAliasGenerator { | ||
| fun generate(yawnContext: YawnContext): TypeAliasSpec | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,10 @@ import com.faire.yawn.generators.properties.EmbeddedIdDefGenerator | |
| import com.faire.yawn.generators.properties.JoinColumnDefGenerator | ||
| import com.faire.yawn.generators.properties.JoinColumnDefWithCompositeKeyGenerator | ||
| import com.faire.yawn.generators.properties.JoinColumnDefWithForeignKeyGenerator | ||
| import com.faire.yawn.generators.typealiases.JoinTypeSafeCriteriaQueryTypeAliasGenerator | ||
| import com.faire.yawn.generators.typealiases.ProjectedTypeSafeCriteriaQueryTypeAliasGenerator | ||
| import com.faire.yawn.generators.typealiases.TableDefTypeAliasGenerator | ||
| import com.faire.yawn.generators.typealiases.TypeSafeCriteriaQueryTypeAliasGenerator | ||
| import com.faire.yawn.generators.types.EmbeddedIdTypeGenerator | ||
| import com.faire.yawn.generators.types.EmbeddedTypeGenerator | ||
| import com.faire.yawn.util.YawnContext | ||
|
|
@@ -37,6 +41,7 @@ import com.google.devtools.ksp.processing.SymbolProcessorProvider | |
| import com.google.devtools.ksp.symbol.KSPropertyDeclaration | ||
| import com.squareup.kotlinpoet.ClassName | ||
| import com.squareup.kotlinpoet.PropertySpec | ||
| import com.squareup.kotlinpoet.TypeAliasSpec | ||
| import com.squareup.kotlinpoet.TypeSpec | ||
| import kotlin.reflect.KClass | ||
|
|
||
|
|
@@ -95,6 +100,17 @@ internal class YawnEntityProcessor(codeGenerator: CodeGenerator) : BaseYawnProce | |
| .addTypes(generateEmbeddedDefinitions(yawnContext)) | ||
| } | ||
|
|
||
| override fun generateTypeAliases(yawnContext: YawnContext): List<TypeAliasSpec> { | ||
| val generators = listOf( | ||
| TableDefTypeAliasGenerator, | ||
| TypeSafeCriteriaQueryTypeAliasGenerator, | ||
| ProjectedTypeSafeCriteriaQueryTypeAliasGenerator, | ||
| JoinTypeSafeCriteriaQueryTypeAliasGenerator, | ||
| ) | ||
|
Comment on lines
+104
to
+109
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: This list should be static or a field defintion given it doesn't change and isn't based on the |
||
|
|
||
| return generators.map { it.generate(yawnContext) } | ||
| } | ||
|
|
||
| /** | ||
| * Within the generated table definition, we might need to define subclasses to represent embedded definitions. | ||
| * This will be either fields tagged with @Embedded or composite primary keys tagged with @EmbeddedId. | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,11 @@ | ||||||||||||
| package com.faire.yawn.util | ||||||||||||
|
|
||||||||||||
| import com.squareup.kotlinpoet.FileSpec | ||||||||||||
| import com.squareup.kotlinpoet.TypeAliasSpec | ||||||||||||
|
|
||||||||||||
| internal fun FileSpec.Builder.addTypeAliases(typeAliases: Collection<TypeAliasSpec>): FileSpec.Builder { | ||||||||||||
| for (typeAlias in typeAliases) { | ||||||||||||
| addTypeAlias(typeAlias) | ||||||||||||
| } | ||||||||||||
| return this | ||||||||||||
|
Comment on lines
+7
to
+10
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
though, not sure that's actually cleaner 😓
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally I find the for loop a little easier to grok so gonna leave as-is, lmk if you feel strongly though
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I find this confusing but it might be because my Kotlin brain is too small |
||||||||||||
| } | ||||||||||||
Uh oh!
There was an error while loading. Please reload this page.