'''
# Amazon Redshift Construct Library

<!--BEGIN STABILITY BANNER-->---


![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge)

> The APIs of higher level constructs in this module are experimental and under active development.
> They are subject to non-backward compatible changes or removal in any future version. These are
> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be
> announced in the release notes. This means that while you may use them, you may need to update
> your source code when upgrading to a newer version of this package.

---
<!--END STABILITY BANNER-->

## Starting a Redshift Cluster Database

To set up a Redshift cluster, define a `Cluster`. It will be launched in a VPC.
You can specify a VPC, otherwise one will be created. The nodes are always launched in private subnets and are encrypted by default.

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
import aws_cdk.aws_ec2 as ec2


vpc = ec2.Vpc(self, "Vpc")
cluster = Cluster(self, "Redshift",
    master_user=Login(
        master_username="admin"
    ),
    vpc=vpc
)
```

By default, the master password will be generated and stored in AWS Secrets Manager.

A default database named `default_db` will be created in the cluster. To change the name of this database set the `defaultDatabaseName` attribute in the constructor properties.

By default, the cluster will not be publicly accessible.
Depending on your use case, you can make the cluster publicly accessible with the `publiclyAccessible` property.

## Connecting

To control who can access the cluster, use the `.connections` attribute. Redshift Clusters have
a default port, so you don't need to specify the port:

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
cluster.connections.allow_default_port_from_any_ipv4("Open to the world")
```

The endpoint to access your database cluster will be available as the `.clusterEndpoint` attribute:

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
cluster.cluster_endpoint.socket_address
```

## Rotating credentials

When the master password is generated and stored in AWS Secrets Manager, it can be rotated automatically:

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
cluster.add_rotation_single_user()
```

The multi user rotation scheme is also available:

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
import aws_cdk.aws_secretsmanager as secretsmanager


cluster.add_rotation_multi_user("MyUser",
    secret=secretsmanager.Secret.from_secret_name_v2(self, "Imported Secret", "my-secret")
)
```

## Database Resources

This module allows for the creation of non-CloudFormation database resources such as users
and tables. This allows you to manage identities, permissions, and stateful resources
within your Redshift cluster from your CDK application.

Because these resources are not available in CloudFormation, this library leverages
[custom
resources](https://docs.aws.amazon.com/cdk/api/latest/docs/custom-resources-readme.html)
to manage them. In addition to the IAM permissions required to make Redshift service
calls, the execution role for the custom resource handler requires database credentials to
create resources within the cluster.

These database credentials can be supplied explicitly through the `adminUser` properties
of the various database resource constructs. Alternatively, the credentials can be
automatically pulled from the Redshift cluster's default administrator
credentials. However, this option is only available if the password for the credentials
was generated by the CDK application (ie., no value vas provided for [the `masterPassword`
property](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-redshift.Login.html#masterpasswordspan-classapi-icon-api-icon-experimental-titlethis-api-element-is-experimental-it-may-change-without-noticespan)
of
[`Cluster.masterUser`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-redshift.Cluster.html#masteruserspan-classapi-icon-api-icon-experimental-titlethis-api-element-is-experimental-it-may-change-without-noticespan)).

### Creating Users

Create a user within a Redshift cluster database by instantiating a `User` construct. This
will generate a username and password, store the credentials in a [AWS Secrets Manager
`Secret`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-secretsmanager.Secret.html),
and make a query to the Redshift cluster to create a new database user with the
credentials.

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
User(self, "User",
    cluster=cluster,
    database_name="databaseName"
)
```

By default, the user credentials are encrypted with your AWS account's default Secrets
Manager encryption key. You can specify the encryption key used for this purpose by
supplying a key in the `encryptionKey` property.

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
import aws_cdk.aws_kms as kms


encryption_key = kms.Key(self, "Key")
User(self, "User",
    encryption_key=encryption_key,
    cluster=cluster,
    database_name="databaseName"
)
```

By default, a username is automatically generated from the user construct ID and its path
in the construct tree. You can specify a particular username by providing a value for the
`username` property. Usernames must be valid identifiers; see: [Names and
identifiers](https://docs.aws.amazon.com/redshift/latest/dg/r_names.html) in the *Amazon
Redshift Database Developer Guide*.

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
User(self, "User",
    username="myuser",
    cluster=cluster,
    database_name="databaseName"
)
```

The user password is generated by AWS Secrets Manager using the default configuration
found in
[`secretsmanager.SecretStringGenerator`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-secretsmanager.SecretStringGenerator.html),
except with password length `30` and some SQL-incompliant characters excluded. The
plaintext for the password will never be present in the CDK application; instead, a
[CloudFormation Dynamic
Reference](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html)
will be used wherever the password value is required.

### Creating Tables

Create a table within a Redshift cluster database by instantiating a `Table`
construct. This will make a query to the Redshift cluster to create a new database table
with the supplied schema.

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
Table(self, "Table",
    table_columns=[Column(name="col1", data_type="varchar(4)"), Column(name="col2", data_type="float")],
    cluster=cluster,
    database_name="databaseName"
)
```

### Granting Privileges

You can give a user privileges to perform certain actions on a table by using the
`Table.grant()` method.

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
user = User(self, "User",
    cluster=cluster,
    database_name="databaseName"
)
table = Table(self, "Table",
    table_columns=[Column(name="col1", data_type="varchar(4)"), Column(name="col2", data_type="float")],
    cluster=cluster,
    database_name="databaseName"
)

table.grant(user, TableAction.DROP, TableAction.SELECT)
```

Take care when managing privileges via the CDK, as attempting to manage a user's
privileges on the same table in multiple CDK applications could lead to accidentally
overriding these permissions. Consider the following two CDK applications which both refer
to the same user and table. In application 1, the resources are created and the user is
given `INSERT` permissions on the table:

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
database_name = "databaseName"
username = "myuser"
table_name = "mytable"

user = User(self, "User",
    username=username,
    cluster=cluster,
    database_name=database_name
)
table = Table(self, "Table",
    table_columns=[Column(name="col1", data_type="varchar(4)"), Column(name="col2", data_type="float")],
    cluster=cluster,
    database_name=database_name
)
table.grant(user, TableAction.INSERT)
```

In application 2, the resources are imported and the user is given `INSERT` permissions on
the table:

```python
# Example automatically generated. See https://github.com/aws/jsii/issues/826
database_name = "databaseName"
username = "myuser"
table_name = "mytable"

user = User.from_user_attributes(self, "User",
    username=username,
    password=SecretValue.plain_text("NOT_FOR_PRODUCTION"),
    cluster=cluster,
    database_name=database_name
)
table = Table.from_table_attributes(self, "Table",
    table_name=table_name,
    table_columns=[Column(name="col1", data_type="varchar(4)"), Column(name="col2", data_type="float")],
    cluster=cluster,
    database_name="databaseName"
)
table.grant(user, TableAction.INSERT)
```

Both applications attempt to grant the user the appropriate privilege on the table by
submitting a `GRANT USER` SQL query to the Redshift cluster. Note that the latter of these
two calls will have no effect since the user has already been granted the privilege.

Now, if application 1 were to remove the call to `grant`, a `REVOKE USER` SQL query is
submitted to the Redshift cluster. In general, application 1 does not know that
application 2 has also granted this permission and thus cannot decide not to issue the
revocation. This leads to the undesirable state where application 2 still contains the
call to `grant` but the user does not have the specified permission.

Note that this does not occur when duplicate privileges are granted within the same
application, as such privileges are de-duplicated before any SQL query is submitted.
'''
import abc
import builtins
import datetime
import enum
import typing

import jsii
import publication
import typing_extensions

from ._jsii import *

