diff --git a/hll/build.gradle.kts b/hll/build.gradle.kts index 56d55d50ea7..f95d45f5cdd 100644 --- a/hll/build.gradle.kts +++ b/hll/build.gradle.kts @@ -8,6 +8,8 @@ import aws.sdk.kotlin.gradle.kmp.* import org.jetbrains.kotlin.gradle.dsl.JvmTarget description = "High-level libraries for the AWS SDK for Kotlin" +extra["displayName"] = "AWS :: SDK :: Kotlin :: HLL" +extra["moduleName"] = "aws.sdk.kotlin.hll" // FIXME 🔽🔽🔽 This is all copied from :aws-runtime and should be commonized 🔽🔽🔽 @@ -85,8 +87,8 @@ apiValidation { val availableSubprojects = subprojects.map { it.name }.toSet() ignoredProjects += listOf( - "dynamodb-mapper-annotation-processor", + "hll-codegen", "dynamodb-mapper-annotation-processor-test", - "dynamodb-mapper-ops-codegen", + "dynamodb-mapper-codegen", ).filter { it in availableSubprojects } // Some projects may not be in the build depending on bootstrapping } diff --git a/hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/build.gradle.kts b/hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/build.gradle.kts deleted file mode 100644 index 4459c69f9a0..00000000000 --- a/hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/build.gradle.kts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -kotlin { - sourceSets { - jvmMain { - dependencies { - implementation(project(":hll:dynamodb-mapper:dynamodb-mapper-annotations")) - implementation(libs.ksp.api) - } - } - } -} diff --git a/hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/jvm/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/jvm/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider deleted file mode 100644 index 8ddced70565..00000000000 --- a/hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/jvm/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider +++ /dev/null @@ -1 +0,0 @@ -aws.sdk.kotlin.hll.dynamodbmapper.processor.MapperProcessorProvider diff --git a/hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/jvm/src/aws/sdk/kotlin/hll/dynamodbmapper/processor/MapperProcessor.kt b/hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/jvm/src/aws/sdk/kotlin/hll/dynamodbmapper/processor/MapperProcessor.kt deleted file mode 100644 index 14797b5c09e..00000000000 --- a/hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/jvm/src/aws/sdk/kotlin/hll/dynamodbmapper/processor/MapperProcessor.kt +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ -package aws.sdk.kotlin.hll.dynamodbmapper.processor - -import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbAttribute -import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbItem -import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbPartitionKey -import com.google.devtools.ksp.KspExperimental -import com.google.devtools.ksp.getAnnotationsByType -import com.google.devtools.ksp.isAnnotationPresent -import com.google.devtools.ksp.processing.* -import com.google.devtools.ksp.symbol.* -import com.google.devtools.ksp.validate - -private val annotationName = DynamoDbItem::class.qualifiedName!! - -public class MapperProcessor(private val env: SymbolProcessorEnvironment) : SymbolProcessor { - override fun process(resolver: Resolver): List { - env.logger.info("Searching for symbols annotated with $annotationName") - val annotated = resolver.getSymbolsWithAnnotation(annotationName) - val invalid = annotated.filterNot { it.validate() }.toList() - env.logger.info("Found invalid classes $invalid") - - annotated - .toList() - .also { env.logger.info("Found annotated classes: $it") } - .filterIsInstance() - .filter { it.validate() } - .forEach { it.accept(ItemVisitor(), Unit) } - - return invalid - } - - private inner class ItemVisitor : KSVisitorVoid() { - override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) { - val basePackageName = classDeclaration.packageName.asString() - val packageName = "$basePackageName.mapper.schemas" - - val className = classDeclaration.qualifiedName!!.getShortName() - val builderName = "${className}Builder" - val converterName = "${className}Converter" - val schemaName = "${className}Schema" - - val props = classDeclaration.getAllProperties().mapNotNull(Property.Companion::from) - val keyProp = checkNotNull(props.singleOrNull { it.isPk }) { - "Expected exactly one @DynamoDbPartitionKey annotation on a property" - } - - env.codeGenerator.createNewFile( - Dependencies(true, classDeclaration.containingFile!!), - packageName, - schemaName, - ).use { file -> - file.bufferedWriter().use { writer -> - writer.append( - """ - |package $packageName - | - |import aws.sdk.kotlin.hll.dynamodbmapper.* - |import aws.sdk.kotlin.hll.dynamodbmapper.items.* - |import aws.sdk.kotlin.hll.dynamodbmapper.model.* - |import aws.sdk.kotlin.hll.dynamodbmapper.values.* - |import $basePackageName.$className - | - |public class $builderName { - ${generateProperties(props)} - | ${generateBuildMethod(className, props)} - |} - | - |public object $converterName : ItemConverter<$className> by SimpleItemConverter( - | builderFactory = ::$builderName, - | build = $builderName::build, - | descriptors = arrayOf( - ${generateDescriptors(className, builderName, props)} - | ), - |) - | - |public object $schemaName : ItemSchema.PartitionKey<$className, ${keyProp.typeName.getShortName()}> { - | override val converter: $converterName = $converterName - | override val partitionKey: KeySpec<${keyProp.keySpecType}> = ${generateKeySpec(keyProp)} - |} - | - |public fun DynamoDbMapper.get${className}Table(name: String): Table.PartitionKey<$className, ${keyProp.typeName.getShortName()}> = getTable(name, $schemaName) - | - """.trimMargin(), - ) - } - } - } - - private fun generateBuildMethod(className: String, props: Sequence) = - buildString { - appendLine("public fun build(): $className {") - - props.forEach { prop -> - appendLine(""" val ${prop.name} = requireNotNull(${prop.name}) { "Missing value for $className.${prop.name}" }""") - } - - appendLine() - - append(" return $className(") - append(props.joinToString(", ") { it.name }) - appendLine(")") - - appendLine(" }") - }.trimEnd() - - private fun generateDescriptors( - className: String, - builderName: String, - props: Sequence, - ) = buildString { - props.forEach { prop -> - val converterType = when (val fqTypeName = prop.typeName.asString()) { - "aws.smithy.kotlin.runtime.time.Instant" -> "InstantConverter.Default" - "kotlin.Boolean" -> "BooleanConverter" - "kotlin.Int" -> "IntConverter" - "kotlin.String" -> "StringConverter" - else -> error("Unsupported attribute type $fqTypeName") - } - - append("| AttributeDescriptor(") - - // key - append("\"") - append(prop.ddbName) - append("\", ") - - // getter - append(className) - append("::") - append(prop.name) - append(", ") - - // setter - append(builderName) - append("::") - append(prop.name) - append("::set, ") - - // converter - append(converterType) - - appendLine("),") - } - }.trimEnd() - - private fun generateKeySpec(keyProp: Property) = buildString { - append("KeySpec.") - append(keyProp.keySpecType) - append("(\"") - append(keyProp.name) - append("\")") - } - - private fun generateProperties(props: Sequence) = buildString { - props.forEach { prop -> - append("| public var ") - append(prop.name) - append(": ") - append(prop.typeName.asString()) - appendLine("? = null") - } - } - } -} - -private data class Property(val name: String, val ddbName: String, val typeName: KSName, val isPk: Boolean) { - companion object { - @OptIn(KspExperimental::class) - fun from(ksProperty: KSPropertyDeclaration) = ksProperty - .getter - ?.returnType - ?.resolve() - ?.declaration - ?.qualifiedName - ?.let { typeName -> - val isPk = ksProperty.isAnnotationPresent(DynamoDbPartitionKey::class) - val name = ksProperty.simpleName.getShortName() - val ddbName = ksProperty.getAnnotationsByType(DynamoDbAttribute::class).singleOrNull()?.name ?: name - Property(name, ddbName, typeName, isPk) - } - } -} - -private val Property.keySpecType: String - get() = when (val fqTypeName = typeName.asString()) { - "kotlin.Int" -> "Number" - "kotlin.String" -> "String" - else -> error("Unsupported key type $fqTypeName, expected Int or String") - } diff --git a/hll/dynamodb-mapper/dynamodb-mapper-codegen/build.gradle.kts b/hll/dynamodb-mapper/dynamodb-mapper-codegen/build.gradle.kts new file mode 100644 index 00000000000..03359aece14 --- /dev/null +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/build.gradle.kts @@ -0,0 +1,24 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +description = "DynamoDbMapper code generation" +extra["displayName"] = "AWS :: SDK :: Kotlin :: HLL :: DynamoDbMapper :: Codegen" +extra["moduleName"] = "aws.sdk.kotlin.hll.dynamodbmapper.codegen" + +plugins { + alias(libs.plugins.kotlin.jvm) +} + +dependencies { + implementation(libs.ksp.api) + implementation(project(":hll:hll-codegen")) + implementation(project(":hll:dynamodb-mapper:dynamodb-mapper-annotations")) + implementation(project(":services:dynamodb")) + + testImplementation(libs.junit.jupiter) + testImplementation(libs.junit.jupiter.params) + testImplementation(libs.kotest.assertions.core.jvm) + testImplementation(libs.kotlin.test.junit5) +} diff --git a/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/AnnotationsProcessor.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/AnnotationsProcessor.kt new file mode 100644 index 00000000000..665e902de2f --- /dev/null +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/AnnotationsProcessor.kt @@ -0,0 +1,43 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations + +import aws.sdk.kotlin.hll.codegen.core.CodeGeneratorFactory +import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbItem +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations.rendering.HighLevelRenderer +import com.google.devtools.ksp.processing.* +import com.google.devtools.ksp.symbol.* +import com.google.devtools.ksp.validate + +private val annotationName = DynamoDbItem::class.qualifiedName!! + +class AnnotationsProcessor(private val environment: SymbolProcessorEnvironment) : SymbolProcessor { + private var invoked = false + private val logger = environment.logger + private val codeGenerator = environment.codeGenerator + private val codeGeneratorFactory = CodeGeneratorFactory(codeGenerator, logger) + + override fun process(resolver: Resolver): List { + if (invoked) { + return listOf() + } + invoked = true + + logger.info("Searching for symbols annotated with $annotationName") + val annotated = resolver.getSymbolsWithAnnotation(annotationName) + val invalid = annotated.filterNot { it.validate() }.toList() + logger.info("Found invalid classes $invalid") + + val annotatedClasses = annotated + .toList() + .also { logger.info("Found annotated classes: $it") } + .filterIsInstance() + .filter { it.validate() } + + HighLevelRenderer(annotatedClasses, logger, codeGeneratorFactory).render() + + return invalid + } +} diff --git a/hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/jvm/src/aws/sdk/kotlin/hll/dynamodbmapper/processor/MapperProcessorProvider.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/AnnotationsProcessorProvider.kt similarity index 63% rename from hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/jvm/src/aws/sdk/kotlin/hll/dynamodbmapper/processor/MapperProcessorProvider.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/AnnotationsProcessorProvider.kt index 4fa71cdf457..1ba9242ab9b 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-annotation-processor/jvm/src/aws/sdk/kotlin/hll/dynamodbmapper/processor/MapperProcessorProvider.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/AnnotationsProcessorProvider.kt @@ -2,11 +2,11 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.processor +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations import com.google.devtools.ksp.processing.SymbolProcessorEnvironment import com.google.devtools.ksp.processing.SymbolProcessorProvider -public class MapperProcessorProvider : SymbolProcessorProvider { - override fun create(environment: SymbolProcessorEnvironment): MapperProcessor = MapperProcessor(environment) +class AnnotationsProcessorProvider : SymbolProcessorProvider { + override fun create(environment: SymbolProcessorEnvironment): AnnotationsProcessor = AnnotationsProcessor(environment) } diff --git a/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/rendering/HighLevelRenderer.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/rendering/HighLevelRenderer.kt new file mode 100644 index 00000000000..ea2bfd2b949 --- /dev/null +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/rendering/HighLevelRenderer.kt @@ -0,0 +1,29 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations.rendering + +import aws.sdk.kotlin.hll.codegen.core.CodeGeneratorFactory +import aws.sdk.kotlin.hll.codegen.rendering.RenderContext +import com.google.devtools.ksp.processing.KSPLogger +import com.google.devtools.ksp.symbol.KSClassDeclaration + +/** + * The parent renderer for all codegen from this package. This class orchestrates the various sub-renderers. + * @param annotatedClasses A list of annotated classes + */ +class HighLevelRenderer( + private val annotatedClasses: List, + private val logger: KSPLogger, + private val codegenFactory: CodeGeneratorFactory, +) { + fun render() { + annotatedClasses.forEach { + logger.info("Processing annotation on ${it.simpleName}") + val renderCtx = RenderContext(logger, codegenFactory, "${it.packageName.asString()}.mapper.schemas", "dynamodb-mapper-annotation-processor") + val annotation = SchemaRenderer(it, renderCtx) + annotation.render() + } + } +} diff --git a/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/rendering/SchemaRenderer.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/rendering/SchemaRenderer.kt new file mode 100644 index 00000000000..e491e508341 --- /dev/null +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/rendering/SchemaRenderer.kt @@ -0,0 +1,147 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations.rendering + +import aws.sdk.kotlin.hll.codegen.model.Member +import aws.sdk.kotlin.hll.codegen.model.Type +import aws.sdk.kotlin.hll.codegen.model.TypeRef +import aws.sdk.kotlin.hll.codegen.model.Types +import aws.sdk.kotlin.hll.codegen.rendering.BuilderRenderer +import aws.sdk.kotlin.hll.codegen.rendering.RenderContext +import aws.sdk.kotlin.hll.codegen.rendering.RendererBase +import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbAttribute +import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbPartitionKey +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.MapperTypes +import com.google.devtools.ksp.KspExperimental +import com.google.devtools.ksp.getAnnotationsByType +import com.google.devtools.ksp.isAnnotationPresent +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSName +import com.google.devtools.ksp.symbol.KSPropertyDeclaration + +/** + * Renders the classes and objects required to make a class usable with the DynamoDbMapper such as schemas, builders, and converters. + * @param classDeclaration the [KSClassDeclaration] of the class + * @param ctx the [RenderContext] of the renderer + */ +class SchemaRenderer( + private val classDeclaration: KSClassDeclaration, + private val ctx: RenderContext, +) : RendererBase(ctx, "${classDeclaration.qualifiedName!!.getShortName()}Schema") { + private val className = classDeclaration.qualifiedName!!.getShortName() + private val classType = Type.from(classDeclaration) + + private val builderName = "${className}Builder" + private val converterName = "${className}Converter" + private val schemaName = "${className}Schema" + + private val properties = classDeclaration.getAllProperties().mapNotNull(AnnotatedClassProperty.Companion::from) + private val keyProperty = checkNotNull(properties.singleOrNull { it.isPk }) { + "Expected exactly one @DynamoDbPartitionKey annotation on a property" + } + + override fun generate() { + renderBuilder() + renderItemConverter() + renderSchema() + renderGetTable() + } + + private fun renderBuilder() { + // TODO Not all classes need builders generated (i.e. the class consists of all public mutable members), add configurability here + val members = classDeclaration.getAllProperties().map(Member.Companion::from).toSet() + BuilderRenderer(this, classType, members).render() + } + + private fun renderItemConverter() { + withBlock("public object #L : #T by #T(", ")", converterName, MapperTypes.Items.itemConverter(classType), MapperTypes.Items.SimpleItemConverter) { + write("builderFactory = ::#L,", builderName) + write("build = #L::build,", builderName) + withBlock("descriptors = arrayOf(", "),") { + properties.forEach { + renderAttributeDescriptor(it) + } + } + } + blankLine() + } + + private fun renderAttributeDescriptor(prop: AnnotatedClassProperty) { + withBlock("#T(", "),", MapperTypes.Items.AttributeDescriptor) { + write("#S,", prop.ddbName) // key + write("#L,", "$className::${prop.name}") // getter + write("#L,", "$builderName::${prop.name}::set") // setter + write("#T", prop.valueConverter) // converter + } + } + + private val AnnotatedClassProperty.valueConverter: Type + get() = when (typeName.asString()) { + "aws.smithy.kotlin.runtime.time.Instant" -> MapperTypes.Values.DefaultInstantConverter + "kotlin.Boolean" -> MapperTypes.Values.BooleanConverter + "kotlin.Int" -> MapperTypes.Values.IntConverter + "kotlin.String" -> MapperTypes.Values.StringConverter + // TODO Add additional "standard" item converters + else -> error("Unsupported attribute type ${typeName.asString()}") + } + + private fun renderSchema() { + withBlock("public object #L : #T {", "}", schemaName, MapperTypes.Items.itemSchemaPartitionKey(classType, keyProperty.typeRef)) { + write("override val converter : #1L = #1L", converterName) + // TODO Handle composite keys + write("override val partitionKey: #T = #T(#S)", MapperTypes.Items.keySpec(keyProperty.keySpec), keyProperty.keySpecType, keyProperty.name) + } + blankLine() + } + + private val AnnotatedClassProperty.keySpec: TypeRef + get() = when (typeName.asString()) { + "kotlin.Int" -> Types.Kotlin.Number + "kotlin.String" -> Types.Kotlin.String + // TODO Handle ByteArray + else -> error("Unsupported key type ${typeName.asString()}, expected Int or String") + } + + private val AnnotatedClassProperty.keySpecType: TypeRef + get() = when (typeName.asString()) { + "kotlin.Int" -> MapperTypes.Items.KeySpecNumber + "kotlin.String" -> MapperTypes.Items.KeySpecString + // TODO Handle ByteArray + else -> error("Unsupported key type ${typeName.asString()}, expected Int or String") + } + + private fun renderGetTable() { + docs("Returns a reference to a table named [name] containing items representing [#T]", classType) + + val fnName = "get${className}Table" + write( + "public fun #T.#L(name: String): #T = #L(name, #L)", + MapperTypes.DynamoDbMapper, + fnName, + MapperTypes.Model.tablePartitionKey(classType, keyProperty.typeRef), + "getTable", + schemaName, + ) + } +} + +private data class AnnotatedClassProperty(val name: String, val typeRef: TypeRef, val ddbName: String, val typeName: KSName, val isPk: Boolean) { + companion object { + @OptIn(KspExperimental::class) + fun from(ksProperty: KSPropertyDeclaration) = ksProperty + .getter + ?.returnType + ?.resolve() + ?.declaration + ?.qualifiedName + ?.let { typeName -> + val isPk = ksProperty.isAnnotationPresent(DynamoDbPartitionKey::class) + val name = ksProperty.simpleName.getShortName() + val typeRef = Type.from(checkNotNull(ksProperty.type) { "Failed to determine class type for $name" }) + val ddbName = ksProperty.getAnnotationsByType(DynamoDbAttribute::class).singleOrNull()?.name ?: name + AnnotatedClassProperty(name, typeRef, ddbName, typeName, isPk) + } + } +} diff --git a/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/MapperTypes.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/MapperTypes.kt new file mode 100644 index 00000000000..429ca345b3a --- /dev/null +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/MapperTypes.kt @@ -0,0 +1,52 @@ +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.model + +import aws.sdk.kotlin.hll.codegen.model.Type +import aws.sdk.kotlin.hll.codegen.model.TypeRef +import aws.sdk.kotlin.hll.codegen.model.TypeVar +import aws.sdk.kotlin.hll.codegen.model.Types +import aws.sdk.kotlin.hll.codegen.util.Pkg + +/** + * A container object for various DynamoDbMapper [Type] instances + */ +object MapperTypes { + // Low-level types + val AttributeValue = TypeRef(Pkg.Ll.Model, "AttributeValue") + val AttributeMap = Types.Kotlin.map(Types.Kotlin.String, AttributeValue) + + // High-level types + val DynamoDbMapper = TypeRef(Pkg.Hl.Base, "DynamoDbMapper") + + object Items { + fun itemSchema(typeVar: String) = TypeRef(Pkg.Hl.Items, "ItemSchema", listOf(TypeVar(typeVar))) + fun itemSchemaPartitionKey(objectType: TypeRef, keyType: TypeRef) = TypeRef(Pkg.Hl.Items, "ItemSchema.PartitionKey", listOf(objectType, keyType)) + fun keySpec(keyType: TypeRef) = TypeRef(Pkg.Hl.Items, "KeySpec", genericArgs = listOf(keyType)) + val KeySpecNumber = TypeRef(Pkg.Hl.Items, "KeySpec.Number") + val KeySpecString = TypeRef(Pkg.Hl.Items, "KeySpec.String") + val AttributeDescriptor = TypeRef(Pkg.Hl.Items, "AttributeDescriptor") + fun itemConverter(objectType: TypeRef) = TypeRef(Pkg.Hl.Items, "ItemConverter", genericArgs = listOf(objectType)) + val SimpleItemConverter = TypeRef(Pkg.Hl.Items, "SimpleItemConverter") + } + + object Model { + fun tablePartitionKey(objectType: TypeRef, keyType: TypeRef) = TypeRef( + Pkg.Hl.Model, + "Table.PartitionKey", + genericArgs = listOf(objectType, keyType), + ) + val toItem = TypeRef(Pkg.Hl.Model, "toItem") + } + + object Values { + val DefaultInstantConverter = TypeRef(Pkg.Hl.Values, "InstantConverter.Default") + val BooleanConverter = TypeRef(Pkg.Hl.Values, "BooleanConverter") + val IntConverter = TypeRef(Pkg.Hl.Values, "IntConverter") + val StringConverter = TypeRef(Pkg.Hl.Values, "StringConverter") + } + + object PipelineImpl { + val HReqContextImpl = TypeRef(Pkg.Hl.PipelineImpl, "HReqContextImpl") + val MapperContextImpl = TypeRef(Pkg.Hl.PipelineImpl, "MapperContextImpl") + val Operation = TypeRef(Pkg.Hl.PipelineImpl, "Operation") + } +} diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/HighLevelOpsProcessor.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/HighLevelOpsProcessor.kt similarity index 78% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/HighLevelOpsProcessor.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/HighLevelOpsProcessor.kt index 4f5ea63db50..83c5aab8db8 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/HighLevelOpsProcessor.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/HighLevelOpsProcessor.kt @@ -2,14 +2,14 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen - -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.core.CodeGeneratorFactory -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.Operation -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.toHighLevel -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.rendering.HighLevelRenderer -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.rendering.RenderContext -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.util.Pkg +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations + +import aws.sdk.kotlin.hll.codegen.core.CodeGeneratorFactory +import aws.sdk.kotlin.hll.codegen.rendering.RenderContext +import aws.sdk.kotlin.hll.codegen.util.Pkg +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model.Operation +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model.toHighLevel +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.rendering.HighLevelRenderer import aws.sdk.kotlin.services.dynamodb.DynamoDbClient import com.google.devtools.ksp.getClassDeclarationByName import com.google.devtools.ksp.getDeclaredFunctions @@ -37,7 +37,7 @@ class HighLevelOpsProcessor(environment: SymbolProcessorEnvironment) : SymbolPro val operations = getOperations(resolver) val codegenFactory = CodeGeneratorFactory(codeGenerator, logger) - val ctx = RenderContext(logger, codegenFactory, pkg) + val ctx = RenderContext(logger, codegenFactory, pkg, "dynamodb-mapper-ops-codegen") HighLevelRenderer(ctx, operations).render() } diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/HighLevelOpsProcessorProvider.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/HighLevelOpsProcessorProvider.kt similarity index 91% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/HighLevelOpsProcessorProvider.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/HighLevelOpsProcessorProvider.kt index 3d965f7d77d..1b3b9611d44 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/HighLevelOpsProcessorProvider.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/HighLevelOpsProcessorProvider.kt @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations import com.google.devtools.ksp.processing.SymbolProcessor import com.google.devtools.ksp.processing.SymbolProcessorEnvironment diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/ItemSourceKind.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/ItemSourceKind.kt similarity index 89% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/ItemSourceKind.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/ItemSourceKind.kt index f40be22e339..5e6675b715f 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/ItemSourceKind.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/ItemSourceKind.kt @@ -2,9 +2,11 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.model +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.util.Pkg +import aws.sdk.kotlin.hll.codegen.model.TypeRef +import aws.sdk.kotlin.hll.codegen.model.TypeVar +import aws.sdk.kotlin.hll.codegen.util.Pkg /** * Identifies a type in the `ItemSource` hierarchy diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/MemberCodegenBehavior.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/MemberCodegenBehavior.kt similarity index 73% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/MemberCodegenBehavior.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/MemberCodegenBehavior.kt index f192b0ef472..69e279c4103 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/MemberCodegenBehavior.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/MemberCodegenBehavior.kt @@ -2,11 +2,16 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.model +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.util.Pkg +import aws.sdk.kotlin.hll.codegen.model.Member +import aws.sdk.kotlin.hll.codegen.model.TypeRef +import aws.sdk.kotlin.hll.codegen.model.Types +import aws.sdk.kotlin.hll.codegen.model.nullable +import aws.sdk.kotlin.hll.codegen.util.Pkg +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.MapperTypes -private val attrMapTypes = setOf(Types.AttributeMap, Types.AttributeMap.nullable()) +private val attrMapTypes = setOf(MapperTypes.AttributeMap, MapperTypes.AttributeMap.nullable()) /** * Describes a behavior to apply for a given [Member] in a low-level structure when generating code for an equivalent @@ -74,37 +79,37 @@ val Member.codegenBehavior: MemberCodegenBehavior } private val Member.isTableName: Boolean - get() = name == "tableName" && type == Types.StringNullable + get() = name == "tableName" && type == Types.Kotlin.StringNullable private val Member.isIndexName: Boolean - get() = name == "indexName" && type == Types.StringNullable + get() = name == "indexName" && type == Types.Kotlin.StringNullable private fun llType(name: String) = TypeRef(Pkg.Ll.Model, name) private val unsupportedMembers = listOf( // superseded by ConditionExpression Member("conditionalOperator", llType("ConditionalOperator")), - Member("expected", Type.stringMap(llType("ExpectedAttributeValue"))), + Member("expected", Types.Kotlin.stringMap(llType("ExpectedAttributeValue"))), // superseded by FilterExpression - Member("queryFilter", Type.stringMap(llType("Condition"))), - Member("scanFilter", Type.stringMap(llType("Condition"))), + Member("queryFilter", Types.Kotlin.stringMap(llType("Condition"))), + Member("scanFilter", Types.Kotlin.stringMap(llType("Condition"))), // superseded by KeyConditionExpression - Member("keyConditions", Type.stringMap(llType("Condition"))), + Member("keyConditions", Types.Kotlin.stringMap(llType("Condition"))), // superseded by ProjectionExpression - Member("attributesToGet", Type.list(Types.String)), + Member("attributesToGet", Types.Kotlin.list(Types.Kotlin.String)), // superseded by UpdateExpression - Member("attributeUpdates", Type.stringMap(llType("AttributeValueUpdate"))), + Member("attributeUpdates", Types.Kotlin.stringMap(llType("AttributeValueUpdate"))), // TODO add support for expressions - Member("expressionAttributeNames", Type.stringMap(Types.String)), - Member("expressionAttributeValues", Types.AttributeMap), - Member("conditionExpression", Types.String), - Member("projectionExpression", Types.String), - Member("updateExpression", Types.String), + Member("expressionAttributeNames", Types.Kotlin.stringMap(Types.Kotlin.String)), + Member("expressionAttributeValues", MapperTypes.AttributeMap), + Member("conditionExpression", Types.Kotlin.String), + Member("projectionExpression", Types.Kotlin.String), + Member("updateExpression", Types.Kotlin.String), ).map { member -> if (member.type is TypeRef) { member.copy(type = member.type.nullable()) diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/ModelAttributes.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/ModelAttributes.kt similarity index 92% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/ModelAttributes.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/ModelAttributes.kt index 55bbdaf1f5d..289f38edc92 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/ModelAttributes.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/ModelAttributes.kt @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.model +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model import aws.smithy.kotlin.runtime.collections.AttributeKey diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Operation.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/Operation.kt similarity index 92% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Operation.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/Operation.kt index cdbc08a1261..50737536822 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Operation.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/Operation.kt @@ -2,10 +2,10 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.model +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.util.capitalizeFirstChar -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.util.plus +import aws.sdk.kotlin.hll.codegen.util.capitalizeFirstChar +import aws.sdk.kotlin.hll.codegen.util.plus import aws.smithy.kotlin.runtime.collections.Attributes import aws.smithy.kotlin.runtime.collections.emptyAttributes import aws.smithy.kotlin.runtime.collections.get diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Structure.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/Structure.kt similarity index 87% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Structure.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/Structure.kt index 5d1198ecd42..dd4e3e12481 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Structure.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/Structure.kt @@ -2,9 +2,13 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.model +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.util.plus +import aws.sdk.kotlin.hll.codegen.model.Member +import aws.sdk.kotlin.hll.codegen.model.Type +import aws.sdk.kotlin.hll.codegen.model.TypeRef +import aws.sdk.kotlin.hll.codegen.model.TypeVar +import aws.sdk.kotlin.hll.codegen.util.plus import aws.smithy.kotlin.runtime.collections.Attributes import aws.smithy.kotlin.runtime.collections.emptyAttributes import aws.smithy.kotlin.runtime.collections.get @@ -31,7 +35,7 @@ data class Structure( type = Type.from(ksTypeRef), members = (ksTypeRef.resolve().declaration as KSClassDeclaration) .getDeclaredProperties() - .map(Member::from) + .map(Member.Companion::from) .toList(), ) } diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/DataTypeGenerator.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/DataTypeGenerator.kt similarity index 88% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/DataTypeGenerator.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/DataTypeGenerator.kt index d50ac5a1e35..b310a7db075 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/DataTypeGenerator.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/DataTypeGenerator.kt @@ -2,12 +2,15 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.core +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.rendering -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.* -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.Member -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.Structure -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.rendering.RenderContext +import aws.sdk.kotlin.hll.codegen.core.CodeGenerator +import aws.sdk.kotlin.hll.codegen.model.Member +import aws.sdk.kotlin.hll.codegen.model.Type +import aws.sdk.kotlin.hll.codegen.model.TypeRef +import aws.sdk.kotlin.hll.codegen.model.TypeVar +import aws.sdk.kotlin.hll.codegen.rendering.RenderContext +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model.Structure /** * Generates immutable data types from a [Structure] into an underlying [CodeGenerator]. These data types consist of a diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/HighLevelRenderer.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/HighLevelRenderer.kt similarity index 71% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/HighLevelRenderer.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/HighLevelRenderer.kt index bb86dc24b77..b8ea097d7cb 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/HighLevelRenderer.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/HighLevelRenderer.kt @@ -2,12 +2,13 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.rendering +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.rendering -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.ItemSourceKind -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.Operation -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.Type -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.itemSourceKinds +import aws.sdk.kotlin.hll.codegen.model.Type +import aws.sdk.kotlin.hll.codegen.rendering.RenderContext +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model.ItemSourceKind +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model.Operation +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model.itemSourceKinds /** * The parent renderer for all codegen from this package. This class orchestrates the various sub-renderers. diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/OperationRenderer.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/OperationRenderer.kt similarity index 85% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/OperationRenderer.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/OperationRenderer.kt index 365919f75df..24e199996ab 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/OperationRenderer.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/OperationRenderer.kt @@ -2,11 +2,15 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.rendering +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.rendering -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.core.DataTypeGenerator -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.core.ImportDirective -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.* +import aws.sdk.kotlin.hll.codegen.core.* +import aws.sdk.kotlin.hll.codegen.model.Member +import aws.sdk.kotlin.hll.codegen.rendering.RenderContext +import aws.sdk.kotlin.hll.codegen.rendering.RendererBase +import aws.sdk.kotlin.hll.codegen.rendering.info +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.MapperTypes +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model.* // FIXME handle paginated operations differently (e.g., don't map pagination parameters, provide only Flow API) @@ -46,13 +50,13 @@ class OperationRenderer( ")", factoryName, itemSourceKind.getSpecType("T"), - Types.Operation, + MapperTypes.PipelineImpl.Operation, ) { write( "initialize = { highLevelReq: #T -> #T(highLevelReq, spec.schema, #T(spec, #S)) },", operation.request.type, - Types.HReqContextImpl, - Types.MapperContextImpl, + MapperTypes.PipelineImpl.HReqContextImpl, + MapperTypes.PipelineImpl.MapperContextImpl, operation.name, ) @@ -82,7 +86,7 @@ class OperationRenderer( openBlock("private fun #T.convert(", operation.request.type) members(MemberCodegenBehavior.Hoist) { write("#L: #T, ", name, type) } - write("schema: #T,", Types.itemSchema("T")) + write("schema: #T,", MapperTypes.Items.itemSchema("T")) closeAndOpenBlock(") = #L {", operation.request.lowLevelName) members(MemberCodegenBehavior.PassThrough) { write("#1L = this@convert.#1L", name) } members(MemberCodegenBehavior.MapKeys) { @@ -110,13 +114,13 @@ class OperationRenderer( "private fun #L.convert(schema: #T) = #T(", ")", operation.response.lowLevelName, - Types.itemSchema("T"), + MapperTypes.Items.itemSchema("T"), operation.response.type, ) { members(MemberCodegenBehavior.PassThrough) { write("#1L = this@convert.#1L,", name) } members(MemberCodegenBehavior.MapKeys, MemberCodegenBehavior.MapAll) { - write("#1L = this@convert.#1L?.#2T()?.let(schema.converter::fromItem),", name, Types.toItem) + write("#1L = this@convert.#1L?.#2T()?.let(schema.converter::fromItem),", name, MapperTypes.Model.toItem) } } } diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/OperationsTypeRenderer.kt b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/OperationsTypeRenderer.kt similarity index 84% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/OperationsTypeRenderer.kt rename to hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/OperationsTypeRenderer.kt index e39a3d51de7..0f05ad1607f 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/OperationsTypeRenderer.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/OperationsTypeRenderer.kt @@ -2,10 +2,17 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.rendering +package aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.rendering -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.* -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.util.lowercaseFirstChar +import aws.sdk.kotlin.hll.codegen.model.Type +import aws.sdk.kotlin.hll.codegen.model.TypeRef +import aws.sdk.kotlin.hll.codegen.model.TypeVar +import aws.sdk.kotlin.hll.codegen.rendering.RenderContext +import aws.sdk.kotlin.hll.codegen.rendering.RendererBase +import aws.sdk.kotlin.hll.codegen.util.lowercaseFirstChar +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model.ItemSourceKind +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model.Operation +import aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.model.itemSourceKinds /** * Renders the `*Operations` interface and `*OperationsImpl` class which contain a method for each codegenned diff --git a/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider new file mode 100644 index 00000000000..59a8692f0a6 --- /dev/null +++ b/hll/dynamodb-mapper/dynamodb-mapper-codegen/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider @@ -0,0 +1,3 @@ +aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.HighLevelOpsProcessorProvider +aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations.AnnotationsProcessorProvider + diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider deleted file mode 100644 index 15972df9b3f..00000000000 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider +++ /dev/null @@ -1 +0,0 @@ -aws.sdk.kotlin.hll.dynamodbmapper.codegen.HighLevelOpsProcessorProvider diff --git a/hll/dynamodb-mapper/dynamodb-mapper/build.gradle.kts b/hll/dynamodb-mapper/dynamodb-mapper/build.gradle.kts index 9a51b2f87cd..ecb3b10eb7a 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper/build.gradle.kts +++ b/hll/dynamodb-mapper/dynamodb-mapper/build.gradle.kts @@ -58,12 +58,14 @@ ksp { "scan", ) arg("op-allowlist", allowlist.joinToString(";")) + + excludeProcessor("aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations.AnnotationsProcessor") } if (project.NATIVE_ENABLED) { // Configure KSP for commonMain source generation; https://github.com/google/ksp/issues/963#issuecomment-1894144639 - dependencies.kspCommonMainMetadata(project(":hll:dynamodb-mapper:dynamodb-mapper-ops-codegen")) + dependencies.kspCommonMainMetadata(project(":hll:dynamodb-mapper:dynamodb-mapper-codegen")) kotlin.sourceSets.commonMain { tasks.withType { @@ -76,7 +78,7 @@ if (project.NATIVE_ENABLED) { // hack follows in narrative, minimally-opinionated comments. // Start by invoking the JVM-only KSP configuration - dependencies.kspJvm(project(":hll:dynamodb-mapper:dynamodb-mapper-ops-codegen")) + dependencies.kspJvm(project(":hll:dynamodb-mapper:dynamodb-mapper-codegen")) // Then we need to move the generated source from jvm to common. Gradle lacks a move task so we roll our own! val moveGenSrc by tasks.registering { diff --git a/hll/dynamodb-mapper/tests/dynamodb-mapper-annotation-processor-test/build.gradle.kts b/hll/dynamodb-mapper/tests/dynamodb-mapper-annotation-processor-test/build.gradle.kts index bb38d584747..6b5a4a097a7 100644 --- a/hll/dynamodb-mapper/tests/dynamodb-mapper-annotation-processor-test/build.gradle.kts +++ b/hll/dynamodb-mapper/tests/dynamodb-mapper-annotation-processor-test/build.gradle.kts @@ -22,5 +22,10 @@ dependencies { listOf( "kspCommonMainMetadata", "kspJvm", // FIXME Generating common code is hard for KSP: https://github.com/google/ksp/issues/567 - ).forEach { configuration -> add(configuration, project(":hll:dynamodb-mapper:dynamodb-mapper-annotation-processor")) } + ).forEach { configuration -> add(configuration, project(":hll:dynamodb-mapper:dynamodb-mapper-codegen")) } +} + +ksp { + // annotation-processor-test does not need the ops-codegen processor loaded + excludeProcessor("aws.sdk.kotlin.hll.dynamodbmapper.codegen.operations.HighLevelOpsProcessorProvider") } diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/build.gradle.kts b/hll/hll-codegen/build.gradle.kts similarity index 60% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/build.gradle.kts rename to hll/hll-codegen/build.gradle.kts index 783dfd4ec8e..78417ffe548 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/build.gradle.kts +++ b/hll/hll-codegen/build.gradle.kts @@ -3,13 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ +description = "Common code-generation utilities used by AWS SDK for Kotlin's high level libraries" +extra["displayName"] = "AWS :: SDK :: Kotlin :: HLL :: Codegen" +extra["moduleName"] = "aws.sdk.kotlin.hll.codegen" + plugins { alias(libs.plugins.kotlin.jvm) } dependencies { implementation(libs.ksp.api) - implementation(project(":services:dynamodb")) + implementation(libs.smithy.kotlin.runtime.core) testImplementation(libs.junit.jupiter) testImplementation(libs.junit.jupiter.params) diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/CodeGenerator.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/CodeGenerator.kt similarity index 94% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/CodeGenerator.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/CodeGenerator.kt index 4a674776e8a..346599e6c73 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/CodeGenerator.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/CodeGenerator.kt @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.core +package aws.sdk.kotlin.hll.codegen.core private const val INDENT = " " @@ -105,6 +105,13 @@ interface CodeGenerator { */ fun withDocs(block: () -> Unit) + /** + * Writes a single line of documentation, wrapping it with KDoc-style comment tokens. + * @param template The templated string of documentation to write + * @param args The arguments to the templated string, if any + */ + fun docs(template: String, vararg args: Any) + /** * Writes a line of text, including a terminating newline (i.e., `\n`) * @param template The string template or literal to append @@ -151,6 +158,7 @@ class CodeGeneratorImpl( private val engine: TemplateEngine, private val persistCallback: (String) -> Unit, override val imports: ImportDirectives = ImportDirectives(), + private val codeGeneratorName: String, ) : CodeGenerator { private val builder = StringBuilder() private var indent = "" @@ -187,7 +195,7 @@ class CodeGeneratorImpl( override fun persist() { val content = buildString { - appendLine("// Code generated by dynamodb-mapper-ops-codegen. DO NOT EDIT!") + appendLine("// Code generated by $codeGeneratorName. DO NOT EDIT!") appendLine() appendLine("package $pkg") appendLine() @@ -211,6 +219,8 @@ class CodeGeneratorImpl( write(" */") } + override fun docs(template: String, vararg args: Any) = withDocs { write(template, *args) } + override fun write(template: String, vararg args: Any) { writeInline(template, *args) builder.append('\n') diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/CodeGeneratorFactory.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/CodeGeneratorFactory.kt similarity index 78% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/CodeGeneratorFactory.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/CodeGeneratorFactory.kt index 4e4950dd16f..6835886c2d8 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/CodeGeneratorFactory.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/CodeGeneratorFactory.kt @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.core +package aws.sdk.kotlin.hll.codegen.core import com.google.devtools.ksp.processing.Dependencies import com.google.devtools.ksp.processing.KSPLogger @@ -19,11 +19,12 @@ class CodeGeneratorFactory(private val ksCodeGenerator: KSCodeGenerator, private /** * Creates a new [CodeGenerator] backed by a [KSCodeGenerator]. The returned generator starts with no imports and * uses a configured [TemplateEngine] with the default set of processors. - * @param name The name of the file which should be created _without_ parent directory or extension (which is always + * @param fileName The name of the file which should be created _without_ parent directory or extension (which is always * **.kt**) * @param pkg The Kotlin package for the generated code (e.g., `aws.sdk.kotlin.hll.dynamodbmapper.operations`) + * @param codeGeneratorName The name of this [CodeGenerator] */ - fun generator(name: String, pkg: String): CodeGenerator { + fun generator(fileName: String, pkg: String, codeGeneratorName: String): CodeGenerator { val imports = ImportDirectives() val processors = listOf( TemplateProcessor.Literal, @@ -33,15 +34,15 @@ class CodeGeneratorFactory(private val ksCodeGenerator: KSCodeGenerator, private val engine = TemplateEngine(processors) val persistCallback: (String) -> Unit = { content -> - logger.info("Checking out code generator for class $pkg.$name") + logger.info("Checking out code generator for class $pkg.$fileName") ksCodeGenerator - .createNewFile(dependencies, pkg, name) // FIXME don't depend on ALL_FILES + .createNewFile(dependencies, pkg, fileName) // FIXME don't depend on ALL_FILES .use { outputStream -> outputStream.writer().use { writer -> writer.append(content) } } } - return CodeGeneratorImpl(pkg, engine, persistCallback, imports) + return CodeGeneratorImpl(pkg, engine, persistCallback, imports, codeGeneratorName) } } diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/ImportDirectives.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/ImportDirectives.kt similarity index 94% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/ImportDirectives.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/ImportDirectives.kt index e899160da8c..cfc0e96b76b 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/ImportDirectives.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/ImportDirectives.kt @@ -2,9 +2,9 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.core +package aws.sdk.kotlin.hll.codegen.core -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.TypeRef +import aws.sdk.kotlin.hll.codegen.model.TypeRef /** * A mutable collection of [ImportDirectives] for eventually writing to a code generator diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateEngine.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateEngine.kt similarity index 98% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateEngine.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateEngine.kt index d180e781f88..383f6a8486b 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateEngine.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateEngine.kt @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.core +package aws.sdk.kotlin.hll.codegen.core /** * A string processing engine that replaces template parameters with passed arguments to form a final string. String diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateProcessor.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateProcessor.kt similarity index 89% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateProcessor.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateProcessor.kt index f0981dccdb7..0b5a4589e1d 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateProcessor.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateProcessor.kt @@ -2,11 +2,11 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.core +package aws.sdk.kotlin.hll.codegen.core -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.Type -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.TypeRef -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.util.quote +import aws.sdk.kotlin.hll.codegen.model.Type +import aws.sdk.kotlin.hll.codegen.model.TypeRef +import aws.sdk.kotlin.hll.codegen.util.quote /** * Defines a template processor which maps an argument value of any type to a string value @@ -71,11 +71,11 @@ private open class TypeProcessor { private class ImportingTypeProcessor(private val pkg: String, private val imports: ImportDirectives) : TypeProcessor() { override fun format(type: Type): String = buildString { - if (type is TypeRef && type.pkg != pkg) { - val existingImport = imports[type.shortName] + if (type is TypeRef && type.pkg != pkg && type.pkg != "kotlin") { + val existingImport = imports[type.baseName] if (existingImport == null) { - imports += ImportDirective(type) + imports += ImportDirective("${type.pkg}.${type.baseName}") } else if (existingImport.fullName != type.fullName) { append(type.pkg) append('.') diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Member.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Member.kt similarity index 92% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Member.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Member.kt index 36fe074ef44..ec2b6dfa374 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Member.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Member.kt @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.model +package aws.sdk.kotlin.hll.codegen.model import com.google.devtools.ksp.symbol.KSPropertyDeclaration diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Type.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Type.kt similarity index 52% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Type.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Type.kt index b2c6985ddbe..a4d28b5005d 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/model/Type.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Type.kt @@ -2,9 +2,10 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.model +package aws.sdk.kotlin.hll.codegen.model -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.util.Pkg +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSTypeReference /** @@ -13,42 +14,27 @@ import com.google.devtools.ksp.symbol.KSTypeReference sealed interface Type { companion object { /** - * Derives a [TypeRef] from a [KSTypeReference] - */ - fun from(ksTypeRef: KSTypeReference): TypeRef { - val resolved = ksTypeRef.resolve() - val name = resolved.declaration.qualifiedName!! - return TypeRef( - pkg = name.getQualifier(), - shortName = name.getShortName(), - genericArgs = resolved.arguments.map { from(it.type!!) }, - nullable = resolved.isMarkedNullable, - ) - } - - /** - * Creates a [TypeRef] for a generic [List] - * @param element The type of elements in the list + * Derives a [TypeRef] from a [KSClassDeclaration] */ - fun list(element: Type) = TypeRef(Pkg.Kotlin.Collections, "List", listOf(element)) + fun from(ksClassDeclaration: KSClassDeclaration): TypeRef = from(ksClassDeclaration.asStarProjectedType()) /** - * Creates a [TypeRef] for a named Kotlin type (e.g., `String`) - */ - fun kotlin(name: String) = TypeRef(Pkg.Kotlin.Base, name) - - /** - * Creates a [TypeRef] for a generic [Map] - * @param key The type of keys in the map - * @param value The type of values in the map + * Derives a [TypeRef] from a [KSTypeReference] */ - fun map(key: Type, value: Type) = TypeRef(Pkg.Kotlin.Collections, "Map", listOf(key, value)) + fun from(ksTypeRef: KSTypeReference): TypeRef = from(ksTypeRef.resolve()) /** - * Creates a [TypeRef] for a generic [Map] with [String] keys - * @param value The type of values in the map + * Derives a [TypeRef] from a [KSType] */ - fun stringMap(value: Type) = map(Types.String, value) + fun from(ksType: KSType): TypeRef { + val name = ksType.declaration.qualifiedName!! + return TypeRef( + pkg = name.getQualifier(), + shortName = name.getShortName(), + genericArgs = ksType.arguments.map { from(it.type!!) }, + nullable = ksType.isMarkedNullable, + ) + } } /** @@ -69,7 +55,7 @@ sealed interface Type { * representing [kotlin.collections.List] would have a single generic argument, which may either be a concrete [TypeRef] * itself (e.g., `List`) or a generic [TypeVar] (e.g., `List`). * @param pkg The Kotlin package for this type - * @param shortName The short name (i.e., not include the kotlin package) for this type + * @param shortName The short name (i.e., not including the kotlin package) for this type * @param genericArgs Zero or more [Type] generic arguments to this type * @param nullable Indicates whether instances of this type allow nullable references */ @@ -83,6 +69,12 @@ data class TypeRef( * The full name of this type, including the Kotlin package */ val fullName: String = "$pkg.$shortName" + + /** + * The base name of this type. In most cases, this will be the same as the short name, but for nested types, this + * will only include the top-level name. For example, the base name of a type Foo.Bar.Baz is Foo. + */ + val baseName: String = shortName.substringBefore(".") } /** @@ -101,23 +93,3 @@ fun Type.nullable() = when { this is TypeVar -> copy(nullable = true) else -> error("Unknown Type ${this::class}") // Should be unreachable, only here to make compiler happy } - -/** - * A container/factory object for various [Type] instances - */ -object Types { - // Kotlin standard types - val String = TypeRef("kotlin", "String") - val StringNullable = String.nullable() - - // Low-level types - val AttributeValue = TypeRef(Pkg.Ll.Model, "AttributeValue") - val AttributeMap = Type.map(String, AttributeValue) - - // High-level types - val HReqContextImpl = TypeRef(Pkg.Hl.PipelineImpl, "HReqContextImpl") - fun itemSchema(typeVar: String) = TypeRef(Pkg.Hl.Items, "ItemSchema", listOf(TypeVar(typeVar))) - val MapperContextImpl = TypeRef(Pkg.Hl.PipelineImpl, "MapperContextImpl") - val Operation = TypeRef(Pkg.Hl.PipelineImpl, "Operation") - val toItem = TypeRef(Pkg.Hl.Model, "toItem") -} diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Types.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Types.kt new file mode 100644 index 00000000000..8b823cf5872 --- /dev/null +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Types.kt @@ -0,0 +1,38 @@ +package aws.sdk.kotlin.hll.codegen.model + +import aws.sdk.kotlin.hll.codegen.util.Pkg + +/** + * A container object for various [Type] instances + */ +object Types { + object Kotlin { + val String = kotlin("String") + val Number = kotlin("Number") + val StringNullable = String.nullable() + + /** + * Creates a [TypeRef] for a generic [List] + * @param element The type of elements in the list + */ + fun list(element: Type) = TypeRef(Pkg.Kotlin.Collections, "List", listOf(element)) + + /** + * Creates a [TypeRef] for a named Kotlin type (e.g., `String`) + */ + fun kotlin(name: String) = TypeRef(Pkg.Kotlin.Base, name) + + /** + * Creates a [TypeRef] for a generic [Map] + * @param key The type of keys in the map + * @param value The type of values in the map + */ + fun map(key: Type, value: Type) = TypeRef(Pkg.Kotlin.Collections, "Map", listOf(key, value)) + + /** + * Creates a [TypeRef] for a generic [Map] with [String] keys + * @param value The type of values in the map + */ + fun stringMap(value: Type) = map(String, value) + } +} diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/BuilderRenderer.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/BuilderRenderer.kt new file mode 100644 index 00000000000..3fb3870922f --- /dev/null +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/BuilderRenderer.kt @@ -0,0 +1,47 @@ +package aws.sdk.kotlin.hll.codegen.rendering + +import aws.sdk.kotlin.hll.codegen.model.Member +import aws.sdk.kotlin.hll.codegen.model.TypeRef +import com.google.devtools.ksp.symbol.* + +/** + * A DSL-style builder renderer. + * @param renderer The base renderer in which the builder will be written + * @param classType The [TypeRef] representing the class for which a builder will be generated + * @param members The [Set] of members of [classType] which will be included in the builder + */ +class BuilderRenderer( + private val renderer: RendererBase, + private val classType: TypeRef, + private val members: Set, +) { + private val className = classType.shortName + + fun render() = renderer.apply { + docs("A DSL-style builder for instances of [#T]", classType) + + withBlock("public class #L {", "}", "${className}Builder") { + members.forEach { + write("public var #L: #T? = null", it.name, it.type) + } + blankLine() + + withBlock("public fun build(): #T {", "}", classType) { + members.forEach { + if (it.type.nullable) { + write("val #1L = #1L", it.name) + } else { + write("val #1L = requireNotNull(#1L) { #2S }", it.name, "Missing value for ${it.name}") + } + } + blankLine() + withBlock("return #T(", ")", classType) { + members.forEach { + write("#L,", it.name) + } + } + } + } + blankLine() + } +} diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/RenderContext.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/RenderContext.kt similarity index 85% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/RenderContext.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/RenderContext.kt index 3461f321fd8..dc6ff2cccb3 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/RenderContext.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/RenderContext.kt @@ -2,9 +2,9 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.rendering +package aws.sdk.kotlin.hll.codegen.rendering -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.core.CodeGeneratorFactory +import aws.sdk.kotlin.hll.codegen.core.CodeGeneratorFactory import com.google.devtools.ksp.processing.KSPLogger import com.google.devtools.ksp.symbol.KSNode @@ -15,7 +15,7 @@ import com.google.devtools.ksp.symbol.KSNode * @param codegenFactory A factory that creates code generator instances for specific files * @param pkg The Kotlin package for the generated code (e.g., `aws.sdk.kotlin.hll.dynamodbmapper.operations`) */ -data class RenderContext(val logger: KSPLogger, val codegenFactory: CodeGeneratorFactory, val pkg: String) +data class RenderContext(val logger: KSPLogger, val codegenFactory: CodeGeneratorFactory, val pkg: String, val rendererName: String = "aws-sdk-kotlin-hll-codegen") fun RenderContext.logging(message: String, symbol: KSNode? = null) = logger.logging(message, symbol) fun RenderContext.info(message: String, symbol: KSNode? = null) = logger.info(message, symbol) diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/RendererBase.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/RendererBase.kt similarity index 60% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/RendererBase.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/RendererBase.kt index 1eb1fc8c336..566f278f9c4 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/rendering/RendererBase.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/RendererBase.kt @@ -2,20 +2,20 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.rendering +package aws.sdk.kotlin.hll.codegen.rendering -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.core.CodeGenerator +import aws.sdk.kotlin.hll.codegen.core.CodeGenerator /** * The parent class for renderers backed by a [CodeGenerator] * @param ctx The active [RenderContext] - * @param name The name of the file which should be created _without_ parent directory or extension (which is always + * @param fileName The name of the file which should be created _without_ parent directory or extension (which is always * **.kt**) */ abstract class RendererBase( ctx: RenderContext, - name: String, -) : CodeGenerator by ctx.codegenFactory.generator(name, ctx.pkg) { + fileName: String, +) : CodeGenerator by ctx.codegenFactory.generator(fileName, ctx.pkg, ctx.rendererName) { /** * Run this renderer by calling the `abstract` [generate] method and then [persist] */ diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/AttributesExt.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/AttributesExt.kt similarity index 94% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/AttributesExt.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/AttributesExt.kt index 00a988c4c1f..4bf2c7bb65e 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/AttributesExt.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/AttributesExt.kt @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.util +package aws.sdk.kotlin.hll.codegen.util import aws.smithy.kotlin.runtime.collections.AttributeKey import aws.smithy.kotlin.runtime.collections.Attributes diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/Pkg.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/Pkg.kt similarity index 89% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/Pkg.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/Pkg.kt index 980202f71d4..68da7965be9 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/Pkg.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/Pkg.kt @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.util +package aws.sdk.kotlin.hll.codegen.util /** * Named constants for various mapper runtime packages @@ -14,6 +14,7 @@ object Pkg { val Model = "$Base.model" val Ops = "$Base.operations" val PipelineImpl = "$Base.pipeline.internal" + val Values = "$Base.values" } object Kotlin { diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/Strings.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/Strings.kt similarity index 96% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/Strings.kt rename to hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/Strings.kt index ad1a5ab9154..4382e390df7 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/Strings.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/Strings.kt @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.util +package aws.sdk.kotlin.hll.codegen.util private val codepointMap = buildMap { (0..255).filter(Character::isISOControl).forEach { code -> put(code, unicodeEscape(code)) } diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateEngineTest.kt b/hll/hll-codegen/src/test/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateEngineTest.kt similarity index 97% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateEngineTest.kt rename to hll/hll-codegen/src/test/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateEngineTest.kt index b9578361c1d..c853b989f7f 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateEngineTest.kt +++ b/hll/hll-codegen/src/test/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateEngineTest.kt @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.core +package aws.sdk.kotlin.hll.codegen.core import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateProcessorTest.kt b/hll/hll-codegen/src/test/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateProcessorTest.kt similarity index 92% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateProcessorTest.kt rename to hll/hll-codegen/src/test/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateProcessorTest.kt index 4df169db48e..ffc793866f7 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/core/TemplateProcessorTest.kt +++ b/hll/hll-codegen/src/test/kotlin/aws/sdk/kotlin/hll/codegen/core/TemplateProcessorTest.kt @@ -2,10 +2,10 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.core +package aws.sdk.kotlin.hll.codegen.core -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.TypeRef -import aws.sdk.kotlin.hll.dynamodbmapper.codegen.model.TypeVar +import aws.sdk.kotlin.hll.codegen.model.TypeRef +import aws.sdk.kotlin.hll.codegen.model.TypeVar import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import kotlin.test.assertContains diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/StringsTest.kt b/hll/hll-codegen/src/test/kotlin/aws/sdk/kotlin/hll/codegen/util/StringsTest.kt similarity index 94% rename from hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/StringsTest.kt rename to hll/hll-codegen/src/test/kotlin/aws/sdk/kotlin/hll/codegen/util/StringsTest.kt index 0cbbd7cda7b..c2f85036c6d 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/util/StringsTest.kt +++ b/hll/hll-codegen/src/test/kotlin/aws/sdk/kotlin/hll/codegen/util/StringsTest.kt @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package aws.sdk.kotlin.hll.dynamodbmapper.codegen.util +package aws.sdk.kotlin.hll.codegen.util import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test diff --git a/settings.gradle.kts b/settings.gradle.kts index a0b1ce8f837..b9e3bedf097 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -39,7 +39,8 @@ include(":aws-runtime:aws-core") include(":aws-runtime:aws-config") include(":aws-runtime:aws-endpoint") include(":aws-runtime:aws-http") -include(":hlls") +include(":hll") +include(":hll:hll-codegen") include(":services") include(":tests") include(":tests:codegen:event-stream") @@ -61,9 +62,8 @@ file("services").listFiles().forEach { if ("dynamodb".isBootstrappedService) { include(":hll:dynamodb-mapper") include(":hll:dynamodb-mapper:dynamodb-mapper") - include(":hll:dynamodb-mapper:dynamodb-mapper-annotation-processor") + include(":hll:dynamodb-mapper:dynamodb-mapper-codegen") include(":hll:dynamodb-mapper:dynamodb-mapper-annotations") - include(":hll:dynamodb-mapper:dynamodb-mapper-ops-codegen") include(":hll:dynamodb-mapper:tests:dynamodb-mapper-annotation-processor-test") } else { logger.warn(":services:dynamodb is not bootstrapped, skipping :hll:dynamodb-mapper and subprojects")