packages/@aws-cdk/aws-glue-alpha/lib/external-table.ts (113 lines of code) (raw):
import { CfnTable } from 'aws-cdk-lib/aws-glue';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
import { IConnection } from './connection';
import { Column } from './schema';
import { PartitionIndex, TableBase, TableBaseProps } from './table-base';
import { addConstructMetadata, MethodMetadata } from 'aws-cdk-lib/core/lib/metadata-resource';
export interface ExternalTableProps extends TableBaseProps {
/**
* The connection the table will use when performing reads and writes.
*
* @default - No connection
*/
readonly connection: IConnection;
/**
* The data source location of the glue table, (e.g. `default_db_public_example` for Redshift).
*
* If this property is set, it will override both `bucket` and `s3Prefix`.
*
* @default - No outsourced data source location
*/
readonly externalDataLocation: string;
}
/**
* A Glue table that targets an external data location (e.g. A table in a Redshift Cluster).
* @resource AWS::Glue::Table
*/
export class ExternalTable extends TableBase {
/**
* Name of this table.
*/
public readonly tableName: string;
/**
* ARN of this table.
*/
public readonly tableArn: string;
/**
* The connection associated to this table
*/
public readonly connection: IConnection;
/**
* This table's partition indexes.
*/
public readonly partitionIndexes?: PartitionIndex[];
protected readonly tableResource: CfnTable;
constructor(scope: Construct, id: string, props: ExternalTableProps) {
super(scope, id, props);
// Enhanced CDK Analytics Telemetry
addConstructMetadata(this, props);
this.connection = props.connection;
this.tableResource = new CfnTable(this, 'Table', {
catalogId: props.database.catalogId,
databaseName: props.database.databaseName,
tableInput: {
name: this.physicalName,
description: props.description || `${this.physicalName} generated by CDK`,
partitionKeys: renderColumns(props.partitionKeys),
parameters: {
'classification': props.dataFormat.classificationString?.value,
'has_encrypted_data': true,
'partition_filtering.enabled': props.enablePartitionFiltering,
'connectionName': props.connection.connectionName,
...props.parameters,
},
storageDescriptor: {
location: props.externalDataLocation,
compressed: this.compressed,
storedAsSubDirectories: props.storedAsSubDirectories ?? false,
columns: renderColumns(props.columns),
inputFormat: props.dataFormat.inputFormat.className,
outputFormat: props.dataFormat.outputFormat.className,
serdeInfo: {
serializationLibrary: props.dataFormat.serializationLibrary.className,
},
parameters: props.storageParameters ? props.storageParameters.reduce((acc, param) => {
if (param.key in acc) {
throw new Error(`Duplicate storage parameter key: ${param.key}`);
}
const key = param.key;
acc[key] = param.value;
return acc;
}, {} as { [key: string]: string }) : undefined,
},
tableType: 'EXTERNAL_TABLE',
},
});
this.tableName = this.getResourceNameAttribute(this.tableResource.ref);
this.tableArn = this.stack.formatArn({
service: 'glue',
resource: 'table',
resourceName: `${this.database.databaseName}/${this.tableName}`,
});
this.node.defaultChild = this.tableResource;
// Partition index creation relies on created table.
if (props.partitionIndexes) {
this.partitionIndexes = props.partitionIndexes;
this.partitionIndexes.forEach((index) => this.addPartitionIndex(index));
}
}
/**
* Grant read permissions to the table
*
* @param grantee the principal
*/
@MethodMetadata()
public grantRead(grantee: iam.IGrantable): iam.Grant {
const ret = this.grant(grantee, readPermissions);
return ret;
}
/**
* Grant write permissions to the table
*
* @param grantee the principal
*/
@MethodMetadata()
public grantWrite(grantee: iam.IGrantable): iam.Grant {
const ret = this.grant(grantee, writePermissions);
return ret;
}
/**
* Grant read and write permissions to the table
*
* @param grantee the principal
*/
@MethodMetadata()
public grantReadWrite(grantee: iam.IGrantable): iam.Grant {
const ret = this.grant(grantee, [...readPermissions, ...writePermissions]);
return ret;
}
}
const readPermissions = [
'glue:BatchGetPartition',
'glue:GetPartition',
'glue:GetPartitions',
'glue:GetTable',
'glue:GetTables',
'glue:GetTableVersion',
'glue:GetTableVersions',
];
const writePermissions = [
'glue:BatchCreatePartition',
'glue:BatchDeletePartition',
'glue:CreatePartition',
'glue:DeletePartition',
'glue:UpdatePartition',
];
function renderColumns(columns?: Array<Column | Column>) {
if (columns === undefined) {
return undefined;
}
return columns.map(column => {
return {
name: column.name,
type: column.type.inputString,
comment: column.comment,
};
});
}