import aws_cdk
import aws_cdk.aws_ec2
import aws_cdk.aws_iam
import aws_cdk.aws_kms
import aws_cdk.aws_s3
import aws_cdk.aws_secretsmanager
import constructs


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.ClusterAttributes",
    jsii_struct_bases=[],
    name_mapping={
        "cluster_endpoint_address": "clusterEndpointAddress",
        "cluster_endpoint_port": "clusterEndpointPort",
        "cluster_name": "clusterName",
        "security_groups": "securityGroups",
    },
)
class ClusterAttributes:
    def __init__(
        self,
        *,
        cluster_endpoint_address: builtins.str,
        cluster_endpoint_port: jsii.Number,
        cluster_name: builtins.str,
        security_groups: typing.Optional[typing.Sequence[aws_cdk.aws_ec2.ISecurityGroup]] = None,
    ) -> None:
        '''(experimental) Properties that describe an existing cluster instance.

        :param cluster_endpoint_address: (experimental) Cluster endpoint address.
        :param cluster_endpoint_port: (experimental) Cluster endpoint port.
        :param cluster_name: (experimental) Identifier for the cluster.
        :param security_groups: (experimental) The security groups of the redshift cluster. Default: no security groups will be attached to the import

        :stability: experimental
        '''
        self._values: typing.Dict[str, typing.Any] = {
            "cluster_endpoint_address": cluster_endpoint_address,
            "cluster_endpoint_port": cluster_endpoint_port,
            "cluster_name": cluster_name,
        }
        if security_groups is not None:
            self._values["security_groups"] = security_groups

    @builtins.property
    def cluster_endpoint_address(self) -> builtins.str:
        '''(experimental) Cluster endpoint address.

        :stability: experimental
        '''
        result = self._values.get("cluster_endpoint_address")
        assert result is not None, "Required property 'cluster_endpoint_address' is missing"
        return typing.cast(builtins.str, result)

    @builtins.property
    def cluster_endpoint_port(self) -> jsii.Number:
        '''(experimental) Cluster endpoint port.

        :stability: experimental
        '''
        result = self._values.get("cluster_endpoint_port")
        assert result is not None, "Required property 'cluster_endpoint_port' is missing"
        return typing.cast(jsii.Number, result)

    @builtins.property
    def cluster_name(self) -> builtins.str:
        '''(experimental) Identifier for the cluster.

        :stability: experimental
        '''
        result = self._values.get("cluster_name")
        assert result is not None, "Required property 'cluster_name' is missing"
        return typing.cast(builtins.str, result)

    @builtins.property
    def security_groups(
        self,
    ) -> typing.Optional[typing.List[aws_cdk.aws_ec2.ISecurityGroup]]:
        '''(experimental) The security groups of the redshift cluster.

        :default: no security groups will be attached to the import

        :stability: experimental
        '''
        result = self._values.get("security_groups")
        return typing.cast(typing.Optional[typing.List[aws_cdk.aws_ec2.ISecurityGroup]], result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "ClusterAttributes(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.ClusterParameterGroupProps",
    jsii_struct_bases=[],
    name_mapping={"parameters": "parameters", "description": "description"},
)
class ClusterParameterGroupProps:
    def __init__(
        self,
        *,
        parameters: typing.Mapping[builtins.str, builtins.str],
        description: typing.Optional[builtins.str] = None,
    ) -> None:
        '''(experimental) Properties for a parameter group.

        :param parameters: (experimental) The parameters in this parameter group.
        :param description: (experimental) Description for this parameter group. Default: a CDK generated description

        :stability: experimental
        '''
        self._values: typing.Dict[str, typing.Any] = {
            "parameters": parameters,
        }
        if description is not None:
            self._values["description"] = description

    @builtins.property
    def parameters(self) -> typing.Mapping[builtins.str, builtins.str]:
        '''(experimental) The parameters in this parameter group.

        :stability: experimental
        '''
        result = self._values.get("parameters")
        assert result is not None, "Required property 'parameters' is missing"
        return typing.cast(typing.Mapping[builtins.str, builtins.str], result)

    @builtins.property
    def description(self) -> typing.Optional[builtins.str]:
        '''(experimental) Description for this parameter group.

        :default: a CDK generated description

        :stability: experimental
        '''
        result = self._values.get("description")
        return typing.cast(typing.Optional[builtins.str], result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "ClusterParameterGroupProps(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.ClusterProps",
    jsii_struct_bases=[],
    name_mapping={
        "master_user": "masterUser",
        "vpc": "vpc",
        "cluster_name": "clusterName",
        "cluster_type": "clusterType",
        "default_database_name": "defaultDatabaseName",
        "encrypted": "encrypted",
        "encryption_key": "encryptionKey",
        "logging_bucket": "loggingBucket",
        "logging_key_prefix": "loggingKeyPrefix",
        "node_type": "nodeType",
        "number_of_nodes": "numberOfNodes",
        "parameter_group": "parameterGroup",
        "port": "port",
        "preferred_maintenance_window": "preferredMaintenanceWindow",
        "publicly_accessible": "publiclyAccessible",
        "removal_policy": "removalPolicy",
        "roles": "roles",
        "security_groups": "securityGroups",
        "subnet_group": "subnetGroup",
        "vpc_subnets": "vpcSubnets",
    },
)
class ClusterProps:
    def __init__(
        self,
        *,
        master_user: "Login",
        vpc: aws_cdk.aws_ec2.IVpc,
        cluster_name: typing.Optional[builtins.str] = None,
        cluster_type: typing.Optional["ClusterType"] = None,
        default_database_name: typing.Optional[builtins.str] = None,
        encrypted: typing.Optional[builtins.bool] = None,
        encryption_key: typing.Optional[aws_cdk.aws_kms.IKey] = None,
        logging_bucket: typing.Optional[aws_cdk.aws_s3.IBucket] = None,
        logging_key_prefix: typing.Optional[builtins.str] = None,
        node_type: typing.Optional["NodeType"] = None,
        number_of_nodes: typing.Optional[jsii.Number] = None,
        parameter_group: typing.Optional["IClusterParameterGroup"] = None,
        port: typing.Optional[jsii.Number] = None,
        preferred_maintenance_window: typing.Optional[builtins.str] = None,
        publicly_accessible: typing.Optional[builtins.bool] = None,
        removal_policy: typing.Optional[aws_cdk.RemovalPolicy] = None,
        roles: typing.Optional[typing.Sequence[aws_cdk.aws_iam.IRole]] = None,
        security_groups: typing.Optional[typing.Sequence[aws_cdk.aws_ec2.ISecurityGroup]] = None,
        subnet_group: typing.Optional["IClusterSubnetGroup"] = None,
        vpc_subnets: typing.Optional[aws_cdk.aws_ec2.SubnetSelection] = None,
    ) -> None:
        '''(experimental) Properties for a new database cluster.

        :param master_user: (experimental) Username and password for the administrative user.
        :param vpc: (experimental) The VPC to place the cluster in.
        :param cluster_name: (experimental) An optional identifier for the cluster. Default: - A name is automatically generated.
        :param cluster_type: (experimental) Settings for the individual instances that are launched. Default: {@link ClusterType.MULTI_NODE}
        :param default_database_name: (experimental) Name of a database which is automatically created inside the cluster. Default: - default_db
        :param encrypted: (experimental) Whether to enable encryption of data at rest in the cluster. Default: true
        :param encryption_key: (experimental) The KMS key to use for encryption of data at rest. Default: - AWS-managed key, if encryption at rest is enabled
        :param logging_bucket: (experimental) Bucket to send logs to. Logging information includes queries and connection attempts, for the specified Amazon Redshift cluster. Default: - No Logs
        :param logging_key_prefix: (experimental) Prefix used for logging. Default: - no prefix
        :param node_type: (experimental) The node type to be provisioned for the cluster. Default: {@link NodeType.DC2_LARGE}
        :param number_of_nodes: (experimental) Number of compute nodes in the cluster. Only specify this property for multi-node clusters. Value must be at least 2 and no more than 100. Default: - 2 if ``clusterType`` is ClusterType.MULTI_NODE, undefined otherwise
        :param parameter_group: (experimental) Additional parameters to pass to the database engine https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-parameter-groups.html. Default: - No parameter group.
        :param port: (experimental) What port to listen on. Default: - The default for the engine is used.
        :param preferred_maintenance_window: (experimental) A preferred maintenance window day/time range. Should be specified as a range ddd:hh24:mi-ddd:hh24:mi (24H Clock UTC). Example: 'Sun:23:45-Mon:00:15' Default: - 30-minute window selected at random from an 8-hour block of time for each AWS Region, occurring on a random day of the week.
        :param publicly_accessible: (experimental) Whether to make cluster publicly accessible. Default: false
        :param removal_policy: (experimental) The removal policy to apply when the cluster and its instances are removed from the stack or replaced during an update. Default: RemovalPolicy.RETAIN
        :param roles: (experimental) A list of AWS Identity and Access Management (IAM) role that can be used by the cluster to access other AWS services. Specify a maximum of 10 roles. Default: - No role is attached to the cluster.
        :param security_groups: (experimental) Security group. Default: - a new security group is created.
        :param subnet_group: (experimental) A cluster subnet group to use with this cluster. Default: - a new subnet group will be created.
        :param vpc_subnets: (experimental) Where to place the instances within the VPC. Default: - private subnets

        :stability: experimental
        '''
        if isinstance(master_user, dict):
            master_user = Login(**master_user)
        if isinstance(vpc_subnets, dict):
            vpc_subnets = aws_cdk.aws_ec2.SubnetSelection(**vpc_subnets)
        self._values: typing.Dict[str, typing.Any] = {
            "master_user": master_user,
            "vpc": vpc,
        }
        if cluster_name is not None:
            self._values["cluster_name"] = cluster_name
        if cluster_type is not None:
            self._values["cluster_type"] = cluster_type
        if default_database_name is not None:
            self._values["default_database_name"] = default_database_name
        if encrypted is not None:
            self._values["encrypted"] = encrypted
        if encryption_key is not None:
            self._values["encryption_key"] = encryption_key
        if logging_bucket is not None:
            self._values["logging_bucket"] = logging_bucket
        if logging_key_prefix is not None:
            self._values["logging_key_prefix"] = logging_key_prefix
        if node_type is not None:
            self._values["node_type"] = node_type
        if number_of_nodes is not None:
            self._values["number_of_nodes"] = number_of_nodes
        if parameter_group is not None:
            self._values["parameter_group"] = parameter_group
        if port is not None:
            self._values["port"] = port
        if preferred_maintenance_window is not None:
            self._values["preferred_maintenance_window"] = preferred_maintenance_window
        if publicly_accessible is not None:
            self._values["publicly_accessible"] = publicly_accessible
        if removal_policy is not None:
            self._values["removal_policy"] = removal_policy
        if roles is not None:
            self._values["roles"] = roles
        if security_groups is not None:
            self._values["security_groups"] = security_groups
        if subnet_group is not None:
            self._values["subnet_group"] = subnet_group
        if vpc_subnets is not None:
            self._values["vpc_subnets"] = vpc_subnets

    @builtins.property
    def master_user(self) -> "Login":
        '''(experimental) Username and password for the administrative user.

        :stability: experimental
        '''
        result = self._values.get("master_user")
        assert result is not None, "Required property 'master_user' is missing"
        return typing.cast("Login", result)

    @builtins.property
    def vpc(self) -> aws_cdk.aws_ec2.IVpc:
        '''(experimental) The VPC to place the cluster in.

        :stability: experimental
        '''
        result = self._values.get("vpc")
        assert result is not None, "Required property 'vpc' is missing"
        return typing.cast(aws_cdk.aws_ec2.IVpc, result)

    @builtins.property
    def cluster_name(self) -> typing.Optional[builtins.str]:
        '''(experimental) An optional identifier for the cluster.

        :default: - A name is automatically generated.

        :stability: experimental
        '''
        result = self._values.get("cluster_name")
        return typing.cast(typing.Optional[builtins.str], result)

    @builtins.property
    def cluster_type(self) -> typing.Optional["ClusterType"]:
        '''(experimental) Settings for the individual instances that are launched.

        :default: {@link ClusterType.MULTI_NODE}

        :stability: experimental
        '''
        result = self._values.get("cluster_type")
        return typing.cast(typing.Optional["ClusterType"], result)

    @builtins.property
    def default_database_name(self) -> typing.Optional[builtins.str]:
        '''(experimental) Name of a database which is automatically created inside the cluster.

        :default: - default_db

        :stability: experimental
        '''
        result = self._values.get("default_database_name")
        return typing.cast(typing.Optional[builtins.str], result)

    @builtins.property
    def encrypted(self) -> typing.Optional[builtins.bool]:
        '''(experimental) Whether to enable encryption of data at rest in the cluster.

        :default: true

        :stability: experimental
        '''
        result = self._values.get("encrypted")
        return typing.cast(typing.Optional[builtins.bool], result)

    @builtins.property
    def encryption_key(self) -> typing.Optional[aws_cdk.aws_kms.IKey]:
        '''(experimental) The KMS key to use for encryption of data at rest.

        :default: - AWS-managed key, if encryption at rest is enabled

        :stability: experimental
        '''
        result = self._values.get("encryption_key")
        return typing.cast(typing.Optional[aws_cdk.aws_kms.IKey], result)

    @builtins.property
    def logging_bucket(self) -> typing.Optional[aws_cdk.aws_s3.IBucket]:
        '''(experimental) Bucket to send logs to.

        Logging information includes queries and connection attempts, for the specified Amazon Redshift cluster.

        :default: - No Logs

        :stability: experimental
        '''
        result = self._values.get("logging_bucket")
        return typing.cast(typing.Optional[aws_cdk.aws_s3.IBucket], result)

    @builtins.property
    def logging_key_prefix(self) -> typing.Optional[builtins.str]:
        '''(experimental) Prefix used for logging.

        :default: - no prefix

        :stability: experimental
        '''
        result = self._values.get("logging_key_prefix")
        return typing.cast(typing.Optional[builtins.str], result)

    @builtins.property
    def node_type(self) -> typing.Optional["NodeType"]:
        '''(experimental) The node type to be provisioned for the cluster.

        :default: {@link NodeType.DC2_LARGE}

        :stability: experimental
        '''
        result = self._values.get("node_type")
        return typing.cast(typing.Optional["NodeType"], result)

    @builtins.property
    def number_of_nodes(self) -> typing.Optional[jsii.Number]:
        '''(experimental) Number of compute nodes in the cluster. Only specify this property for multi-node clusters.

        Value must be at least 2 and no more than 100.

        :default: - 2 if ``clusterType`` is ClusterType.MULTI_NODE, undefined otherwise

        :stability: experimental
        '''
        result = self._values.get("number_of_nodes")
        return typing.cast(typing.Optional[jsii.Number], result)

    @builtins.property
    def parameter_group(self) -> typing.Optional["IClusterParameterGroup"]:
        '''(experimental) Additional parameters to pass to the database engine https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-parameter-groups.html.

        :default: - No parameter group.

        :stability: experimental
        '''
        result = self._values.get("parameter_group")
        return typing.cast(typing.Optional["IClusterParameterGroup"], result)

    @builtins.property
    def port(self) -> typing.Optional[jsii.Number]:
        '''(experimental) What port to listen on.

        :default: - The default for the engine is used.

        :stability: experimental
        '''
        result = self._values.get("port")
        return typing.cast(typing.Optional[jsii.Number], result)

    @builtins.property
    def preferred_maintenance_window(self) -> typing.Optional[builtins.str]:
        '''(experimental) A preferred maintenance window day/time range. Should be specified as a range ddd:hh24:mi-ddd:hh24:mi (24H Clock UTC).

        Example: 'Sun:23:45-Mon:00:15'

        :default:

        - 30-minute window selected at random from an 8-hour block of time for
        each AWS Region, occurring on a random day of the week.

        :see: https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_UpgradeDBInstance.Maintenance.html#Concepts.DBMaintenance
        :stability: experimental
        '''
        result = self._values.get("preferred_maintenance_window")
        return typing.cast(typing.Optional[builtins.str], result)

    @builtins.property
    def publicly_accessible(self) -> typing.Optional[builtins.bool]:
        '''(experimental) Whether to make cluster publicly accessible.

        :default: false

        :stability: experimental
        '''
        result = self._values.get("publicly_accessible")
        return typing.cast(typing.Optional[builtins.bool], result)

    @builtins.property
    def removal_policy(self) -> typing.Optional[aws_cdk.RemovalPolicy]:
        '''(experimental) The removal policy to apply when the cluster and its instances are removed from the stack or replaced during an update.

        :default: RemovalPolicy.RETAIN

        :stability: experimental
        '''
        result = self._values.get("removal_policy")
        return typing.cast(typing.Optional[aws_cdk.RemovalPolicy], result)

    @builtins.property
    def roles(self) -> typing.Optional[typing.List[aws_cdk.aws_iam.IRole]]:
        '''(experimental) A list of AWS Identity and Access Management (IAM) role that can be used by the cluster to access other AWS services.

        Specify a maximum of 10 roles.

        :default: - No role is attached to the cluster.

        :stability: experimental
        '''
        result = self._values.get("roles")
        return typing.cast(typing.Optional[typing.List[aws_cdk.aws_iam.IRole]], result)

    @builtins.property
    def security_groups(
        self,
    ) -> typing.Optional[typing.List[aws_cdk.aws_ec2.ISecurityGroup]]:
        '''(experimental) Security group.

        :default: - a new security group is created.

        :stability: experimental
        '''
        result = self._values.get("security_groups")
        return typing.cast(typing.Optional[typing.List[aws_cdk.aws_ec2.ISecurityGroup]], result)

    @builtins.property
    def subnet_group(self) -> typing.Optional["IClusterSubnetGroup"]:
        '''(experimental) A cluster subnet group to use with this cluster.

        :default: - a new subnet group will be created.

        :stability: experimental
        '''
        result = self._values.get("subnet_group")
        return typing.cast(typing.Optional["IClusterSubnetGroup"], result)

    @builtins.property
    def vpc_subnets(self) -> typing.Optional[aws_cdk.aws_ec2.SubnetSelection]:
        '''(experimental) Where to place the instances within the VPC.

        :default: - private subnets

        :stability: experimental
        '''
        result = self._values.get("vpc_subnets")
        return typing.cast(typing.Optional[aws_cdk.aws_ec2.SubnetSelection], result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "ClusterProps(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.ClusterSubnetGroupProps",
    jsii_struct_bases=[],
    name_mapping={
        "description": "description",
        "vpc": "vpc",
        "removal_policy": "removalPolicy",
        "vpc_subnets": "vpcSubnets",
    },
)
class ClusterSubnetGroupProps:
    def __init__(
        self,
        *,
        description: builtins.str,
        vpc: aws_cdk.aws_ec2.IVpc,
        removal_policy: typing.Optional[aws_cdk.RemovalPolicy] = None,
        vpc_subnets: typing.Optional[aws_cdk.aws_ec2.SubnetSelection] = None,
    ) -> None:
        '''(experimental) Properties for creating a ClusterSubnetGroup.

        :param description: (experimental) Description of the subnet group.
        :param vpc: (experimental) The VPC to place the subnet group in.
        :param removal_policy: (experimental) The removal policy to apply when the subnet group are removed from the stack or replaced during an update. Default: RemovalPolicy.RETAIN
        :param vpc_subnets: (experimental) Which subnets within the VPC to associate with this group. Default: - private subnets

        :stability: experimental
        '''
        if isinstance(vpc_subnets, dict):
            vpc_subnets = aws_cdk.aws_ec2.SubnetSelection(**vpc_subnets)
        self._values: typing.Dict[str, typing.Any] = {
            "description": description,
            "vpc": vpc,
        }
        if removal_policy is not None:
            self._values["removal_policy"] = removal_policy
        if vpc_subnets is not None:
            self._values["vpc_subnets"] = vpc_subnets

    @builtins.property
    def description(self) -> builtins.str:
        '''(experimental) Description of the subnet group.

        :stability: experimental
        '''
        result = self._values.get("description")
        assert result is not None, "Required property 'description' is missing"
        return typing.cast(builtins.str, result)

    @builtins.property
    def vpc(self) -> aws_cdk.aws_ec2.IVpc:
        '''(experimental) The VPC to place the subnet group in.

        :stability: experimental
        '''
        result = self._values.get("vpc")
        assert result is not None, "Required property 'vpc' is missing"
        return typing.cast(aws_cdk.aws_ec2.IVpc, result)

    @builtins.property
    def removal_policy(self) -> typing.Optional[aws_cdk.RemovalPolicy]:
        '''(experimental) The removal policy to apply when the subnet group are removed from the stack or replaced during an update.

        :default: RemovalPolicy.RETAIN

        :stability: experimental
        '''
        result = self._values.get("removal_policy")
        return typing.cast(typing.Optional[aws_cdk.RemovalPolicy], result)

    @builtins.property
    def vpc_subnets(self) -> typing.Optional[aws_cdk.aws_ec2.SubnetSelection]:
        '''(experimental) Which subnets within the VPC to associate with this group.

        :default: - private subnets

        :stability: experimental
        '''
        result = self._values.get("vpc_subnets")
        return typing.cast(typing.Optional[aws_cdk.aws_ec2.SubnetSelection], result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "ClusterSubnetGroupProps(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


@jsii.enum(jsii_type="@aws-cdk/aws-redshift-alpha.ClusterType")
class ClusterType(enum.Enum):
    '''(experimental) What cluster type to use.

    Used by {@link ClusterProps.clusterType}

    :stability: experimental
    '''

    SINGLE_NODE = "SINGLE_NODE"
    '''(experimental) single-node cluster, the {@link ClusterProps.numberOfNodes} parameter is not required.

    :stability: experimental
    '''
    MULTI_NODE = "MULTI_NODE"
    '''(experimental) multi-node cluster, set the amount of nodes using {@link ClusterProps.numberOfNodes} parameter.

    :stability: experimental
    '''


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.Column",
    jsii_struct_bases=[],
    name_mapping={"data_type": "dataType", "name": "name"},
)
class Column:
    def __init__(self, *, data_type: builtins.str, name: builtins.str) -> None:
        '''(experimental) A column in a Redshift table.

        :param data_type: (experimental) The data type of the column.
        :param name: (experimental) The name of the column.

        :stability: experimental
        '''
        self._values: typing.Dict[str, typing.Any] = {
            "data_type": data_type,
            "name": name,
        }

    @builtins.property
    def data_type(self) -> builtins.str:
        '''(experimental) The data type of the column.

        :stability: experimental
        '''
        result = self._values.get("data_type")
        assert result is not None, "Required property 'data_type' is missing"
        return typing.cast(builtins.str, result)

    @builtins.property
    def name(self) -> builtins.str:
        '''(experimental) The name of the column.

        :stability: experimental
        '''
        result = self._values.get("name")
        assert result is not None, "Required property 'name' is missing"
        return typing.cast(builtins.str, result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "Column(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.DatabaseOptions",
    jsii_struct_bases=[],
    name_mapping={
        "cluster": "cluster",
        "database_name": "databaseName",
        "admin_user": "adminUser",
    },
)
class DatabaseOptions:
    def __init__(
        self,
        *,
        cluster: "ICluster",
        database_name: builtins.str,
        admin_user: typing.Optional[aws_cdk.aws_secretsmanager.ISecret] = None,
    ) -> None:
        '''(experimental) Properties for accessing a Redshift database.

        :param cluster: (experimental) The cluster containing the database.
        :param database_name: (experimental) The name of the database.
        :param admin_user: (experimental) The secret containing credentials to a Redshift user with administrator privileges. Secret JSON schema: ``{ username: string; password: string }``. Default: - the admin secret is taken from the cluster

        :stability: experimental
        '''
        self._values: typing.Dict[str, typing.Any] = {
            "cluster": cluster,
            "database_name": database_name,
        }
        if admin_user is not None:
            self._values["admin_user"] = admin_user

    @builtins.property
    def cluster(self) -> "ICluster":
        '''(experimental) The cluster containing the database.

        :stability: experimental
        '''
        result = self._values.get("cluster")
        assert result is not None, "Required property 'cluster' is missing"
        return typing.cast("ICluster", result)

    @builtins.property
    def database_name(self) -> builtins.str:
        '''(experimental) The name of the database.

        :stability: experimental
        '''
        result = self._values.get("database_name")
        assert result is not None, "Required property 'database_name' is missing"
        return typing.cast(builtins.str, result)

    @builtins.property
    def admin_user(self) -> typing.Optional[aws_cdk.aws_secretsmanager.ISecret]:
        '''(experimental) The secret containing credentials to a Redshift user with administrator privileges.

        Secret JSON schema: ``{ username: string; password: string }``.

        :default: - the admin secret is taken from the cluster

        :stability: experimental
        '''
        result = self._values.get("admin_user")
        return typing.cast(typing.Optional[aws_cdk.aws_secretsmanager.ISecret], result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "DatabaseOptions(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


class DatabaseSecret(
    aws_cdk.aws_secretsmanager.Secret,
    metaclass=jsii.JSIIMeta,
    jsii_type="@aws-cdk/aws-redshift-alpha.DatabaseSecret",
):
    '''(experimental) A database secret.

    :stability: experimental
    :resource: AWS::SecretsManager::Secret
    '''

    def __init__(
        self,
        scope: constructs.Construct,
        id: builtins.str,
        *,
        username: builtins.str,
        encryption_key: typing.Optional[aws_cdk.aws_kms.IKey] = None,
    ) -> None:
        '''
        :param scope: -
        :param id: -
        :param username: (experimental) The username.
        :param encryption_key: (experimental) The KMS key to use to encrypt the secret. Default: default master key

        :stability: experimental
        '''
        props = DatabaseSecretProps(username=username, encryption_key=encryption_key)

        jsii.create(self.__class__, self, [scope, id, props])


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.DatabaseSecretProps",
    jsii_struct_bases=[],
    name_mapping={"username": "username", "encryption_key": "encryptionKey"},
)
class DatabaseSecretProps:
    def __init__(
        self,
        *,
        username: builtins.str,
        encryption_key: typing.Optional[aws_cdk.aws_kms.IKey] = None,
    ) -> None:
        '''(experimental) Construction properties for a DatabaseSecret.

        :param username: (experimental) The username.
        :param encryption_key: (experimental) The KMS key to use to encrypt the secret. Default: default master key

        :stability: experimental
        '''
        self._values: typing.Dict[str, typing.Any] = {
            "username": username,
        }
        if encryption_key is not None:
            self._values["encryption_key"] = encryption_key

    @builtins.property
    def username(self) -> builtins.str:
        '''(experimental) The username.

        :stability: experimental
        '''
        result = self._values.get("username")
        assert result is not None, "Required property 'username' is missing"
        return typing.cast(builtins.str, result)

    @builtins.property
    def encryption_key(self) -> typing.Optional[aws_cdk.aws_kms.IKey]:
        '''(experimental) The KMS key to use to encrypt the secret.

        :default: default master key

        :stability: experimental
        '''
        result = self._values.get("encryption_key")
        return typing.cast(typing.Optional[aws_cdk.aws_kms.IKey], result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "DatabaseSecretProps(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


class Endpoint(
    metaclass=jsii.JSIIMeta,
    jsii_type="@aws-cdk/aws-redshift-alpha.Endpoint",
):
    '''(experimental) Connection endpoint of a redshift cluster.

    Consists of a combination of hostname and port.

    :stability: experimental
    '''

    def __init__(self, address: builtins.str, port: jsii.Number) -> None:
        '''
        :param address: -
        :param port: -

        :stability: experimental
        '''
        jsii.create(self.__class__, self, [address, port])

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="hostname")
    def hostname(self) -> builtins.str:
        '''(experimental) The hostname of the endpoint.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "hostname"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="port")
    def port(self) -> jsii.Number:
        '''(experimental) The port of the endpoint.

        :stability: experimental
        '''
        return typing.cast(jsii.Number, jsii.get(self, "port"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="socketAddress")
    def socket_address(self) -> builtins.str:
        '''(experimental) The combination of "HOSTNAME:PORT" for this endpoint.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "socketAddress"))


