Skip to content

Instantly share code, notes, and snippets.

@andrestone
Last active March 27, 2023 07:18
Show Gist options
  • Save andrestone/278ef74b3f2775a4d13abc472f3ea0b2 to your computer and use it in GitHub Desktop.
Save andrestone/278ef74b3f2775a4d13abc472f3ea0b2 to your computer and use it in GitHub Desktop.
`create` with `SetAttribute` with no client results in `DynamoDBSet` being passed as param.
import * as AWS from "@aws-sdk/client-dynamodb";
import { Entity, Service } from "../../";
const table = "your_table_name";
export const configuration = {
endpoint: "http://localhost:8000",
region: "us-east-1"
};
const client = new AWS.DynamoDB(configuration);
const dynamodb = client;
const definition = {
"KeySchema":[
{
"AttributeName":"pk",
"KeyType":"HASH"
},
{
"AttributeName":"sk",
"KeyType":"RANGE"
}
],
"AttributeDefinitions":[
{
"AttributeName":"pk",
"AttributeType":"S"
},
{
"AttributeName":"sk",
"AttributeType":"S"
},
{
"AttributeName":"gsi1pk",
"AttributeType":"S"
},
{
"AttributeName":"gsi1sk",
"AttributeType":"S"
},
{
"AttributeName":"gsi2pk",
"AttributeType":"S"
},
{
"AttributeName":"gsi2sk",
"AttributeType":"S"
},
{
"AttributeName":"gsi3pk",
"AttributeType":"S"
},
{
"AttributeName":"gsi3sk",
"AttributeType":"S"
},
{
"AttributeName":"gsi4pk",
"AttributeType":"S"
},
{
"AttributeName":"gsi4sk",
"AttributeType":"S"
},
{
"AttributeName":"gsi5pk",
"AttributeType":"S"
},
{
"AttributeName":"gsi5sk",
"AttributeType":"S"
}
],
"GlobalSecondaryIndexes":[
{
"IndexName":"gsi1pk-gsi1sk-index",
"KeySchema":[
{
"AttributeName":"gsi1pk",
"KeyType":"HASH"
},
{
"AttributeName":"gsi1sk",
"KeyType":"RANGE"
}
],
"Projection":{
"ProjectionType":"ALL"
}
},
{
"IndexName":"gsi2pk-gsi2sk-index",
"KeySchema":[
{
"AttributeName":"gsi2pk",
"KeyType":"HASH"
},
{
"AttributeName":"gsi2sk",
"KeyType":"RANGE"
}
],
"Projection":{
"ProjectionType":"ALL"
}
},
{
"IndexName":"gsi3pk-gsi3sk-index",
"KeySchema":[
{
"AttributeName":"gsi3pk",
"KeyType":"HASH"
},
{
"AttributeName":"gsi3sk",
"KeyType":"RANGE"
}
],
"Projection":{
"ProjectionType":"ALL"
}
},
{
"IndexName":"gsi4pk-gsi4sk-index",
"KeySchema":[
{
"AttributeName":"gsi4pk",
"KeyType":"HASH"
},
{
"AttributeName":"gsi4sk",
"KeyType":"RANGE"
}
],
"Projection":{
"ProjectionType":"ALL"
}
},
{
"IndexName":"gsi5pk-gsi5sk-index",
"KeySchema":[
{
"AttributeName":"gsi5pk",
"KeyType":"HASH"
},
{
"AttributeName":"gsi5sk",
"KeyType":"RANGE"
}
],
"Projection":{
"ProjectionType":"ALL"
}
}
],
"BillingMode":"PAY_PER_REQUEST"
}
export function createTableManager() {
return {
async exists() {
let tables = await dynamodb.listTables({});
return !!tables.TableNames?.includes(table);
},
async drop() {
return dynamodb.deleteTable({TableName: table});
},
async create() {
return dynamodb.createTable({...definition, TableName: table});
}
}
}
async function initializeTable() {
const tableManager = createTableManager();
const exists = await tableManager.exists();
if (exists) {
await tableManager.drop();
}
await tableManager.create();
}
/* Users Entity */
const users = new Entity(
{
model: {
entity: "user",
service: "taskapp",
version: "1"
},
attributes: {
team: {
type: "string"
},
user: {
type: "string"
},
role: {
type: ["dev", "senior", "staff", "principal"] as const,
set: (title: string) => {
// save as index for comparison
return [
"dev",
"senior",
"staff",
"principal"
].indexOf(title);
},
get: (index: number) => {
return [
"dev",
"senior",
"staff",
"principal"
][index] || "other";
}
},
manager: {
type: "set",
items: ["frank", "jane", "joe", "sally"] as const,
},
firstName: {
type: "string"
},
lastName: {
type: "string"
},
fullName: {
type: "string",
// never set value to the database
set: () => undefined,
// calculate full name on retrieval
get: (_, {firstName, lastName}) => {
return `${firstName ?? ""} ${lastName ?? ""}`.trim();
}
},
profile: {
type: "map",
properties: {
photo: {
type: "string"
},
bio: {
type: "string"
},
location: {
type: "string"
}
}
},
pinned: {
type: "any"
},
following: {
type: "set",
items: "string"
},
followers: {
type: "set",
items: "string"
},
createdAt: {
type: "number",
default: () => Date.now(),
readOnly: true
},
updatedAt: {
type: "number",
watch: "*",
set: () => Date.now(),
readOnly: true
}
},
indexes: {
members: {
collection: "organization",
pk: {
composite: ["team"],
field: "pk"
},
sk: {
composite: ["user"],
field: "sk"
}
},
user: {
collection: "assignments",
index: "gsi1pk-gsi1sk-index",
pk: {
composite: ["user"],
field: "gsi1pk"
},
sk: {
field: "gsi1sk",
composite: []
}
}
}
},
{ table }
);
new Service({ users }, { table, client, });
/* Write queries to generate parameters on the right */
const run = async () => {
await initializeTable();
// `create` is like `put` except it uses "attribute_not_exists"
// to ensure you do not overwrite a record that already exists
users.create({
team: "purple",
user: "t.walch",
role: "senior",
lastName: "walch",
firstName: "tyler",
manager: ["jane", "frank"], // This fails if Entity is instantiated without a client
profile: {
bio: "makes things",
photo: "selfie.jpg",
location: "atlanta"
},
// interact with DynamoDB sets like arrays
following: ["d.purdy"]
}).go();
};
run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment