import { Construct } from 'constructs'; import type { DataFormat } from './data-format'; import type { IDatabase } from './database'; import type { CfnTable } from './glue.generated'; import { type PartitionProjection } from './partition-projection'; import type { Column } from './schema'; import type { StorageParameter } from './storage-parameter'; import * as iam from '../../aws-iam'; import type { IResource } from '../../core'; import { Resource } from '../../core'; /** * Properties of a Partition Index. */ export interface PartitionIndex { /** * The name of the partition index. * * @default - a name will be generated for you. */ readonly indexName?: string; /** * The partition key names that comprise the partition * index. The names must correspond to a name in the * table's partition keys. */ readonly keyNames: string[]; } export interface ITable extends IResource { /** * @attribute */ readonly tableArn: string; /** * @attribute */ readonly tableName: string; } export interface TableAttributes { readonly tableArn: string; readonly tableName: string; } export interface TableBaseProps { /** * Name of the table. * * @default - generated by CDK. */ readonly tableName?: string; /** * Description of the table. * * @default generated */ readonly description?: string; /** * Database in which to store the table. */ readonly database: IDatabase; /** * Columns of the table. */ readonly columns: Column[]; /** * Partition columns of the table. * * @default table is not partitioned */ readonly partitionKeys?: Column[]; /** * Partition indexes on the table. A maximum of 3 indexes * are allowed on a table. Keys in the index must be part * of the table's partition keys. * * @default table has no partition indexes */ readonly partitionIndexes?: PartitionIndex[]; /** * Storage type of the table's data. */ readonly dataFormat: DataFormat; /** * Indicates whether the table's data is compressed or not. * * @default false */ readonly compressed?: boolean; /** * Indicates whether the table data is stored in subdirectories. * * @default false */ readonly storedAsSubDirectories?: boolean; /** * Enables partition filtering. * * @see https://docs.aws.amazon.com/athena/latest/ug/glue-best-practices.html#glue-best-practices-partition-index * * @default - The parameter is not defined */ readonly enablePartitionFiltering?: boolean; /** * The user-supplied properties for the description of the physical storage of this table. These properties help describe the format of the data that is stored within the crawled data sources. * * The key/value pairs that are allowed to be submitted are not limited, however their functionality is not guaranteed. * * Some keys will be auto-populated by glue crawlers, however, you can override them by specifying the key and value in this property. * * @see https://docs.aws.amazon.com/glue/latest/dg/table-properties-crawler.html * * @see https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_EXTERNAL_TABLE.html#r_CREATE_EXTERNAL_TABLE-parameters - under _"TABLE PROPERTIES"_ * * @example * * declare const glueDatabase: glue.IDatabase; * const table = new glue.S3Table(this, 'Table', { * storageParameters: [ * glue.StorageParameter.skipHeaderLineCount(1), * glue.StorageParameter.compressionType(glue.CompressionType.GZIP), * glue.StorageParameter.custom('foo', 'bar'), // Will have no effect * glue.StorageParameter.custom('separatorChar', ','), // Will describe the separator char used in the data * glue.StorageParameter.custom(glue.StorageParameters.WRITE_PARALLEL, 'off'), * ], * // ... * database: glueDatabase, * columns: [{ * name: 'col1', * type: glue.Schema.STRING, * }], * dataFormat: glue.DataFormat.CSV, * }); * * @default - The parameter is not defined */ readonly storageParameters?: StorageParameter[]; /** * The key/value pairs define properties associated with the table. * The key/value pairs that are allowed to be submitted are not limited, however their functionality is not guaranteed. * * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-glue-table-tableinput.html#cfn-glue-table-tableinput-parameters * * @default - The parameter is not defined */ readonly parameters?: { [key: string]: string; }; /** * Whether the data stored in the table is encrypted. * * This sets the `has_encrypted_data` table parameter. Athena reads it when * querying client-side (CSE-KMS) encrypted datasets; for server-side * encrypted (SSE-S3 / SSE-KMS) or unencrypted data it has no effect, since * Amazon S3 decrypts server-side encrypted objects transparently. * * Do not also set `has_encrypted_data` through `parameters` - use this * property instead. A conflicting value in `parameters` is rejected. * * @see https://docs.aws.amazon.com/athena/latest/ug/creating-tables-based-on-encrypted-datasets-in-s3.html * * @default true */ readonly hasEncryptedData?: boolean; /** * Partition projection configuration for this table. * * Partition projection allows Athena to automatically add new partitions * without requiring `ALTER TABLE ADD PARTITION` statements. * * @see https://docs.aws.amazon.com/athena/latest/ug/partition-projection.html * * @default - No partition projection */ readonly partitionProjection?: PartitionProjection; } /** * A Glue table. */ export declare abstract class TableBase extends Resource implements ITable { static fromTableArn(scope: Construct, id: string, tableArn: string): ITable; /** * Creates a Table construct that represents an external table. * * @param scope The scope creating construct (usually `this`). * @param id The construct's id. * @param attrs Import attributes */ static fromTableAttributes(scope: Construct, id: string, attrs: TableAttributes): ITable; protected abstract readonly tableResource: CfnTable; abstract readonly tableName: string; abstract readonly tableArn: string; abstract readonly partitionIndexes?: PartitionIndex[]; /** * Database this table belongs to. */ readonly database: IDatabase; /** * Indicates whether the table's data is compressed or not. */ readonly compressed: boolean; /** * Format of this table's data files. */ readonly dataFormat: DataFormat; /** * This table's columns. */ readonly columns: Column[]; /** * This table's partition keys if the table is partitioned. */ readonly partitionKeys?: Column[]; /** * The tables' storage descriptor properties. */ readonly storageParameters?: StorageParameter[]; /** * This table's partition projection configuration if enabled. */ readonly partitionProjection?: PartitionProjection; /** * The tables' properties associated with the table. * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-glue-table-tableinput.html#cfn-glue-table-tableinput-parameters */ protected readonly parameters: { [key: string]: string; }; /** * Whether the data stored in the table is encrypted. Emitted as the * `has_encrypted_data` table parameter. */ protected readonly hasEncryptedData: boolean; /** * Partition indexes must be created one at a time. To avoid * race conditions, we store the resource and add dependencies * each time a new partition index is created. */ private partitionIndexCustomResources; constructor(scope: Construct, id: string, props: TableBaseProps); abstract grantRead(grantee: iam.IGrantable): iam.Grant; abstract grantWrite(grantee: iam.IGrantable): iam.Grant; abstract grantReadWrite(grantee: iam.IGrantable): iam.Grant; /** * Add a partition index to the table. You can have a maximum of 3 partition * indexes to a table. Partition index keys must be a subset of the table's * partition keys. * * @see https://docs.aws.amazon.com/glue/latest/dg/partition-indexes.html */ addPartitionIndex(index: PartitionIndex): void; private generateIndexName; /** * Reconcile a `has_encrypted_data` value supplied through the free-form * `parameters` map with the typed `hasEncryptedData` property. * * `has_encrypted_data` is managed by this construct and emitted authoritatively * from `hasEncryptedData`. Supplying it through `parameters` as well is only * tolerated when the value is identical; a differing (or unresolved) value is * rejected so the two inputs can never silently disagree. On success the key is * removed from the free-form map so the managed value is the single source of * truth. */ private reconcileHasEncryptedData; private validatePartitionIndex; /** * Validate partition projection configuration and merge generated parameters into this.parameters. */ private validateAndGeneratePartitionProjection; /** * Grant the given identity custom permissions on this table. * * This is a low-level escape hatch: the `actions` are applied verbatim, * scoped to this table's ARN. Prefer the intent-based `grantRead` / * `grantWrite` / `grantReadWrite` methods, which grant a curated set of * actions and also cover the underlying S3 data. Only pass the specific * actions the grantee needs - avoid service wildcards such as `glue:*`. * [disable-awslint:no-grants] * * @param grantee the principal * @param actions the set of Glue actions to allow (for example `glue:GetTable`) */ grant(grantee: iam.IGrantable, actions: string[]): iam.Grant; /** * Grant the given identity custom permissions on this table AND its parent * catalog and database. * * This is a low-level escape hatch for actions (such as certain Lake * Formation or crawler operations) that must be authorized against the * catalog and database in addition to the table. The `actions` are applied * verbatim to all three ARNs (table, catalog, database), so scope them * tightly: pass only the specific actions the grantee needs and avoid * service wildcards such as `glue:*`, which would grant broad access across * every resource in the catalog and database. * [disable-awslint:no-grants] * * @param grantee the principal * @param actions the set of Glue actions to allow (for example `glue:GetTable`) */ grantToUnderlyingResources(grantee: iam.IGrantable, actions: string[]): iam.Grant; }