@jsii.interface(jsii_type="@aws-cdk/aws-redshift-alpha.ICluster")
class ICluster(
    aws_cdk.IResource,
    aws_cdk.aws_ec2.IConnectable,
    aws_cdk.aws_secretsmanager.ISecretAttachmentTarget,
    typing_extensions.Protocol,
):
    '''(experimental) Create a Redshift Cluster with a given number of nodes.

    Implemented by {@link Cluster} via {@link ClusterBase}.

    :stability: experimental
    '''

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterEndpoint")
    def cluster_endpoint(self) -> Endpoint:
        '''(experimental) The endpoint to use for read/write operations.

        :stability: experimental
        :attribute: EndpointAddress,EndpointPort
        '''
        ...

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterName")
    def cluster_name(self) -> builtins.str:
        '''(experimental) Name of the cluster.

        :stability: experimental
        :attribute: ClusterName
        '''
        ...


class _IClusterProxy(
    jsii.proxy_for(aws_cdk.IResource), # type: ignore[misc]
    jsii.proxy_for(aws_cdk.aws_ec2.IConnectable), # type: ignore[misc]
    jsii.proxy_for(aws_cdk.aws_secretsmanager.ISecretAttachmentTarget), # type: ignore[misc]
):
    '''(experimental) Create a Redshift Cluster with a given number of nodes.

    Implemented by {@link Cluster} via {@link ClusterBase}.

    :stability: experimental
    '''

    __jsii_type__: typing.ClassVar[str] = "@aws-cdk/aws-redshift-alpha.ICluster"

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterEndpoint")
    def cluster_endpoint(self) -> Endpoint:
        '''(experimental) The endpoint to use for read/write operations.

        :stability: experimental
        :attribute: EndpointAddress,EndpointPort
        '''
        return typing.cast(Endpoint, jsii.get(self, "clusterEndpoint"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterName")
    def cluster_name(self) -> builtins.str:
        '''(experimental) Name of the cluster.

        :stability: experimental
        :attribute: ClusterName
        '''
        return typing.cast(builtins.str, jsii.get(self, "clusterName"))

# Adding a "__jsii_proxy_class__(): typing.Type" function to the interface
typing.cast(typing.Any, ICluster).__jsii_proxy_class__ = lambda : _IClusterProxy


@jsii.interface(jsii_type="@aws-cdk/aws-redshift-alpha.IClusterParameterGroup")
class IClusterParameterGroup(aws_cdk.IResource, typing_extensions.Protocol):
    '''(experimental) A parameter group.

    :stability: experimental
    '''

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterParameterGroupName")
    def cluster_parameter_group_name(self) -> builtins.str:
        '''(experimental) The name of this parameter group.

        :stability: experimental
        :attribute: true
        '''
        ...


class _IClusterParameterGroupProxy(
    jsii.proxy_for(aws_cdk.IResource) # type: ignore[misc]
):
    '''(experimental) A parameter group.

    :stability: experimental
    '''

    __jsii_type__: typing.ClassVar[str] = "@aws-cdk/aws-redshift-alpha.IClusterParameterGroup"

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterParameterGroupName")
    def cluster_parameter_group_name(self) -> builtins.str:
        '''(experimental) The name of this parameter group.

        :stability: experimental
        :attribute: true
        '''
        return typing.cast(builtins.str, jsii.get(self, "clusterParameterGroupName"))

# Adding a "__jsii_proxy_class__(): typing.Type" function to the interface
typing.cast(typing.Any, IClusterParameterGroup).__jsii_proxy_class__ = lambda : _IClusterParameterGroupProxy


@jsii.interface(jsii_type="@aws-cdk/aws-redshift-alpha.IClusterSubnetGroup")
class IClusterSubnetGroup(aws_cdk.IResource, typing_extensions.Protocol):
    '''(experimental) Interface for a cluster subnet group.

    :stability: experimental
    '''

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterSubnetGroupName")
    def cluster_subnet_group_name(self) -> builtins.str:
        '''(experimental) The name of the cluster subnet group.

        :stability: experimental
        :attribute: true
        '''
        ...


class _IClusterSubnetGroupProxy(
    jsii.proxy_for(aws_cdk.IResource) # type: ignore[misc]
):
    '''(experimental) Interface for a cluster subnet group.

    :stability: experimental
    '''

    __jsii_type__: typing.ClassVar[str] = "@aws-cdk/aws-redshift-alpha.IClusterSubnetGroup"

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterSubnetGroupName")
    def cluster_subnet_group_name(self) -> builtins.str:
        '''(experimental) The name of the cluster subnet group.

        :stability: experimental
        :attribute: true
        '''
        return typing.cast(builtins.str, jsii.get(self, "clusterSubnetGroupName"))

# Adding a "__jsii_proxy_class__(): typing.Type" function to the interface
typing.cast(typing.Any, IClusterSubnetGroup).__jsii_proxy_class__ = lambda : _IClusterSubnetGroupProxy


@jsii.interface(jsii_type="@aws-cdk/aws-redshift-alpha.ITable")
class ITable(constructs.IConstruct, typing_extensions.Protocol):
    '''(experimental) Represents a table in a Redshift database.

    :stability: experimental
    '''

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="cluster")
    def cluster(self) -> ICluster:
        '''(experimental) The cluster where the table is located.

        :stability: experimental
        '''
        ...

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="databaseName")
    def database_name(self) -> builtins.str:
        '''(experimental) The name of the database where the table is located.

        :stability: experimental
        '''
        ...

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="tableColumns")
    def table_columns(self) -> typing.List[Column]:
        '''(experimental) The columns of the table.

        :stability: experimental
        '''
        ...

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="tableName")
    def table_name(self) -> builtins.str:
        '''(experimental) Name of the table.

        :stability: experimental
        '''
        ...

    @jsii.member(jsii_name="grant")
    def grant(self, user: "IUser", *actions: "TableAction") -> None:
        '''(experimental) Grant a user privilege to access this table.

        :param user: -
        :param actions: -

        :stability: experimental
        '''
        ...


