Table creation #307
Unanswered
benjstephenson
asked this question in
Q&A
Replies: 2 comments 1 reply
-
Creating the table is a little out of Electro's scope, but making a function that could translate an Electro schema type to a table definition (CloudFormation, CreateTable command, CDK, etc) would be pretty simple 👍 You could iterate over the attributes for field names and types and iterate over the indexes for GSIs and fields. |
Beta Was this translation helpful? Give feedback.
0 replies
-
Something like this: import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Stack, StackProps, RemovalPolicy } from 'aws-cdk-lib';
import { Construct } from "constructs";
import { Entity, Schema } from "electrodb";
type NonSpecificEntity = Entity<string, string, string, Schema<string, string, string>>
type NonSpecificEntityIndex = NonSpecificEntity['schema']['indexes'][string];
type TableIndexDefinition = {
type: 'TableIndex';
partitionKey: dynamodb.Attribute;
sortKey?: dynamodb.Attribute;
}
type SecondaryIndexDefinition = {
type: 'SecondaryIndex';
indexName: string;
partitionKey: dynamodb.Attribute;
sortKey?: dynamodb.Attribute;
projectionType: dynamodb.ProjectionType;
}
type LocalSecondaryIndexDefinition = {
type: 'LocalSecondaryIndex';
indexName: string;
sortKey: dynamodb.Attribute;
projectionType: dynamodb.ProjectionType;
}
type IndexDefinition =
| TableIndexDefinition
| SecondaryIndexDefinition
| LocalSecondaryIndexDefinition;
function getTableIndexName<E extends Entity<any, any, any, any>>(entity: E): string {
const { schema } = entity;
let tableIndexName: string | null = null;
for (let accessPattern in schema.indexes) {
const indexDefinition = schema.indexes[accessPattern];
if (indexDefinition.index === undefined) {
tableIndexName = accessPattern;
break;
}
}
if (tableIndexName === null) {
throw new Error('No table index found');
}
return tableIndexName;
}
function createTableIndexDefinition(indexDefinition: NonSpecificEntityIndex): TableIndexDefinition {
return {
type: 'TableIndex',
partitionKey: {
name: indexDefinition.pk.field,
type: dynamodb.AttributeType.STRING
},
sortKey: indexDefinition.sk ? {
name: indexDefinition.sk.field,
type: dynamodb.AttributeType.STRING
} : undefined
}
}
function createSecondaryIndexDefinition(indexDefinition: NonSpecificEntityIndex): SecondaryIndexDefinition {
return {
type: 'SecondaryIndex',
indexName: indexDefinition.index!,
partitionKey: {
name: indexDefinition.pk.field,
type: dynamodb.AttributeType.STRING
},
sortKey: indexDefinition.sk ? {
name: indexDefinition.sk.field,
type: dynamodb.AttributeType.STRING
} : undefined,
projectionType: indexDefinition.project === 'keys_only'
? dynamodb.ProjectionType.KEYS_ONLY
: dynamodb.ProjectionType.ALL,
}
}
function createLocalSecondaryIndexDefinition(indexDefinition: NonSpecificEntityIndex): LocalSecondaryIndexDefinition {
return {
type: 'LocalSecondaryIndex',
indexName: indexDefinition.index!,
sortKey: {
name: indexDefinition.sk!.field,
type: dynamodb.AttributeType.STRING
},
projectionType: indexDefinition.project === 'keys_only'
? dynamodb.ProjectionType.KEYS_ONLY
: dynamodb.ProjectionType.ALL,
}
}
function getIndexes(entity: NonSpecificEntity): IndexDefinition[] {
const { schema } = entity;
const indexes: IndexDefinition[] = [];
const tableIndexName = getTableIndexName(entity);
for (const accessPattern in schema.indexes) {
const indexDefinition = schema.indexes[accessPattern];
if (indexDefinition.index !== undefined && indexDefinition.index === tableIndexName) {
indexes.push(createTableIndexDefinition(indexDefinition));
} else if (accessPattern === tableIndexName) {
indexes.push(createLocalSecondaryIndexDefinition(indexDefinition));
} else {
indexes.push(createSecondaryIndexDefinition(indexDefinition));
}
}
return indexes;
}
function getTableIndex(indexDefinitions: IndexDefinition[]) {
for (const tableDefinition of indexDefinitions) {
if (tableDefinition.type === 'TableIndex') {
return tableDefinition;
}
}
throw new Error('No table index found');
}
function getTableName(entity: NonSpecificEntity) {
const tableName = entity.getTableName();
if (!tableName) {
throw new Error('No table name found');
}
return tableName;
}
interface AwsCdkElectroDBTableStackProps extends StackProps {
entity: NonSpecificEntity;
}
export class AwsCdkElectroDBTableStack extends Stack {
constructor(scope: Construct, id: string, props: AwsCdkElectroDBTableStackProps) {
super(scope, id, props);
const { entity } = props;
const tableName = getTableName(entity);
const indexDefinitions = getIndexes(entity);
const tableIndex = getTableIndex(indexDefinitions);
const table = new dynamodb.Table(this, tableName, {
partitionKey: tableIndex.partitionKey,
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: RemovalPolicy.DESTROY,
sortKey: tableIndex.sortKey,
pointInTimeRecovery: true,
tableClass: dynamodb.TableClass.STANDARD,
});
for (let indexDefinition of indexDefinitions) {
if (indexDefinition.type === 'TableIndex') {
continue;
}
if (indexDefinition.type === 'SecondaryIndex') {
table.addGlobalSecondaryIndex({
indexName: indexDefinition.indexName,
partitionKey: indexDefinition.partitionKey,
sortKey: indexDefinition.sortKey,
projectionType: indexDefinition.projectionType,
});
} else if (indexDefinition.type === 'LocalSecondaryIndex') {
table.addLocalSecondaryIndex({
indexName: indexDefinition.indexName,
sortKey: indexDefinition.sortKey,
projectionType: indexDefinition.projectionType,
});
}
}
}
} |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Is it possible to create Dynamo tables using Eletro? I can't find anything in the docs that points to it and I don't really want to have to maintain a separate schema definition for creating tables and also the one for use with the Entity classes; unless there's a way to reuse the definition with the aws-sdk?
Beta Was this translation helpful? Give feedback.
All reactions