// Code generated by smithy-go-codegen DO NOT EDIT.

package dynamodb

import (
	"context"
	"fmt"
	awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
	"github.com/aws/aws-sdk-go-v2/aws/signer/v4"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
	internalEndpointDiscovery "github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery"
	"github.com/aws/smithy-go/middleware"
	smithyhttp "github.com/aws/smithy-go/transport/http"
)

// The CreateTable operation adds a new table to your account. In an Amazon Web
// Services account, table names must be unique within each Region. That is, you
// can have two tables with same name if you create the tables in different
// Regions. CreateTable is an asynchronous operation. Upon receiving a CreateTable
// request, DynamoDB immediately returns a response with a TableStatus of CREATING.
// After the table is created, DynamoDB sets the TableStatus to ACTIVE. You can
// perform read and write operations only on an ACTIVE table. You can optionally
// define secondary indexes on the new table, as part of the CreateTable operation.
// If you want to create multiple tables with secondary indexes on them, you must
// create the tables sequentially. Only one table with secondary indexes can be in
// the CREATING state at any given time. You can use the DescribeTable action to
// check the table status.
func (c *Client) CreateTable(ctx context.Context, params *CreateTableInput, optFns ...func(*Options)) (*CreateTableOutput, error) {
	if params == nil {
		params = &CreateTableInput{}
	}

	result, metadata, err := c.invokeOperation(ctx, "CreateTable", params, optFns, c.addOperationCreateTableMiddlewares)
	if err != nil {
		return nil, err
	}

	out := result.(*CreateTableOutput)
	out.ResultMetadata = metadata
	return out, nil
}