class _ITableProxy(
    jsii.proxy_for(constructs.IConstruct) # type: ignore[misc]
):
    '''(experimental) Represents a table in a Redshift database.

    :stability: experimental
    '''

    __jsii_type__: typing.ClassVar[str] = "@aws-cdk/aws-redshift-alpha.ITable"

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="cluster")
    def cluster(self) -> ICluster:
        '''(experimental) The cluster where the table is located.

        :stability: experimental
        '''
        return typing.cast(ICluster, jsii.get(self, "cluster"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="databaseName")
    def database_name(self) -> builtins.str:
        '''(experimental) The name of the database where the table is located.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "databaseName"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="tableColumns")
    def table_columns(self) -> typing.List[Column]:
        '''(experimental) The columns of the table.

        :stability: experimental
        '''
        return typing.cast(typing.List[Column], jsii.get(self, "tableColumns"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="tableName")
    def table_name(self) -> builtins.str:
        '''(experimental) Name of the table.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "tableName"))

    @jsii.member(jsii_name="grant")
    def grant(self, user: "IUser", *actions: "TableAction") -> None:
        '''(experimental) Grant a user privilege to access this table.

        :param user: -
        :param actions: -

        :stability: experimental
        '''
        return typing.cast(None, jsii.invoke(self, "grant", [user, *actions]))

# Adding a "__jsii_proxy_class__(): typing.Type" function to the interface
typing.cast(typing.Any, ITable).__jsii_proxy_class__ = lambda : _ITableProxy


@jsii.interface(jsii_type="@aws-cdk/aws-redshift-alpha.IUser")
class IUser(constructs.IConstruct, typing_extensions.Protocol):
    '''(experimental) Represents a user in a Redshift database.

    :stability: experimental
    '''

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="cluster")
    def cluster(self) -> ICluster:
        '''(experimental) The cluster where the table is located.

        :stability: experimental
        '''
        ...

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="databaseName")
    def database_name(self) -> builtins.str:
        '''(experimental) The name of the database where the table is located.

        :stability: experimental
        '''
        ...

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="password")
    def password(self) -> aws_cdk.SecretValue:
        '''(experimental) The password of the user.

        :stability: experimental
        '''
        ...

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="username")
    def username(self) -> builtins.str:
        '''(experimental) The name of the user.

        :stability: experimental
        '''
        ...

    @jsii.member(jsii_name="addTablePrivileges")
    def add_table_privileges(self, table: ITable, *actions: "TableAction") -> None:
        '''(experimental) Grant this user privilege to access a table.

        :param table: -
        :param actions: -

        :stability: experimental
        '''
        ...


