diff --git a/bee.persistent.test/datasource.b/src/main/kotlin/com/beeproduced/datasource/b/Entities.kt b/bee.persistent.test/datasource.b/src/main/kotlin/com/beeproduced/datasource/b/Entities.kt index ae12f15..4661a5b 100644 --- a/bee.persistent.test/datasource.b/src/main/kotlin/com/beeproduced/datasource/b/Entities.kt +++ b/bee.persistent.test/datasource.b/src/main/kotlin/com/beeproduced/datasource/b/Entities.kt @@ -10,72 +10,72 @@ import java.util.* * @version 2023-12-16 */ -@Entity -@Inheritance(strategy = InheritanceType.SINGLE_TABLE) -open class Composer( - @Id - val id: UUID, - val name: String -) - -@Entity -data class AiComposer( - override val id: UUID, - override val name: String, - val model: String, - @Embedded - val params: AiParams, - @Column(name = "ai_data_id") - val aiDataId: UUID? = null, - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "ai_data_id", insertable = false, updatable = false) - val aiData: AiData? = null -) : Composer(id, name) - -@Entity -data class AiData( - @Id - val id: UUID, - val data: String -) - -@Embeddable -data class AiParams( - val z1: String, - val z2: String -) - -@Entity -data class HumanComposer( - override val id: UUID, - override val name: String, - val lastname: String, - @Column(name = "human_data_id") - val humanDataId: UUID? = null, - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "human_data_id", insertable = false, updatable = false) - val humanData: HumanData? = null -) : Composer(id, name) - -@Entity -data class HumanData( - @Id - val id: UUID, - val data: String -) - -@Entity -data class ComposerContainer( - @Id - val id: UUID, - @Column(name = "c1_id") - val c1Id: UUID, - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "c1_id", insertable = false, updatable = false) - val c1: Composer?, - @Column(name = "c2_id") - val c2Id: UUID, - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "c2_id", insertable = false, updatable = false) - val c2: Composer? -) \ No newline at end of file +// @Entity +// @Inheritance(strategy = InheritanceType.SINGLE_TABLE) +// open class Composer( +// @Id +// val id: UUID, +// val name: String +// ) +// +// @Entity +// data class AiComposer( +// override val id: UUID, +// override val name: String, +// val model: String, +// @Embedded +// val params: AiParams, +// @Column(name = "ai_data_id") +// val aiDataId: UUID? = null, +// @OneToOne(fetch = FetchType.LAZY) +// @JoinColumn(name = "ai_data_id", insertable = false, updatable = false) +// val aiData: AiData? = null +// ) : Composer(id, name) +// +// @Entity +// data class AiData( +// @Id +// val id: UUID, +// val data: String +// ) +// +// @Embeddable +// data class AiParams( +// val z1: String, +// val z2: String +// ) +// +// @Entity +// data class HumanComposer( +// override val id: UUID, +// override val name: String, +// val lastname: String, +// @Column(name = "human_data_id") +// val humanDataId: UUID? = null, +// @OneToOne(fetch = FetchType.LAZY) +// @JoinColumn(name = "human_data_id", insertable = false, updatable = false) +// val humanData: HumanData? = null +// ) : Composer(id, name) +// +// @Entity +// data class HumanData( +// @Id +// val id: UUID, +// val data: String +// ) +// +// @Entity +// data class ComposerContainer( +// @Id +// val id: UUID, +// @Column(name = "c1_id") +// val c1Id: UUID, +// @OneToOne(fetch = FetchType.LAZY) +// @JoinColumn(name = "c1_id", insertable = false, updatable = false) +// val c1: Composer?, +// @Column(name = "c2_id") +// val c2Id: UUID, +// @OneToOne(fetch = FetchType.LAZY) +// @JoinColumn(name = "c2_id", insertable = false, updatable = false) +// val c2: Composer? +// ) \ No newline at end of file diff --git a/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/BeePersistentBlazeFeature.kt b/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/BeePersistentBlazeFeature.kt index 31a4f07..ad3ddbd 100644 --- a/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/BeePersistentBlazeFeature.kt +++ b/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/BeePersistentBlazeFeature.kt @@ -6,6 +6,8 @@ import com.beeproduced.bee.generative.BeeGenerativeInput import com.beeproduced.bee.generative.Shared import com.beeproduced.bee.generative.processor.Options import com.beeproduced.bee.generative.util.resolveTypeAlias +import com.beeproduced.bee.persistent.blaze.processor.codegen.BeePersistentBlazeConfig +import com.beeproduced.bee.persistent.blaze.processor.codegen.BeePersistentViewCodegen import com.beeproduced.bee.persistent.blaze.processor.info.* import com.beeproduced.bee.persistent.blaze.processor.info.AnnotationInfo.ANNOTATIONS_RELATION import com.beeproduced.bee.persistent.blaze.processor.info.AnnotationInfo.ANNOTATION_EMBEDDED_ID @@ -144,6 +146,16 @@ class BeePersistentBlazeFeature : BeeGenerativeFeature { throw IllegalArgumentException("Entity [${entityInfo.simpleName}] has no ID") } } + + val config = BeePersistentBlazeConfig( + "com.beeproduced.persistent.generated", + 2 + ) + val viewCodeGen = BeePersistentViewCodegen( + input.codeGenerator, input.dependencies, input.logger, + inheritedEntities.values.toList(), config + ) + viewCodeGen.processEntities() } private fun resolveAnnotations(annotations: Sequence): List { diff --git a/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/codegen/BeePersistentViewCodegen.kt b/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/codegen/BeePersistentViewCodegen.kt index 5ac1a90..92af449 100644 --- a/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/codegen/BeePersistentViewCodegen.kt +++ b/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/codegen/BeePersistentViewCodegen.kt @@ -9,6 +9,7 @@ import com.google.devtools.ksp.processing.KSPLogger import com.google.devtools.ksp.symbol.KSType import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.TypeSpec import com.squareup.kotlinpoet.ksp.writeTo /** @@ -27,6 +28,7 @@ class BeePersistentViewCodegen( private val packageName: String = "com.beeproduced.bee.persistent.generated" private val fileName: String = "GeneratedViews" + private val entitiesMap = entities.associateBy { it.qualifiedName!! } private val poetMap: PoetMap = mutableMapOf() private fun FunSpec.Builder.addNStatement(format: String) @@ -36,15 +38,106 @@ class BeePersistentViewCodegen( } - private val viewCount: MutableMap = entities + private fun viewCount(): MutableMap = entities .map { it.qualifiedName!! } .associateWithTo(HashMap()) { 0 } + private fun MutableMap.viewCountReached(entity: EntityInfo): Boolean { + val count = this[entity.qualifiedName!!] ?: return true + return count >= config.depth + } + + private fun MutableMap.incrementViewCount(entity: EntityInfo) { + val count = this[entity.qualifiedName!!] ?: config.depth + this[entity.qualifiedName!!] = count + 1 + } + + private fun MutableMap.viewName(entity: EntityInfo, parent: EntityInfo?): String { + val count = this[entity.qualifiedName!!] ?: config.depth + return "${entity.simpleName}__View__${parent?.simpleName ?: "Root"}__$count" + } + fun processEntities() { FileSpec .builder(packageName, fileName) + .also { + entities.forEach { entity -> + it.processEntity(entity, viewCount()) + } + for ((info, props) in debugInfo) { + logger.info(info) + for (p in props) { + logger.info(" $p") + } + } + } .build() .writeTo(codeGenerator, dependencies) } -} \ No newline at end of file + + private val debugInfo = mutableMapOf>() + + private fun FileSpec.Builder.processEntity( + entity: EntityInfo, viewCount: ViewCount + ): String { + val viewName = viewCount.viewName(entity, null) + + if (!debugInfo.containsKey(viewName)) { + debugInfo[viewName] = mutableSetOf() + } + + //logger.info("View $viewName") + for (relation in entity.relations) { + + // logger.info(relation.toString()) + // logger.info("${relation.simpleName} X ${relation.qualifiedName}") + + val relationEntity = entitiesMap[relation.qualifiedName!!] ?: continue + val relationView = processEntity(relationEntity, viewCount.toMutableMap(), entity) + //logger.info(" View $viewName | ${relation.simpleName} => $relationView") + + if (relationView != null) + debugInfo[viewName]?.add(relationView) + } + + return viewName + } + + private fun FileSpec.Builder.processEntity( + entity: EntityInfo, viewCount: ViewCount, root: EntityInfo + ): String? { + if (viewCount.viewCountReached(entity)) return null + viewCount.incrementViewCount(entity) + val viewName = viewCount.viewName(entity, root) + + if (!debugInfo.containsKey(viewName)) { + debugInfo[viewName] = mutableSetOf() + } + + //logger.info("View $viewName") + for (relation in entity.relations) { + + // logger.info(relation.toString()) + // logger.info("${relation.simpleName} X ${relation.qualifiedName}") + + val relationEntity = entitiesMap[relation.qualifiedName!!] ?: continue + val relationView = processEntity(relationEntity, viewCount.toMutableMap(), root) + //logger.info(" View $viewName | ${relation.simpleName} => $relationView") + + if (relationView != null) + debugInfo[viewName]?.add(relationView) + } + + return viewName + } + + private fun TypeSpec.Builder.buildEntityView(entity: EntityInfo): TypeSpec.Builder { + + + return this + } + +} + +typealias ViewCount = MutableMap \ No newline at end of file diff --git a/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/info/EntityInfo.kt b/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/info/EntityInfo.kt index da2bd8c..4176ef0 100644 --- a/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/info/EntityInfo.kt +++ b/bee.persistent/src/blaze-processor/kotlin/com/beeproduced/bee/persistent/blaze/processor/info/EntityInfo.kt @@ -46,8 +46,10 @@ data class ResolvedValue( interface AbstractProperty { val declaration: KSPropertyDeclaration val type: KSType + val nonCollectionType: KSType val annotations: List val simpleName: String get() = declaration.simpleName.asString() + val qualifiedName: String? get() = nonCollectionType.declaration.qualifiedName?.asString() } interface ValueClassProperty { @@ -59,7 +61,9 @@ data class EntityProperty( override val declaration: KSPropertyDeclaration, override val type: KSType, override val annotations: List -) : AbstractProperty +) : AbstractProperty { + override val nonCollectionType: KSType = getNonNullableSingleRepresentation(type) +} data class IdProperty( override val declaration: KSPropertyDeclaration, @@ -69,9 +73,11 @@ data class IdProperty( val isGenerated: Boolean, val isEmbedded: Boolean, ) : AbstractProperty, ValueClassProperty { + override val nonCollectionType: KSType = getNonNullableSingleRepresentation(type) + fun generatedDefaultValueLiteral(): String { - val typeName = declaration.simpleName.asString() if (type.isMarkedNullable) return "null" + val typeName = nonCollectionType.declaration.simpleName.asString() return when (typeName) { "Double" -> "-1.0" "Float" -> "-1.0F" @@ -100,4 +106,26 @@ data class ColumnProperty( override val type: KSType, override val annotations: List, override val innerValue: ResolvedValue?, -) : AbstractProperty, ValueClassProperty \ No newline at end of file +) : AbstractProperty, ValueClassProperty { + override val nonCollectionType: KSType = getNonNullableSingleRepresentation(type) +} + +fun getNonNullableSingleRepresentation(type: KSType): KSType { + // Check if the type is a generic type with type arguments (like Set) + if (type.arguments.isNotEmpty()) { + // Get the first type argument, e.g., T in Set + val typeArgument = type.arguments.first().type + + // Check if the type argument is non-null + return typeArgument?.resolve()?.let { typeArg -> + if (typeArg.isMarkedNullable) { + // If typeArg is nullable, get its non-nullable counterpart + typeArg.makeNotNullable() + } else { + // If typeArg is already non-nullable, return it as is + typeArg + } + } ?: type + } + return type +} \ No newline at end of file