// Represents the input of a CreateTable operation.
type CreateTableInput struct {

	// An array of attributes that describe the key schema for the table and indexes.
	//
	// This member is required.
	AttributeDefinitions []types.AttributeDefinition

	// Specifies the attributes that make up the primary key for a table or an index.
	// The attributes in KeySchema must also be defined in the AttributeDefinitions
	// array. For more information, see Data Model
	// (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataModel.html)
	// in the Amazon DynamoDB Developer Guide. Each KeySchemaElement in the array is
	// composed of:
	//
	// * AttributeName - The name of this key attribute.
	//
	// * KeyType - The
	// role that the key attribute will assume:
	//
	// * HASH - partition key
	//
	// * RANGE - sort
	// key
	//
	// The partition key of an item is also known as its hash attribute. The term
	// "hash attribute" derives from the DynamoDB usage of an internal hash function to
	// evenly distribute data items across partitions, based on their partition key
	// values. The sort key of an item is also known as its range attribute. The term
	// "range attribute" derives from the way DynamoDB stores items with the same
	// partition key physically close together, in sorted order by the sort key value.
	// For a simple primary key (partition key), you must provide exactly one element
	// with a KeyType of HASH. For a composite primary key (partition key and sort
	// key), you must provide exactly two elements, in this order: The first element
	// must have a KeyType of HASH, and the second element must have a KeyType of
	// RANGE. For more information, see Working with Tables
	// (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithTables.html#WorkingWithTables.primary.key)
	// in the Amazon DynamoDB Developer Guide.
	//
	// This member is required.
	KeySchema []types.KeySchemaElement

	// The name of the table to create.
	//
	// This member is required.
	TableName *string

	// Controls how you are charged for read and write throughput and how you manage
	// capacity. This setting can be changed later.
	//
	// * PROVISIONED - We recommend using
	// PROVISIONED for predictable workloads. PROVISIONED sets the billing mode to
	// Provisioned Mode
	// (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.ProvisionedThroughput.Manual).
	//
	// *
	// PAY_PER_REQUEST - We recommend using PAY_PER_REQUEST for unpredictable
	// workloads. PAY_PER_REQUEST sets the billing mode to On-Demand Mode
	// (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.OnDemand).
	BillingMode types.BillingMode

	// One or more global secondary indexes (the maximum is 20) to be created on the
	// table. Each global secondary index in the array includes the following:
	//
	// *
	// IndexName - The name of the global secondary index. Must be unique only for this
	// table.
	//
	// * KeySchema - Specifies the key schema for the global secondary
	// index.
	//
	// * Projection - Specifies attributes that are copied (projected) from the
	// table into the index. These are in addition to the primary key attributes and
	// index key attributes, which are automatically projected. Each attribute
	// specification is composed of:
	//
	// * ProjectionType - One of the following:
	//
	// *
	// KEYS_ONLY - Only the index and primary keys are projected into the index.
	//
	// *
	// INCLUDE - Only the specified table attributes are projected into the index. The
	// list of projected attributes is in NonKeyAttributes.
	//
	// * ALL - All of the table
	// attributes are projected into the index.
	//
	// * NonKeyAttributes - A list of one or
	// more non-key attribute names that are projected into the secondary index. The
	// total count of attributes provided in NonKeyAttributes, summed across all of the
	// secondary indexes, must not exceed 100. If you project the same attribute into
	// two different indexes, this counts as two distinct attributes when determining
	// the total.
	//
	// * ProvisionedThroughput - The provisioned throughput settings for
	// the global secondary index, consisting of read and write capacity units.
	GlobalSecondaryIndexes []types.GlobalSecondaryIndex

	// One or more local secondary indexes (the maximum is 5) to be created on the
	// table. Each index is scoped to a given partition key value. There is a 10 GB
	// size limit per partition key value; otherwise, the size of a local secondary
	// index is unconstrained. Each local secondary index in the array includes the
	// following:
	//
	// * IndexName - The name of the local secondary index. Must be unique
	// only for this table.
	//
	// * KeySchema - Specifies the key schema for the local
	// secondary index. The key schema must begin with the same partition key as the
	// table.
	//
	// * Projection - Specifies attributes that are copied (projected) from the
	// table into the index. These are in addition to the primary key attributes and
	// index key attributes, which are automatically projected. Each attribute
	// specification is composed of:
	//
	// * ProjectionType - One of the following:
	//
	// *
	// KEYS_ONLY - Only the index and primary keys are projected into the index.
	//
	// *
	// INCLUDE - Only the specified table attributes are projected into the index. The
	// list of projected attributes is in NonKeyAttributes.
	//
	// * ALL - All of the table
	// attributes are projected into the index.
	//
	// * NonKeyAttributes - A list of one or
	// more non-key attribute names that are projected into the secondary index. The
	// total count of attributes provided in NonKeyAttributes, summed across all of the
	// secondary indexes, must not exceed 100. If you project the same attribute into
	// two different indexes, this counts as two distinct attributes when determining
	// the total.
	LocalSecondaryIndexes []types.LocalSecondaryIndex

	// Represents the provisioned throughput settings for a specified table or index.
	// The settings can be modified using the UpdateTable operation. If you set
	// BillingMode as PROVISIONED, you must specify this property. If you set
	// BillingMode as PAY_PER_REQUEST, you cannot specify this property. For current
	// minimum and maximum provisioned throughput values, see Service, Account, and
	// Table Quotas
	// (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html)
	// in the Amazon DynamoDB Developer Guide.
	ProvisionedThroughput *types.ProvisionedThroughput

	// Represents the settings used to enable server-side encryption.
	SSESpecification *types.SSESpecification

	// The settings for DynamoDB Streams on the table. These settings consist of:
	//
	// *
	// StreamEnabled - Indicates whether DynamoDB Streams is to be enabled (true) or
	// disabled (false).
	//
	// * StreamViewType - When an item in the table is modified,
	// StreamViewType determines what information is written to the table's stream.
	// Valid values for StreamViewType are:
	//
	// * KEYS_ONLY - Only the key attributes of
	// the modified item are written to the stream.
	//
	// * NEW_IMAGE - The entire item, as
	// it appears after it was modified, is written to the stream.
	//
	// * OLD_IMAGE - The
	// entire item, as it appeared before it was modified, is written to the stream.
	//
	// *
	// NEW_AND_OLD_IMAGES - Both the new and the old item images of the item are
	// written to the stream.
	StreamSpecification *types.StreamSpecification

	// The table class of the new table. Valid values are STANDARD and
	// STANDARD_INFREQUENT_ACCESS.
	TableClass types.TableClass

	// A list of key-value pairs to label the table. For more information, see Tagging
	// for DynamoDB
	// (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tagging.html).
	Tags []types.Tag

	noSmithyDocumentSerde
}