class _IUserProxy(
    jsii.proxy_for(constructs.IConstruct) # type: ignore[misc]
):
    '''(experimental) Represents a user in a Redshift database.

    :stability: experimental
    '''

    __jsii_type__: typing.ClassVar[str] = "@aws-cdk/aws-redshift-alpha.IUser"

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="cluster")
    def cluster(self) -> ICluster:
        '''(experimental) The cluster where the table is located.

        :stability: experimental
        '''
        return typing.cast(ICluster, jsii.get(self, "cluster"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="databaseName")
    def database_name(self) -> builtins.str:
        '''(experimental) The name of the database where the table is located.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "databaseName"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="password")
    def password(self) -> aws_cdk.SecretValue:
        '''(experimental) The password of the user.

        :stability: experimental
        '''
        return typing.cast(aws_cdk.SecretValue, jsii.get(self, "password"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="username")
    def username(self) -> builtins.str:
        '''(experimental) The name of the user.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "username"))

    @jsii.member(jsii_name="addTablePrivileges")
    def add_table_privileges(self, table: ITable, *actions: "TableAction") -> None:
        '''(experimental) Grant this user privilege to access a table.

        :param table: -
        :param actions: -

        :stability: experimental
        '''
        return typing.cast(None, jsii.invoke(self, "addTablePrivileges", [table, *actions]))

# Adding a "__jsii_proxy_class__(): typing.Type" function to the interface
typing.cast(typing.Any, IUser).__jsii_proxy_class__ = lambda : _IUserProxy


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.Login",
    jsii_struct_bases=[],
    name_mapping={
        "master_username": "masterUsername",
        "encryption_key": "encryptionKey",
        "master_password": "masterPassword",
    },
)
class Login:
    def __init__(
        self,
        *,
        master_username: builtins.str,
        encryption_key: typing.Optional[aws_cdk.aws_kms.IKey] = None,
        master_password: typing.Optional[aws_cdk.SecretValue] = None,
    ) -> None:
        '''(experimental) Username and password combination.

        :param master_username: (experimental) Username.
        :param encryption_key: (experimental) KMS encryption key to encrypt the generated secret. Default: default master key
        :param master_password: (experimental) Password. Do not put passwords in your CDK code directly. Default: a Secrets Manager generated password

        :stability: experimental
        '''
        self._values: typing.Dict[str, typing.Any] = {
            "master_username": master_username,
        }
        if encryption_key is not None:
            self._values["encryption_key"] = encryption_key
        if master_password is not None:
            self._values["master_password"] = master_password

    @builtins.property
    def master_username(self) -> builtins.str:
        '''(experimental) Username.

        :stability: experimental
        '''
        result = self._values.get("master_username")
        assert result is not None, "Required property 'master_username' is missing"
        return typing.cast(builtins.str, result)

    @builtins.property
    def encryption_key(self) -> typing.Optional[aws_cdk.aws_kms.IKey]:
        '''(experimental) KMS encryption key to encrypt the generated secret.

        :default: default master key

        :stability: experimental
        '''
        result = self._values.get("encryption_key")
        return typing.cast(typing.Optional[aws_cdk.aws_kms.IKey], result)

    @builtins.property
    def master_password(self) -> typing.Optional[aws_cdk.SecretValue]:
        '''(experimental) Password.

        Do not put passwords in your CDK code directly.

        :default: a Secrets Manager generated password

        :stability: experimental
        '''
        result = self._values.get("master_password")
        return typing.cast(typing.Optional[aws_cdk.SecretValue], result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "Login(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


@jsii.enum(jsii_type="@aws-cdk/aws-redshift-alpha.NodeType")
class NodeType(enum.Enum):
    '''(experimental) Possible Node Types to use in the cluster used for defining {@link ClusterProps.nodeType}.

    :stability: experimental
    '''

    DS2_XLARGE = "DS2_XLARGE"
    '''(experimental) ds2.xlarge.

    :stability: experimental
    '''
    DS2_8XLARGE = "DS2_8XLARGE"
    '''(experimental) ds2.8xlarge.

    :stability: experimental
    '''
    DC1_LARGE = "DC1_LARGE"
    '''(experimental) dc1.large.

    :stability: experimental
    '''
    DC1_8XLARGE = "DC1_8XLARGE"
    '''(experimental) dc1.8xlarge.

    :stability: experimental
    '''
    DC2_LARGE = "DC2_LARGE"
    '''(experimental) dc2.large.

    :stability: experimental
    '''
    DC2_8XLARGE = "DC2_8XLARGE"
    '''(experimental) dc2.8xlarge.

    :stability: experimental
    '''
    RA3_XLPLUS = "RA3_XLPLUS"
    '''(experimental) ra3.xlplus.

    :stability: experimental
    '''
    RA3_4XLARGE = "RA3_4XLARGE"
    '''(experimental) ra3.4xlarge.

    :stability: experimental
    '''
    RA3_16XLARGE = "RA3_16XLARGE"
    '''(experimental) ra3.16xlarge.

    :stability: experimental
    '''


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.RotationMultiUserOptions",
    jsii_struct_bases=[],
    name_mapping={"secret": "secret", "automatically_after": "automaticallyAfter"},
)
class RotationMultiUserOptions:
    def __init__(
        self,
        *,
        secret: aws_cdk.aws_secretsmanager.ISecret,
        automatically_after: typing.Optional[aws_cdk.Duration] = None,
    ) -> None:
        '''(experimental) Options to add the multi user rotation.

        :param secret: (experimental) The secret to rotate. It must be a JSON string with the following format:: { "engine": <required: database engine>, "host": <required: instance host name>, "username": <required: username>, "password": <required: password>, "dbname": <optional: database name>, "port": <optional: if not specified, default port will be used>, "masterarn": <required: the arn of the master secret which will be used to create users/change passwords> }
        :param automatically_after: (experimental) Specifies the number of days after the previous rotation before Secrets Manager triggers the next automatic rotation. Default: Duration.days(30)

        :stability: experimental
        '''
        self._values: typing.Dict[str, typing.Any] = {
            "secret": secret,
        }
        if automatically_after is not None:
            self._values["automatically_after"] = automatically_after

    @builtins.property
    def secret(self) -> aws_cdk.aws_secretsmanager.ISecret:
        '''(experimental) The secret to rotate.

        It must be a JSON string with the following format::

           {
              "engine": <required: database engine>,
              "host": <required: instance host name>,
              "username": <required: username>,
              "password": <required: password>,
              "dbname": <optional: database name>,
              "port": <optional: if not specified, default port will be used>,
              "masterarn": <required: the arn of the master secret which will be used to create users/change passwords>
           }

        :stability: experimental
        '''
        result = self._values.get("secret")
        assert result is not None, "Required property 'secret' is missing"
        return typing.cast(aws_cdk.aws_secretsmanager.ISecret, result)

    @builtins.property
    def automatically_after(self) -> typing.Optional[aws_cdk.Duration]:
        '''(experimental) Specifies the number of days after the previous rotation before Secrets Manager triggers the next automatic rotation.

        :default: Duration.days(30)

        :stability: experimental
        '''
        result = self._values.get("automatically_after")
        return typing.cast(typing.Optional[aws_cdk.Duration], result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "RotationMultiUserOptions(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


@jsii.implements(ITable)
class Table(
    constructs.Construct,
    metaclass=jsii.JSIIMeta,
    jsii_type="@aws-cdk/aws-redshift-alpha.Table",
):
    '''(experimental) A table in a Redshift cluster.

    :stability: experimental
    '''

    def __init__(
        self,
        scope: constructs.Construct,
        id: builtins.str,
        *,
        table_columns: typing.Sequence[Column],
        removal_policy: typing.Optional[aws_cdk.RemovalPolicy] = None,
        table_name: typing.Optional[builtins.str] = None,
        cluster: ICluster,
        database_name: builtins.str,
        admin_user: typing.Optional[aws_cdk.aws_secretsmanager.ISecret] = None,
    ) -> None:
        '''
        :param scope: -
        :param id: -
        :param table_columns: (experimental) The columns of the table.
        :param removal_policy: (experimental) The policy to apply when this resource is removed from the application. Default: cdk.RemovalPolicy.Retain
        :param table_name: (experimental) The name of the table. Default: - a name is generated
        :param cluster: (experimental) The cluster containing the database.
        :param database_name: (experimental) The name of the database.
        :param admin_user: (experimental) The secret containing credentials to a Redshift user with administrator privileges. Secret JSON schema: ``{ username: string; password: string }``. Default: - the admin secret is taken from the cluster

        :stability: experimental
        '''
        props = TableProps(
            table_columns=table_columns,
            removal_policy=removal_policy,
            table_name=table_name,
            cluster=cluster,
            database_name=database_name,
            admin_user=admin_user,
        )

        jsii.create(self.__class__, self, [scope, id, props])

    @jsii.member(jsii_name="fromTableAttributes") # type: ignore[misc]
    @builtins.classmethod
    def from_table_attributes(
        cls,
        scope: constructs.Construct,
        id: builtins.str,
        *,
        cluster: ICluster,
        database_name: builtins.str,
        table_columns: typing.Sequence[Column],
        table_name: builtins.str,
    ) -> ITable:
        '''(experimental) Specify a Redshift table using a table name and schema that already exists.

        :param scope: -
        :param id: -
        :param cluster: (experimental) The cluster where the table is located.
        :param database_name: (experimental) The name of the database where the table is located.
        :param table_columns: (experimental) The columns of the table.
        :param table_name: (experimental) Name of the table.

        :stability: experimental
        '''
        attrs = TableAttributes(
            cluster=cluster,
            database_name=database_name,
            table_columns=table_columns,
            table_name=table_name,
        )

        return typing.cast(ITable, jsii.sinvoke(cls, "fromTableAttributes", [scope, id, attrs]))

    @jsii.member(jsii_name="applyRemovalPolicy")
    def apply_removal_policy(self, policy: aws_cdk.RemovalPolicy) -> None:
        '''(experimental) Apply the given removal policy to this resource.

        The Removal Policy controls what happens to this resource when it stops
        being managed by CloudFormation, either because you've removed it from the
        CDK application or because you've made a change that requires the resource
        to be replaced.

        The resource can be destroyed (``RemovalPolicy.DESTROY``), or left in your AWS
        account for data recovery and cleanup later (``RemovalPolicy.RETAIN``).

        This resource is retained by default.

        :param policy: -

        :stability: experimental
        '''
        return typing.cast(None, jsii.invoke(self, "applyRemovalPolicy", [policy]))

    @jsii.member(jsii_name="grant")
    def grant(self, user: IUser, *actions: "TableAction") -> None:
        '''(experimental) Grant a user privilege to access this table.

        :param user: -
        :param actions: -

        :stability: experimental
        '''
        return typing.cast(None, jsii.invoke(self, "grant", [user, *actions]))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="cluster")
    def cluster(self) -> ICluster:
        '''(experimental) The cluster where the table is located.

        :stability: experimental
        '''
        return typing.cast(ICluster, jsii.get(self, "cluster"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="databaseName")
    def database_name(self) -> builtins.str:
        '''(experimental) The name of the database where the table is located.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "databaseName"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="tableColumns")
    def table_columns(self) -> typing.List[Column]:
        '''(experimental) The columns of the table.

        :stability: experimental
        '''
        return typing.cast(typing.List[Column], jsii.get(self, "tableColumns"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="tableName")
    def table_name(self) -> builtins.str:
        '''(experimental) Name of the table.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "tableName"))


