Skip to content

Commit

Permalink
Remove defaults for some shapes in some services
Browse files Browse the repository at this point in the history
Adds an integration that removes the default value from certain
shapes in some services where the default value is 0, but the
service expects a value > 0.
  • Loading branch information
milesziemer committed Nov 17, 2023
1 parent 6a0857b commit ad40494
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .changes/190be92b-a106-476b-99b3-224a80f81d7d.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"id": "190be92b-a106-476b-99b3-224a80f81d7d",
"type": "bugfix",
"description": "**Breaking**: Make some types for EMR Serverless optional by removing default values",
"requiresMinorVersionBump": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package aws.sdk.kotlin.codegen.customization

import software.amazon.smithy.codegen.core.CodegenException
import software.amazon.smithy.kotlin.codegen.KotlinSettings
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
import software.amazon.smithy.kotlin.codegen.model.hasTrait
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.shapes.AbstractShapeBuilder
import software.amazon.smithy.model.shapes.MemberShape
import software.amazon.smithy.model.shapes.Shape
import software.amazon.smithy.model.shapes.ShapeId
import software.amazon.smithy.model.traits.DefaultTrait
import software.amazon.smithy.model.transform.ModelTransformer
import software.amazon.smithy.utils.ToSmithyBuilder

/**
* Removes the default value of certain shapes, and any member that target
* those shapes,for certain services. These default values may cause
* serialization, validation, or other unexpected issues.
*/
class RemoveDefaults : KotlinIntegration {
// Service shape id -> Shape id of each root shape to remove default values from.
private val removeDefaultsFrom = mapOf(
ShapeId.from("com.amazonaws.amplifyuibuilder#AmplifyUIBuilder") to setOf(
ShapeId.from("com.amazonaws.amplifyuibuilder#ListComponentsLimit"),
ShapeId.from("com.amazonaws.amplifyuibuilder#ListFormsLimit"),
ShapeId.from("com.amazonaws.amplifyuibuilder#ListThemesLimit"),
),
ShapeId.from("com.amazonaws.drs#ElasticDisasterRecoveryService") to setOf(
ShapeId.from("com.amazonaws.drs#Validity"),
ShapeId.from("com.amazonaws.drs#CostOptimizationConfiguration\$burstBalanceThreshold"),
ShapeId.from("com.amazonaws.drs#CostOptimizationConfiguration\$burstBalanceDeltaThreshold"),
ShapeId.from("com.amazonaws.drs#ListStagingAccountsRequest\$maxResults"),
ShapeId.from("com.amazonaws.drs#StrictlyPositiveInteger"),
ShapeId.from("com.amazonaws.drs#MaxResultsType"),
ShapeId.from("com.amazonaws.drs#MaxResultsReplicatingSourceServers"),
ShapeId.from("com.amazonaws.drs#LaunchActionOrder"),
),
ShapeId.from("com.amazonaws.evidently#Evidently") to setOf(
ShapeId.from("com.amazonaws.evidently#ResultsPeriod"),
),
ShapeId.from("com.amazonaws.location#LocationService") to setOf(
ShapeId.from("com.amazonaws.location#ListPlaceIndexesRequest\$MaxResults"),
ShapeId.from("com.amazonaws.location#SearchPlaceIndexForSuggestionsRequest\$MaxResults"),
ShapeId.from("com.amazonaws.location#PlaceIndexSearchResultLimit"),
),
ShapeId.from("com.amazonaws.paymentcryptographydata#PaymentCryptographyDataPlane") to setOf(
ShapeId.from("com.amazonaws.paymentcryptographydata#IntegerRangeBetween4And12"),
),
ShapeId.from("com.amazonaws.emrserverless#AwsToledoWebService") to setOf(
ShapeId.from("com.amazonaws.emrserverless#WorkerCounts"),
),
)

override val order: Byte = 0

override fun enabledForService(model: Model, settings: KotlinSettings): Boolean {
val serviceId = settings.service
return serviceId in removeDefaultsFrom
}

override fun preprocessModel(model: Model, settings: KotlinSettings): Model {
val serviceId = settings.service
val removeDefaultsFromShapes = removeDefaultsFrom[serviceId]
?: throw CodegenException("expected $serviceId in removed defaults map")
return removeDefaults(model, removeDefaultsFromShapes)
}

fun removeDefaults(model: Model, fromShapes: Set<ShapeId>): Model {
val removedRootDefaults: MutableSet<ShapeId> = HashSet()
val removedRootDefaultsModel = ModelTransformer.create().mapShapes(model) {
if (shouldRemoveRootDefault(it, fromShapes)) {
removedRootDefaults.add(it.id)
removeDefault(it)
} else {
it
}
}

return ModelTransformer.create().mapShapes(removedRootDefaultsModel) {
if (shouldRemoveMemberDefault(it, removedRootDefaults, fromShapes)) {
removeDefault(it)
} else {
it
}
}
}

private fun shouldRemoveRootDefault(shape: Shape, removeDefaultsFrom: Set<ShapeId>): Boolean =
shape !is MemberShape && removeDefaultsFrom.contains(shape.id) && shape.hasTrait<DefaultTrait>()

private fun shouldRemoveMemberDefault(
shape: Shape,
removedRootDefaults: Set<ShapeId>,
removeDefaultsFrom: Set<ShapeId>,
): Boolean = shape is MemberShape &&
// Check the original set of shapes to remove for this shape id, to remove members that were in that set.
(removedRootDefaults.contains(shape.target) || removeDefaultsFrom.contains(shape.id)) &&
shape.hasTrait<DefaultTrait>()

private fun removeDefault(shape: Shape): Shape =
((shape as ToSmithyBuilder<*>).toBuilder() as AbstractShapeBuilder<*, *>)
.removeTrait(DefaultTrait.ID)
.build()
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ aws.sdk.kotlin.codegen.customization.s3.HostPrefixRequestRouteFilter
aws.sdk.kotlin.codegen.customization.s3.UnwrappedXmlOutputIntegration
aws.sdk.kotlin.codegen.customization.ClockSkew
aws.sdk.kotlin.codegen.customization.ec2.EC2MakePrimitivesOptional
aws.sdk.kotlin.codegen.customization.RemoveDefaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package aws.sdk.kotlin.codegen.customization

import org.junit.jupiter.api.Test
import software.amazon.smithy.kotlin.codegen.model.hasTrait
import software.amazon.smithy.kotlin.codegen.test.toSmithyModel
import software.amazon.smithy.model.shapes.ShapeId
import software.amazon.smithy.model.traits.DefaultTrait
import kotlin.test.assertFalse

class RemoveDefaultsTest {
@Test
fun removesDefaults() {
val model = """
${"$"}version: "2.0"
namespace test
structure Foo {
bar: Bar = 0
baz: Integer = 0
}
@default(0)
integer Bar
""".toSmithyModel()

val removeDefaultsFrom = setOf(ShapeId.from("test#Bar"), ShapeId.from("test#Foo\$baz"))
val transformed = RemoveDefaults().removeDefaults(model, removeDefaultsFrom)
val barMember = transformed.expectShape(ShapeId.from("test#Foo\$bar"))
assertFalse(barMember.hasTrait<DefaultTrait>())
val bazMember = transformed.expectShape(ShapeId.from("test#Foo\$baz"))
assertFalse(bazMember.hasTrait<DefaultTrait>())
val root = transformed.expectShape(ShapeId.from("test#Bar"))
assertFalse(root.hasTrait<DefaultTrait>())
}
}

0 comments on commit ad40494

Please sign in to comment.