// Represents the output of a CreateTable operation.
type CreateTableOutput struct {

	// Represents the properties of the table.
	TableDescription *types.TableDescription

	// Metadata pertaining to the operation's result.
	ResultMetadata middleware.Metadata

	noSmithyDocumentSerde
}

func (c *Client) addOperationCreateTableMiddlewares(stack *middleware.Stack, options Options) (err error) {
	err = stack.Serialize.Add(&awsAwsjson10_serializeOpCreateTable{}, middleware.After)
	if err != nil {
		return err
	}
	err = stack.Deserialize.Add(&awsAwsjson10_deserializeOpCreateTable{}, middleware.After)
	if err != nil {
		return err
	}
	if err = addSetLoggerMiddleware(stack, options); err != nil {
		return err
	}
	if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil {
		return err
	}
	if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil {
		return err
	}
	if err = addResolveEndpointMiddleware(stack, options); err != nil {
		return err
	}
	if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil {
		return err
	}
	if err = addRetryMiddlewares(stack, options); err != nil {
		return err
	}
	if err = addHTTPSignerV4Middleware(stack, options); err != nil {
		return err
	}
	if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil {
		return err
	}
	if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil {
		return err
	}
	if err = addClientUserAgent(stack); err != nil {
		return err
	}
	if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil {
		return err
	}
	if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil {
		return err
	}
	if err = addOpCreateTableDiscoverEndpointMiddleware(stack, options, c); err != nil {
		return err
	}
	if err = addOpCreateTableValidationMiddleware(stack); err != nil {
		return err
	}
	if err = stack.Initialize.Add(newServiceMetadataMiddleware_opCreateTable(options.Region), middleware.Before); err != nil {
		return err
	}
	if err = addRequestIDRetrieverMiddleware(stack); err != nil {
		return err
	}
	if err = addResponseErrorMiddleware(stack); err != nil {
		return err
	}
	if err = addValidateResponseChecksum(stack, options); err != nil {
		return err
	}
	if err = addAcceptEncodingGzip(stack, options); err != nil {
		return err
	}
	if err = addRequestResponseLogging(stack, options); err != nil {
		return err
	}
	return nil
}

func addOpCreateTableDiscoverEndpointMiddleware(stack *middleware.Stack, o Options, c *Client) error {
	return stack.Serialize.Insert(&internalEndpointDiscovery.DiscoverEndpoint{
		Options: []func(*internalEndpointDiscovery.DiscoverEndpointOptions){
			func(opt *internalEndpointDiscovery.DiscoverEndpointOptions) {
				opt.DisableHTTPS = o.EndpointOptions.DisableHTTPS
				opt.Logger = o.Logger
			},
		},
		DiscoverOperation:            c.fetchOpCreateTableDiscoverEndpoint,
		EndpointDiscoveryEnableState: o.EndpointDiscovery.EnableEndpointDiscovery,
		EndpointDiscoveryRequired:    false,
	}, "ResolveEndpoint", middleware.After)
}

func (c *Client) fetchOpCreateTableDiscoverEndpoint(ctx context.Context, input interface{}, optFns ...func(*internalEndpointDiscovery.DiscoverEndpointOptions)) (internalEndpointDiscovery.WeightedAddress, error) {
	in, ok := input.(*CreateTableInput)
	if !ok {
		return internalEndpointDiscovery.WeightedAddress{}, fmt.Errorf("unknown input type %T", input)
	}
	_ = in

	identifierMap := make(map[string]string, 0)

	key := fmt.Sprintf("DynamoDB.%v", identifierMap)

	if v, ok := c.endpointCache.Get(key); ok {
		return v, nil
	}

	discoveryOperationInput := &DescribeEndpointsInput{}

	opt := internalEndpointDiscovery.DiscoverEndpointOptions{}
	for _, fn := range optFns {
		fn(&opt)
	}

	go c.handleEndpointDiscoveryFromService(ctx, discoveryOperationInput, key, opt)
	return internalEndpointDiscovery.WeightedAddress{}, nil
}

func newServiceMetadataMiddleware_opCreateTable(region string) *awsmiddleware.RegisterServiceMetadata {
	return &awsmiddleware.RegisterServiceMetadata{
		Region:        region,
		ServiceID:     ServiceID,
		SigningName:   "dynamodb",
		OperationName: "CreateTable",
	}
}