@jsii.enum(jsii_type="@aws-cdk/aws-redshift-alpha.TableAction")
class TableAction(enum.Enum):
    '''(experimental) An action that a Redshift user can be granted privilege to perform on a table.

    :stability: experimental
    '''

    SELECT = "SELECT"
    '''(experimental) Grants privilege to select data from a table or view using a SELECT statement.

    :stability: experimental
    '''
    INSERT = "INSERT"
    '''(experimental) Grants privilege to load data into a table using an INSERT statement or a COPY statement.

    :stability: experimental
    '''
    UPDATE = "UPDATE"
    '''(experimental) Grants privilege to update a table column using an UPDATE statement.

    :stability: experimental
    '''
    DELETE = "DELETE"
    '''(experimental) Grants privilege to delete a data row from a table.

    :stability: experimental
    '''
    DROP = "DROP"
    '''(experimental) Grants privilege to drop a table.

    :stability: experimental
    '''
    REFERENCES = "REFERENCES"
    '''(experimental) Grants privilege to create a foreign key constraint.

    You need to grant this privilege on both the referenced table and the referencing table; otherwise, the user can't create the constraint.

    :stability: experimental
    '''
    ALL = "ALL"
    '''(experimental) Grants all available privileges at once to the specified user or user group.

    :stability: experimental
    '''


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.TableAttributes",
    jsii_struct_bases=[],
    name_mapping={
        "cluster": "cluster",
        "database_name": "databaseName",
        "table_columns": "tableColumns",
        "table_name": "tableName",
    },
)
class TableAttributes:
    def __init__(
        self,
        *,
        cluster: ICluster,
        database_name: builtins.str,
        table_columns: typing.Sequence[Column],
        table_name: builtins.str,
    ) -> None:
        '''(experimental) A full specification of a Redshift table that can be used to import it fluently into the CDK application.

        :param cluster: (experimental) The cluster where the table is located.
        :param database_name: (experimental) The name of the database where the table is located.
        :param table_columns: (experimental) The columns of the table.
        :param table_name: (experimental) Name of the table.

        :stability: experimental
        '''
        self._values: typing.Dict[str, typing.Any] = {
            "cluster": cluster,
            "database_name": database_name,
            "table_columns": table_columns,
            "table_name": table_name,
        }

    @builtins.property
    def cluster(self) -> ICluster:
        '''(experimental) The cluster where the table is located.

        :stability: experimental
        '''
        result = self._values.get("cluster")
        assert result is not None, "Required property 'cluster' is missing"
        return typing.cast(ICluster, result)

    @builtins.property
    def database_name(self) -> builtins.str:
        '''(experimental) The name of the database where the table is located.

        :stability: experimental
        '''
        result = self._values.get("database_name")
        assert result is not None, "Required property 'database_name' is missing"
        return typing.cast(builtins.str, result)

    @builtins.property
    def table_columns(self) -> typing.List[Column]:
        '''(experimental) The columns of the table.

        :stability: experimental
        '''
        result = self._values.get("table_columns")
        assert result is not None, "Required property 'table_columns' is missing"
        return typing.cast(typing.List[Column], result)

    @builtins.property
    def table_name(self) -> builtins.str:
        '''(experimental) Name of the table.

        :stability: experimental
        '''
        result = self._values.get("table_name")
        assert result is not None, "Required property 'table_name' is missing"
        return typing.cast(builtins.str, result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "TableAttributes(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.TableProps",
    jsii_struct_bases=[DatabaseOptions],
    name_mapping={
        "cluster": "cluster",
        "database_name": "databaseName",
        "admin_user": "adminUser",
        "table_columns": "tableColumns",
        "removal_policy": "removalPolicy",
        "table_name": "tableName",
    },
)
class TableProps(DatabaseOptions):
    def __init__(
        self,
        *,
        cluster: ICluster,
        database_name: builtins.str,
        admin_user: typing.Optional[aws_cdk.aws_secretsmanager.ISecret] = None,
        table_columns: typing.Sequence[Column],
        removal_policy: typing.Optional[aws_cdk.RemovalPolicy] = None,
        table_name: typing.Optional[builtins.str] = None,
    ) -> None:
        '''(experimental) Properties for configuring a Redshift table.

        :param cluster: (experimental) The cluster containing the database.
        :param database_name: (experimental) The name of the database.
        :param admin_user: (experimental) The secret containing credentials to a Redshift user with administrator privileges. Secret JSON schema: ``{ username: string; password: string }``. Default: - the admin secret is taken from the cluster
        :param table_columns: (experimental) The columns of the table.
        :param removal_policy: (experimental) The policy to apply when this resource is removed from the application. Default: cdk.RemovalPolicy.Retain
        :param table_name: (experimental) The name of the table. Default: - a name is generated

        :stability: experimental
        '''
        self._values: typing.Dict[str, typing.Any] = {
            "cluster": cluster,
            "database_name": database_name,
            "table_columns": table_columns,
        }
        if admin_user is not None:
            self._values["admin_user"] = admin_user
        if removal_policy is not None:
            self._values["removal_policy"] = removal_policy
        if table_name is not None:
            self._values["table_name"] = table_name

    @builtins.property
    def cluster(self) -> ICluster:
        '''(experimental) The cluster containing the database.

        :stability: experimental
        '''
        result = self._values.get("cluster")
        assert result is not None, "Required property 'cluster' is missing"
        return typing.cast(ICluster, result)

    @builtins.property
    def database_name(self) -> builtins.str:
        '''(experimental) The name of the database.

        :stability: experimental
        '''
        result = self._values.get("database_name")
        assert result is not None, "Required property 'database_name' is missing"
        return typing.cast(builtins.str, result)

    @builtins.property
    def admin_user(self) -> typing.Optional[aws_cdk.aws_secretsmanager.ISecret]:
        '''(experimental) The secret containing credentials to a Redshift user with administrator privileges.

        Secret JSON schema: ``{ username: string; password: string }``.

        :default: - the admin secret is taken from the cluster

        :stability: experimental
        '''
        result = self._values.get("admin_user")
        return typing.cast(typing.Optional[aws_cdk.aws_secretsmanager.ISecret], result)

    @builtins.property
    def table_columns(self) -> typing.List[Column]:
        '''(experimental) The columns of the table.

        :stability: experimental
        '''
        result = self._values.get("table_columns")
        assert result is not None, "Required property 'table_columns' is missing"
        return typing.cast(typing.List[Column], result)

    @builtins.property
    def removal_policy(self) -> typing.Optional[aws_cdk.RemovalPolicy]:
        '''(experimental) The policy to apply when this resource is removed from the application.

        :default: cdk.RemovalPolicy.Retain

        :stability: experimental
        '''
        result = self._values.get("removal_policy")
        return typing.cast(typing.Optional[aws_cdk.RemovalPolicy], result)

    @builtins.property
    def table_name(self) -> typing.Optional[builtins.str]:
        '''(experimental) The name of the table.

        :default: - a name is generated

        :stability: experimental
        '''
        result = self._values.get("table_name")
        return typing.cast(typing.Optional[builtins.str], result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "TableProps(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


@jsii.implements(IUser)
class User(
    constructs.Construct,
    metaclass=jsii.JSIIMeta,
    jsii_type="@aws-cdk/aws-redshift-alpha.User",
):
    '''(experimental) A user in a Redshift cluster.

    :stability: experimental
    '''

    def __init__(
        self,
        scope: constructs.Construct,
        id: builtins.str,
        *,
        encryption_key: typing.Optional[aws_cdk.aws_kms.IKey] = None,
        removal_policy: typing.Optional[aws_cdk.RemovalPolicy] = None,
        username: typing.Optional[builtins.str] = None,
        cluster: ICluster,
        database_name: builtins.str,
        admin_user: typing.Optional[aws_cdk.aws_secretsmanager.ISecret] = None,
    ) -> None:
        '''
        :param scope: -
        :param id: -
        :param encryption_key: (experimental) KMS key to encrypt the generated secret. Default: - the default AWS managed key is used
        :param removal_policy: (experimental) The policy to apply when this resource is removed from the application. Default: cdk.RemovalPolicy.Destroy
        :param username: (experimental) The name of the user. For valid values, see: https://docs.aws.amazon.com/redshift/latest/dg/r_names.html Default: - a name is generated
        :param cluster: (experimental) The cluster containing the database.
        :param database_name: (experimental) The name of the database.
        :param admin_user: (experimental) The secret containing credentials to a Redshift user with administrator privileges. Secret JSON schema: ``{ username: string; password: string }``. Default: - the admin secret is taken from the cluster

        :stability: experimental
        '''
        props = UserProps(
            encryption_key=encryption_key,
            removal_policy=removal_policy,
            username=username,
            cluster=cluster,
            database_name=database_name,
            admin_user=admin_user,
        )

        jsii.create(self.__class__, self, [scope, id, props])

    @jsii.member(jsii_name="fromUserAttributes") # type: ignore[misc]
    @builtins.classmethod
    def from_user_attributes(
        cls,
        scope: constructs.Construct,
        id: builtins.str,
        *,
        password: aws_cdk.SecretValue,
        username: builtins.str,
        cluster: ICluster,
        database_name: builtins.str,
        admin_user: typing.Optional[aws_cdk.aws_secretsmanager.ISecret] = None,
    ) -> IUser:
        '''(experimental) Specify a Redshift user using credentials that already exist.

        :param scope: -
        :param id: -
        :param password: (experimental) The password of the user. Do not put passwords in CDK code directly.
        :param username: (experimental) The name of the user.
        :param cluster: (experimental) The cluster containing the database.
        :param database_name: (experimental) The name of the database.
        :param admin_user: (experimental) The secret containing credentials to a Redshift user with administrator privileges. Secret JSON schema: ``{ username: string; password: string }``. Default: - the admin secret is taken from the cluster

        :stability: experimental
        '''
        attrs = UserAttributes(
            password=password,
            username=username,
            cluster=cluster,
            database_name=database_name,
            admin_user=admin_user,
        )

        return typing.cast(IUser, jsii.sinvoke(cls, "fromUserAttributes", [scope, id, attrs]))

    @jsii.member(jsii_name="addTablePrivileges")
    def add_table_privileges(self, table: ITable, *actions: TableAction) -> None:
        '''(experimental) Grant this user privilege to access a table.

        :param table: -
        :param actions: -

        :stability: experimental
        '''
        return typing.cast(None, jsii.invoke(self, "addTablePrivileges", [table, *actions]))

    @jsii.member(jsii_name="applyRemovalPolicy")
    def apply_removal_policy(self, policy: aws_cdk.RemovalPolicy) -> None:
        '''(experimental) Apply the given removal policy to this resource.

        The Removal Policy controls what happens to this resource when it stops
        being managed by CloudFormation, either because you've removed it from the
        CDK application or because you've made a change that requires the resource
        to be replaced.

        The resource can be destroyed (``RemovalPolicy.DESTROY``), or left in your AWS
        account for data recovery and cleanup later (``RemovalPolicy.RETAIN``).

        This resource is destroyed by default.

        :param policy: -

        :stability: experimental
        '''
        return typing.cast(None, jsii.invoke(self, "applyRemovalPolicy", [policy]))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="cluster")
    def cluster(self) -> ICluster:
        '''(experimental) The cluster where the table is located.

        :stability: experimental
        '''
        return typing.cast(ICluster, jsii.get(self, "cluster"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="databaseName")
    def database_name(self) -> builtins.str:
        '''(experimental) The name of the database where the table is located.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "databaseName"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="password")
    def password(self) -> aws_cdk.SecretValue:
        '''(experimental) The password of the user.

        :stability: experimental
        '''
        return typing.cast(aws_cdk.SecretValue, jsii.get(self, "password"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="username")
    def username(self) -> builtins.str:
        '''(experimental) The name of the user.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "username"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="databaseProps")
    def _database_props(self) -> DatabaseOptions:
        '''
        :stability: experimental
        '''
        return typing.cast(DatabaseOptions, jsii.get(self, "databaseProps"))

    @_database_props.setter
    def _database_props(self, value: DatabaseOptions) -> None:
        jsii.set(self, "databaseProps", value)


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.UserAttributes",
    jsii_struct_bases=[DatabaseOptions],
    name_mapping={
        "cluster": "cluster",
        "database_name": "databaseName",
        "admin_user": "adminUser",
        "password": "password",
        "username": "username",
    },
)
class UserAttributes(DatabaseOptions):
    def __init__(
        self,
        *,
        cluster: ICluster,
        database_name: builtins.str,
        admin_user: typing.Optional[aws_cdk.aws_secretsmanager.ISecret] = None,
        password: aws_cdk.SecretValue,
        username: builtins.str,
    ) -> None:
        '''(experimental) A full specification of a Redshift user that can be used to import it fluently into the CDK application.

        :param cluster: (experimental) The cluster containing the database.
        :param database_name: (experimental) The name of the database.
        :param admin_user: (experimental) The secret containing credentials to a Redshift user with administrator privileges. Secret JSON schema: ``{ username: string; password: string }``. Default: - the admin secret is taken from the cluster
        :param password: (experimental) The password of the user. Do not put passwords in CDK code directly.
        :param username: (experimental) The name of the user.

        :stability: experimental
        '''
        self._values: typing.Dict[str, typing.Any] = {
            "cluster": cluster,
            "database_name": database_name,
            "password": password,
            "username": username,
        }
        if admin_user is not None:
            self._values["admin_user"] = admin_user

    @builtins.property
    def cluster(self) -> ICluster:
        '''(experimental) The cluster containing the database.

        :stability: experimental
        '''
        result = self._values.get("cluster")
        assert result is not None, "Required property 'cluster' is missing"
        return typing.cast(ICluster, result)

    @builtins.property
    def database_name(self) -> builtins.str:
        '''(experimental) The name of the database.

        :stability: experimental
        '''
        result = self._values.get("database_name")
        assert result is not None, "Required property 'database_name' is missing"
        return typing.cast(builtins.str, result)

    @builtins.property
    def admin_user(self) -> typing.Optional[aws_cdk.aws_secretsmanager.ISecret]:
        '''(experimental) The secret containing credentials to a Redshift user with administrator privileges.

        Secret JSON schema: ``{ username: string; password: string }``.

        :default: - the admin secret is taken from the cluster

        :stability: experimental
        '''
        result = self._values.get("admin_user")
        return typing.cast(typing.Optional[aws_cdk.aws_secretsmanager.ISecret], result)

    @builtins.property
    def password(self) -> aws_cdk.SecretValue:
        '''(experimental) The password of the user.

        Do not put passwords in CDK code directly.

        :stability: experimental
        '''
        result = self._values.get("password")
        assert result is not None, "Required property 'password' is missing"
        return typing.cast(aws_cdk.SecretValue, result)

    @builtins.property
    def username(self) -> builtins.str:
        '''(experimental) The name of the user.

        :stability: experimental
        '''
        result = self._values.get("username")
        assert result is not None, "Required property 'username' is missing"
        return typing.cast(builtins.str, result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "UserAttributes(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


@jsii.data_type(
    jsii_type="@aws-cdk/aws-redshift-alpha.UserProps",
    jsii_struct_bases=[DatabaseOptions],
    name_mapping={
        "cluster": "cluster",
        "database_name": "databaseName",
        "admin_user": "adminUser",
        "encryption_key": "encryptionKey",
        "removal_policy": "removalPolicy",
        "username": "username",
    },
)
class UserProps(DatabaseOptions):
    def __init__(
        self,
        *,
        cluster: ICluster,
        database_name: builtins.str,
        admin_user: typing.Optional[aws_cdk.aws_secretsmanager.ISecret] = None,
        encryption_key: typing.Optional[aws_cdk.aws_kms.IKey] = None,
        removal_policy: typing.Optional[aws_cdk.RemovalPolicy] = None,
        username: typing.Optional[builtins.str] = None,
    ) -> None:
        '''(experimental) Properties for configuring a Redshift user.

        :param cluster: (experimental) The cluster containing the database.
        :param database_name: (experimental) The name of the database.
        :param admin_user: (experimental) The secret containing credentials to a Redshift user with administrator privileges. Secret JSON schema: ``{ username: string; password: string }``. Default: - the admin secret is taken from the cluster
        :param encryption_key: (experimental) KMS key to encrypt the generated secret. Default: - the default AWS managed key is used
        :param removal_policy: (experimental) The policy to apply when this resource is removed from the application. Default: cdk.RemovalPolicy.Destroy
        :param username: (experimental) The name of the user. For valid values, see: https://docs.aws.amazon.com/redshift/latest/dg/r_names.html Default: - a name is generated

        :stability: experimental
        '''
        self._values: typing.Dict[str, typing.Any] = {
            "cluster": cluster,
            "database_name": database_name,
        }
        if admin_user is not None:
            self._values["admin_user"] = admin_user
        if encryption_key is not None:
            self._values["encryption_key"] = encryption_key
        if removal_policy is not None:
            self._values["removal_policy"] = removal_policy
        if username is not None:
            self._values["username"] = username

    @builtins.property
    def cluster(self) -> ICluster:
        '''(experimental) The cluster containing the database.

        :stability: experimental
        '''
        result = self._values.get("cluster")
        assert result is not None, "Required property 'cluster' is missing"
        return typing.cast(ICluster, result)

    @builtins.property
    def database_name(self) -> builtins.str:
        '''(experimental) The name of the database.

        :stability: experimental
        '''
        result = self._values.get("database_name")
        assert result is not None, "Required property 'database_name' is missing"
        return typing.cast(builtins.str, result)

    @builtins.property
    def admin_user(self) -> typing.Optional[aws_cdk.aws_secretsmanager.ISecret]:
        '''(experimental) The secret containing credentials to a Redshift user with administrator privileges.

        Secret JSON schema: ``{ username: string; password: string }``.

        :default: - the admin secret is taken from the cluster

        :stability: experimental
        '''
        result = self._values.get("admin_user")
        return typing.cast(typing.Optional[aws_cdk.aws_secretsmanager.ISecret], result)

    @builtins.property
    def encryption_key(self) -> typing.Optional[aws_cdk.aws_kms.IKey]:
        '''(experimental) KMS key to encrypt the generated secret.

        :default: - the default AWS managed key is used

        :stability: experimental
        '''
        result = self._values.get("encryption_key")
        return typing.cast(typing.Optional[aws_cdk.aws_kms.IKey], result)

    @builtins.property
    def removal_policy(self) -> typing.Optional[aws_cdk.RemovalPolicy]:
        '''(experimental) The policy to apply when this resource is removed from the application.

        :default: cdk.RemovalPolicy.Destroy

        :stability: experimental
        '''
        result = self._values.get("removal_policy")
        return typing.cast(typing.Optional[aws_cdk.RemovalPolicy], result)

    @builtins.property
    def username(self) -> typing.Optional[builtins.str]:
        '''(experimental) The name of the user.

        For valid values, see: https://docs.aws.amazon.com/redshift/latest/dg/r_names.html

        :default: - a name is generated

        :stability: experimental
        '''
        result = self._values.get("username")
        return typing.cast(typing.Optional[builtins.str], result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "UserProps(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


@jsii.implements(ICluster)
class Cluster(
    aws_cdk.Resource,
    metaclass=jsii.JSIIMeta,
    jsii_type="@aws-cdk/aws-redshift-alpha.Cluster",
):
    '''(experimental) Create a Redshift cluster a given number of nodes.

    :stability: experimental
    :resource: AWS::Redshift::Cluster
    '''

    def __init__(
        self,
        scope: constructs.Construct,
        id: builtins.str,
        *,
        master_user: Login,
        vpc: aws_cdk.aws_ec2.IVpc,
        cluster_name: typing.Optional[builtins.str] = None,
        cluster_type: typing.Optional[ClusterType] = None,
        default_database_name: typing.Optional[builtins.str] = None,
        encrypted: typing.Optional[builtins.bool] = None,
        encryption_key: typing.Optional[aws_cdk.aws_kms.IKey] = None,
        logging_bucket: typing.Optional[aws_cdk.aws_s3.IBucket] = None,
        logging_key_prefix: typing.Optional[builtins.str] = None,
        node_type: typing.Optional[NodeType] = None,
        number_of_nodes: typing.Optional[jsii.Number] = None,
        parameter_group: typing.Optional[IClusterParameterGroup] = None,
        port: typing.Optional[jsii.Number] = None,
        preferred_maintenance_window: typing.Optional[builtins.str] = None,
        publicly_accessible: typing.Optional[builtins.bool] = None,
        removal_policy: typing.Optional[aws_cdk.RemovalPolicy] = None,
        roles: typing.Optional[typing.Sequence[aws_cdk.aws_iam.IRole]] = None,
        security_groups: typing.Optional[typing.Sequence[aws_cdk.aws_ec2.ISecurityGroup]] = None,
        subnet_group: typing.Optional[IClusterSubnetGroup] = None,
        vpc_subnets: typing.Optional[aws_cdk.aws_ec2.SubnetSelection] = None,
    ) -> None:
        '''
        :param scope: -
        :param id: -
        :param master_user: (experimental) Username and password for the administrative user.
        :param vpc: (experimental) The VPC to place the cluster in.
        :param cluster_name: (experimental) An optional identifier for the cluster. Default: - A name is automatically generated.
        :param cluster_type: (experimental) Settings for the individual instances that are launched. Default: {@link ClusterType.MULTI_NODE}
        :param default_database_name: (experimental) Name of a database which is automatically created inside the cluster. Default: - default_db
        :param encrypted: (experimental) Whether to enable encryption of data at rest in the cluster. Default: true
        :param encryption_key: (experimental) The KMS key to use for encryption of data at rest. Default: - AWS-managed key, if encryption at rest is enabled
        :param logging_bucket: (experimental) Bucket to send logs to. Logging information includes queries and connection attempts, for the specified Amazon Redshift cluster. Default: - No Logs
        :param logging_key_prefix: (experimental) Prefix used for logging. Default: - no prefix
        :param node_type: (experimental) The node type to be provisioned for the cluster. Default: {@link NodeType.DC2_LARGE}
        :param number_of_nodes: (experimental) Number of compute nodes in the cluster. Only specify this property for multi-node clusters. Value must be at least 2 and no more than 100. Default: - 2 if ``clusterType`` is ClusterType.MULTI_NODE, undefined otherwise
        :param parameter_group: (experimental) Additional parameters to pass to the database engine https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-parameter-groups.html. Default: - No parameter group.
        :param port: (experimental) What port to listen on. Default: - The default for the engine is used.
        :param preferred_maintenance_window: (experimental) A preferred maintenance window day/time range. Should be specified as a range ddd:hh24:mi-ddd:hh24:mi (24H Clock UTC). Example: 'Sun:23:45-Mon:00:15' Default: - 30-minute window selected at random from an 8-hour block of time for each AWS Region, occurring on a random day of the week.
        :param publicly_accessible: (experimental) Whether to make cluster publicly accessible. Default: false
        :param removal_policy: (experimental) The removal policy to apply when the cluster and its instances are removed from the stack or replaced during an update. Default: RemovalPolicy.RETAIN
        :param roles: (experimental) A list of AWS Identity and Access Management (IAM) role that can be used by the cluster to access other AWS services. Specify a maximum of 10 roles. Default: - No role is attached to the cluster.
        :param security_groups: (experimental) Security group. Default: - a new security group is created.
        :param subnet_group: (experimental) A cluster subnet group to use with this cluster. Default: - a new subnet group will be created.
        :param vpc_subnets: (experimental) Where to place the instances within the VPC. Default: - private subnets

        :stability: experimental
        '''
        props = ClusterProps(
            master_user=master_user,
            vpc=vpc,
            cluster_name=cluster_name,
            cluster_type=cluster_type,
            default_database_name=default_database_name,
            encrypted=encrypted,
            encryption_key=encryption_key,
            logging_bucket=logging_bucket,
            logging_key_prefix=logging_key_prefix,
            node_type=node_type,
            number_of_nodes=number_of_nodes,
            parameter_group=parameter_group,
            port=port,
            preferred_maintenance_window=preferred_maintenance_window,
            publicly_accessible=publicly_accessible,
            removal_policy=removal_policy,
            roles=roles,
            security_groups=security_groups,
            subnet_group=subnet_group,
            vpc_subnets=vpc_subnets,
        )

        jsii.create(self.__class__, self, [scope, id, props])

    @jsii.member(jsii_name="fromClusterAttributes") # type: ignore[misc]
    @builtins.classmethod
    def from_cluster_attributes(
        cls,
        scope: constructs.Construct,
        id: builtins.str,
        *,
        cluster_endpoint_address: builtins.str,
        cluster_endpoint_port: jsii.Number,
        cluster_name: builtins.str,
        security_groups: typing.Optional[typing.Sequence[aws_cdk.aws_ec2.ISecurityGroup]] = None,
    ) -> ICluster:
        '''(experimental) Import an existing DatabaseCluster from properties.

        :param scope: -
        :param id: -
        :param cluster_endpoint_address: (experimental) Cluster endpoint address.
        :param cluster_endpoint_port: (experimental) Cluster endpoint port.
        :param cluster_name: (experimental) Identifier for the cluster.
        :param security_groups: (experimental) The security groups of the redshift cluster. Default: no security groups will be attached to the import

        :stability: experimental
        '''
        attrs = ClusterAttributes(
            cluster_endpoint_address=cluster_endpoint_address,
            cluster_endpoint_port=cluster_endpoint_port,
            cluster_name=cluster_name,
            security_groups=security_groups,
        )

        return typing.cast(ICluster, jsii.sinvoke(cls, "fromClusterAttributes", [scope, id, attrs]))

    @jsii.member(jsii_name="addRotationMultiUser")
    def add_rotation_multi_user(
        self,
        id: builtins.str,
        *,
        secret: aws_cdk.aws_secretsmanager.ISecret,
        automatically_after: typing.Optional[aws_cdk.Duration] = None,
    ) -> aws_cdk.aws_secretsmanager.SecretRotation:
        '''(experimental) Adds the multi user rotation to this cluster.

        :param id: -
        :param secret: (experimental) The secret to rotate. It must be a JSON string with the following format:: { "engine": <required: database engine>, "host": <required: instance host name>, "username": <required: username>, "password": <required: password>, "dbname": <optional: database name>, "port": <optional: if not specified, default port will be used>, "masterarn": <required: the arn of the master secret which will be used to create users/change passwords> }
        :param automatically_after: (experimental) Specifies the number of days after the previous rotation before Secrets Manager triggers the next automatic rotation. Default: Duration.days(30)

        :stability: experimental
        '''
        options = RotationMultiUserOptions(
            secret=secret, automatically_after=automatically_after
        )

        return typing.cast(aws_cdk.aws_secretsmanager.SecretRotation, jsii.invoke(self, "addRotationMultiUser", [id, options]))

    @jsii.member(jsii_name="addRotationSingleUser")
    def add_rotation_single_user(
        self,
        automatically_after: typing.Optional[aws_cdk.Duration] = None,
    ) -> aws_cdk.aws_secretsmanager.SecretRotation:
        '''(experimental) Adds the single user rotation of the master password to this cluster.

        :param automatically_after: Specifies the number of days after the previous rotation before Secrets Manager triggers the next automatic rotation.

        :stability: experimental
        '''
        return typing.cast(aws_cdk.aws_secretsmanager.SecretRotation, jsii.invoke(self, "addRotationSingleUser", [automatically_after]))

    @jsii.member(jsii_name="asSecretAttachmentTarget")
    def as_secret_attachment_target(
        self,
    ) -> aws_cdk.aws_secretsmanager.SecretAttachmentTargetProps:
        '''(experimental) Renders the secret attachment target specifications.

        :stability: experimental
        '''
        return typing.cast(aws_cdk.aws_secretsmanager.SecretAttachmentTargetProps, jsii.invoke(self, "asSecretAttachmentTarget", []))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterEndpoint")
    def cluster_endpoint(self) -> Endpoint:
        '''(experimental) The endpoint to use for read/write operations.

        :stability: experimental
        '''
        return typing.cast(Endpoint, jsii.get(self, "clusterEndpoint"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterName")
    def cluster_name(self) -> builtins.str:
        '''(experimental) Identifier of the cluster.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "clusterName"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="connections")
    def connections(self) -> aws_cdk.aws_ec2.Connections:
        '''(experimental) Access to the network connections.

        :stability: experimental
        '''
        return typing.cast(aws_cdk.aws_ec2.Connections, jsii.get(self, "connections"))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="secret")
    def secret(self) -> typing.Optional[aws_cdk.aws_secretsmanager.ISecret]:
        '''(experimental) The secret attached to this cluster.

        :stability: experimental
        '''
        return typing.cast(typing.Optional[aws_cdk.aws_secretsmanager.ISecret], jsii.get(self, "secret"))


@jsii.implements(IClusterParameterGroup)
class ClusterParameterGroup(
    aws_cdk.Resource,
    metaclass=jsii.JSIIMeta,
    jsii_type="@aws-cdk/aws-redshift-alpha.ClusterParameterGroup",
):
    '''(experimental) A cluster parameter group.

    :stability: experimental
    :resource: AWS::Redshift::ClusterParameterGroup
    '''

    def __init__(
        self,
        scope: constructs.Construct,
        id: builtins.str,
        *,
        parameters: typing.Mapping[builtins.str, builtins.str],
        description: typing.Optional[builtins.str] = None,
    ) -> None:
        '''
        :param scope: -
        :param id: -
        :param parameters: (experimental) The parameters in this parameter group.
        :param description: (experimental) Description for this parameter group. Default: a CDK generated description

        :stability: experimental
        '''
        props = ClusterParameterGroupProps(
            parameters=parameters, description=description
        )

        jsii.create(self.__class__, self, [scope, id, props])

    @jsii.member(jsii_name="fromClusterParameterGroupName") # type: ignore[misc]
    @builtins.classmethod
    def from_cluster_parameter_group_name(
        cls,
        scope: constructs.Construct,
        id: builtins.str,
        cluster_parameter_group_name: builtins.str,
    ) -> IClusterParameterGroup:
        '''(experimental) Imports a parameter group.

        :param scope: -
        :param id: -
        :param cluster_parameter_group_name: -

        :stability: experimental
        '''
        return typing.cast(IClusterParameterGroup, jsii.sinvoke(cls, "fromClusterParameterGroupName", [scope, id, cluster_parameter_group_name]))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterParameterGroupName")
    def cluster_parameter_group_name(self) -> builtins.str:
        '''(experimental) The name of the parameter group.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "clusterParameterGroupName"))


@jsii.implements(IClusterSubnetGroup)
class ClusterSubnetGroup(
    aws_cdk.Resource,
    metaclass=jsii.JSIIMeta,
    jsii_type="@aws-cdk/aws-redshift-alpha.ClusterSubnetGroup",
):
    '''(experimental) Class for creating a Redshift cluster subnet group.

    :stability: experimental
    :resource: AWS::Redshift::ClusterSubnetGroup
    '''

    def __init__(
        self,
        scope: constructs.Construct,
        id: builtins.str,
        *,
        description: builtins.str,
        vpc: aws_cdk.aws_ec2.IVpc,
        removal_policy: typing.Optional[aws_cdk.RemovalPolicy] = None,
        vpc_subnets: typing.Optional[aws_cdk.aws_ec2.SubnetSelection] = None,
    ) -> None:
        '''
        :param scope: -
        :param id: -
        :param description: (experimental) Description of the subnet group.
        :param vpc: (experimental) The VPC to place the subnet group in.
        :param removal_policy: (experimental) The removal policy to apply when the subnet group are removed from the stack or replaced during an update. Default: RemovalPolicy.RETAIN
        :param vpc_subnets: (experimental) Which subnets within the VPC to associate with this group. Default: - private subnets

        :stability: experimental
        '''
        props = ClusterSubnetGroupProps(
            description=description,
            vpc=vpc,
            removal_policy=removal_policy,
            vpc_subnets=vpc_subnets,
        )

        jsii.create(self.__class__, self, [scope, id, props])

    @jsii.member(jsii_name="fromClusterSubnetGroupName") # type: ignore[misc]
    @builtins.classmethod
    def from_cluster_subnet_group_name(
        cls,
        scope: constructs.Construct,
        id: builtins.str,
        cluster_subnet_group_name: builtins.str,
    ) -> IClusterSubnetGroup:
        '''(experimental) Imports an existing subnet group by name.

        :param scope: -
        :param id: -
        :param cluster_subnet_group_name: -

        :stability: experimental
        '''
        return typing.cast(IClusterSubnetGroup, jsii.sinvoke(cls, "fromClusterSubnetGroupName", [scope, id, cluster_subnet_group_name]))

    @builtins.property # type: ignore[misc]
    @jsii.member(jsii_name="clusterSubnetGroupName")
    def cluster_subnet_group_name(self) -> builtins.str:
        '''(experimental) The name of the cluster subnet group.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "clusterSubnetGroupName"))


__all__ = [
    "Cluster",
    "ClusterAttributes",
    "ClusterParameterGroup",
    "ClusterParameterGroupProps",
    "ClusterProps",
    "ClusterSubnetGroup",
    "ClusterSubnetGroupProps",
    "ClusterType",
    "Column",
    "DatabaseOptions",
    "DatabaseSecret",
    "DatabaseSecretProps",
    "Endpoint",
    "ICluster",
    "IClusterParameterGroup",
    "IClusterSubnetGroup",
    "ITable",
    "IUser",
    "Login",
    "NodeType",
    "RotationMultiUserOptions",
    "Table",
    "TableAction",
    "TableAttributes",
    "TableProps",
    "User",
    "UserAttributes",
    "UserProps",
]

publication.publish()
