Skip to content

Commit

Permalink
Tidy up dynamodb schema and UI store (#59)
Browse files Browse the repository at this point in the history
* Fix double fetch issue

* Tidy dynamoDB schema

* Tidy up album store

* Update test
  • Loading branch information
LaurenceHo committed Jun 9, 2024
1 parent ed653b0 commit 0d23920
Show file tree
Hide file tree
Showing 25 changed files with 562 additions and 617 deletions.
41 changes: 21 additions & 20 deletions server/src/aggregations/albums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const handler: Handler = async (event: DynamoDBStreamEvent, context, call
const albumsHavePlace = albumLists.filter((album) => album.place != null);
const featuredAlbums = albumLists.filter((album) => album.isFeatured);
const albumsByYear = albumLists
.sort((a, b) => (a.year > b.year ? 1 : -1))
.sort((a, b) => (a.year > b.year ? -1 : 1))
.reduce(
(acc, album) => {
if (!acc[album.year]) {
Expand All @@ -36,26 +36,27 @@ export const handler: Handler = async (event: DynamoDBStreamEvent, context, call
);

try {
// Insert albums with location
await DataAggregationEntity.update({
key: ALBUM_WITH_LOCATIONS,
})
.set({ value: albumsHavePlace, updatedAt: new Date().toISOString() })
.go({ response: 'none' });
await Promise.all([
// Insert albums with location
DataAggregationEntity.update({
key: ALBUM_WITH_LOCATIONS,
})
.set({ value: albumsHavePlace, updatedAt: new Date().toISOString() })
.go({ response: 'none' }),
// Insert featured albums
DataAggregationEntity.update({
key: FEATURED_ALBUMS,
})
.set({ value: featuredAlbums, updatedAt: new Date().toISOString() })
.go({ response: 'none' }),
// Insert albums by year
DataAggregationEntity.update({
key: ALBUM_BY_YEARS,
})
.set({ value: albumsByYear, updatedAt: new Date().toISOString() })
.go({ response: 'none' }),
]);

// Insert featured albums
await DataAggregationEntity.update({
key: FEATURED_ALBUMS,
})
.set({ value: featuredAlbums, updatedAt: new Date().toISOString() })
.go({ response: 'none' });

// Insert albums by year
await DataAggregationEntity.update({
key: ALBUM_BY_YEARS,
})
.set({ value: albumsByYear, updatedAt: new Date().toISOString() })
.go({ response: 'none' });
callback(null, 'success');
} catch (err: any) {
callback(err);
Expand Down
22 changes: 11 additions & 11 deletions server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { app } from './app.js';
import { uploadObject } from './controllers/helpers.js';
import { initialiseDynamodbTables } from './services/initialise-dynamodb-tables.js';
import S3Service from './services/s3-service.js';

try {
const s3Service = new S3Service();
await initialiseDynamodbTables();
console.log('Finish verifying DynamoDB tables.');

const exists = await s3Service.checkObject({ Bucket: process.env.AWS_S3_BUCKET_NAME, Key: 'updateDatabaseAt.json' });
if (!exists) {
console.log('updateDatabaseAt.json does not exist');
await uploadObject('updateDatabaseAt.json', JSON.stringify({ time: new Date().toISOString() }));
}
const s3Service = new S3Service();

await app.listen({ port: 3000 });
console.log('App is listening on port 3000.🚀🚀🚀');
} catch (err) {
console.error(err);
const exists = await s3Service.checkObject({ Bucket: process.env.AWS_S3_BUCKET_NAME, Key: 'updateDatabaseAt.json' });
if (!exists) {
console.log('updateDatabaseAt.json does not exist');
await uploadObject('updateDatabaseAt.json', JSON.stringify({ time: new Date().toISOString() }));
}

await app.listen({ port: 3000 });
console.log('App is listening on port 3000.🚀🚀🚀');
21 changes: 0 additions & 21 deletions server/src/schemas/album-tag.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,10 @@
import { CreateTableCommandInput } from '@aws-sdk/client-dynamodb';
import { Entity, EntityRecord } from 'electrodb';
import { ddbDocClient } from '../services/dynamodb-client.js';

export type AlbumTag = EntityRecord<typeof AlbumTagEntity>;

export const albumTagsTableName = process.env.PHOTO_ALBUM_TAGS_TABLE_NAME || 'photo-album-tags';

export const albumTagsTableSchema: CreateTableCommandInput = {
AttributeDefinitions: [
{
AttributeName: 'tag',
AttributeType: 'S',
},
],
KeySchema: [
{
AttributeName: 'tag',
KeyType: 'HASH',
},
],
ProvisionedThroughput: {
ReadCapacityUnits: 4,
WriteCapacityUnits: 4,
},
TableName: albumTagsTableName,
};

export const AlbumTagEntity = new Entity(
{
model: {
Expand Down
29 changes: 0 additions & 29 deletions server/src/schemas/album.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { CreateTableCommandInput } from '@aws-sdk/client-dynamodb';
import { CustomAttributeType, Entity, EntityRecord } from 'electrodb';
import { Place } from '../models.js';
import { ddbDocClient } from '../services/dynamodb-client.js';
Expand Down Expand Up @@ -30,34 +29,6 @@ type PlaceAttributes =
| null
| undefined;

export const albumTableSchema: CreateTableCommandInput = {
TableName: albumTableName,
KeySchema: [
{
AttributeName: 'pk',
KeyType: 'HASH',
},
{
AttributeName: 'sk',
KeyType: 'RANGE',
},
],
AttributeDefinitions: [
{
AttributeName: 'pk',
AttributeType: 'S',
},
{
AttributeName: 'sk',
AttributeType: 'S',
},
],
ProvisionedThroughput: {
ReadCapacityUnits: 4,
WriteCapacityUnits: 4,
},
};

export const AlbumEntity = new Entity(
{
model: {
Expand Down
29 changes: 0 additions & 29 deletions server/src/schemas/user-permission.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,10 @@
import { CreateTableCommandInput } from '@aws-sdk/client-dynamodb';
import { Entity, EntityRecord } from 'electrodb';
import { ddbDocClient } from '../services/dynamodb-client.js';

export type UserPermission = EntityRecord<typeof UserPermissionEntity>;

export const userTableName = process.env.PHOTO_USER_PERMISSION_TABLE_NAME || 'user-permission';

export const userPermissionTableSchema: CreateTableCommandInput = {
AttributeDefinitions: [
{
AttributeName: 'uid',
AttributeType: 'S',
},
{
AttributeName: 'email',
AttributeType: 'S',
},
],
KeySchema: [
{
AttributeName: 'uid',
KeyType: 'HASH',
},
{
AttributeName: 'email',
KeyType: 'RANGE',
},
],
ProvisionedThroughput: {
ReadCapacityUnits: 1,
WriteCapacityUnits: 1,
},
TableName: userTableName,
};

export const UserPermissionEntity = new Entity(
{
model: {
Expand Down
113 changes: 49 additions & 64 deletions server/src/services/initialise-dynamodb-tables.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { CreateTableCommand, DescribeTableCommand } from '@aws-sdk/client-dynamodb';
import { AlbumTag, AlbumTagEntity, albumTagsTableName, albumTagsTableSchema } from '../schemas/album-tag.js';
import { Album, AlbumEntity, albumTableName, albumTableSchema } from '../schemas/album.js';
import {
UserPermission,
UserPermissionEntity,
userPermissionTableSchema,
userTableName,
} from '../schemas/user-permission.js';
import { DescribeTableCommand } from '@aws-sdk/client-dynamodb';
import { AlbumTag, AlbumTagEntity, albumTagsTableName } from '../schemas/album-tag.js';
import { Album, AlbumEntity, albumTableName } from '../schemas/album.js';
import { UserPermission, UserPermissionEntity, userTableName } from '../schemas/user-permission.js';
import { ddbDocClient } from './dynamodb-client.js';

const getTableStatus = async (tableName: string) => {
Expand All @@ -24,28 +19,25 @@ const waitForTable = async (tableName: string, cb: (value: boolean) => void) =>
console.log(`Waiting for ${tableName} table to become active......`);
setTimeout(() => waitForTable(tableName, cb), 5000);
} else {
console.log(`${tableName} table is active`);
cb(true);
}
};

const initialiseAlbumTable = async () => {
let albumTableResponse;
try {
albumTableResponse = await getTableStatus(albumTableName);
await getTableStatus(albumTableName);
} catch (error) {
// DO NOTHING
console.error(error);
throw Error(`Table ${albumTableName} does not exist. Please run 'npm run serverless:deploy' first.`);
}

if (!albumTableResponse?.Table) {
console.log(`${albumTableName} table does not exist. Creating table......`);
try {
await ddbDocClient.send(new CreateTableCommand(albumTableSchema));
console.log(`${albumTableName} table created.`);

await waitForTable(albumTableName, async (value) => {
if (value) {
console.log(`Īnsert mock data into ${albumTableName} table......`);
try {
console.log(`Checking ${albumTableName} has data......`);
await waitForTable(albumTableName, async (value) => {
if (value) {
const items = await AlbumEntity.scan.go({ limit: 1, ignoreOwnership: true });
if (items.data.length === 0) {
console.log(`Insert mock data into ${albumTableName} table......`);
await AlbumEntity.create({
year: 'na',
id: 'test-album-1',
Expand All @@ -67,63 +59,57 @@ const initialiseAlbumTable = async () => {
} as Album).go({ response: 'none' });
console.log(`Mock data inserted into ${albumTableName} table.`);
}
});
} catch (error) {
console.error(`Error creating ${albumTableName}:`, error);
}
} else {
console.log(`${albumTableName} table exists.👍`);
}
});
console.log(`${albumTableName} table all set.👍`);
} catch (error) {
console.error(`Error when checking ${albumTableName}:`, error);
}
};

const initialiseAlbumTagsTable = async () => {
let response;
try {
response = await getTableStatus(albumTagsTableName);
await getTableStatus(albumTagsTableName);
} catch (error) {
// DO NOTHING
console.error(error);
throw Error(`Table ${albumTableName} does not exist. Please run 'npm run serverless:deploy' first.`);
}

if (!response?.Table) {
console.log(`${albumTagsTableName} table does not exist. Creating table......`);
try {
await ddbDocClient.send(new CreateTableCommand(albumTagsTableSchema));
console.log(`${albumTagsTableName} table created.`);

await waitForTable(albumTagsTableName, async (value) => {
if (value) {
console.log(`Īnsert mock data into ${albumTagsTableName} table......`);
try {
console.log(`Checking ${albumTagsTableName} has data......`);
await waitForTable(albumTagsTableName, async (value) => {
if (value) {
const items = await AlbumTagEntity.scan.go({ limit: 1, ignoreOwnership: true });
if (items.data.length === 0) {
console.log(`Insert mock data into ${albumTagsTableName} table......`);
await AlbumTagEntity.create({
tag: 'test-tag-1',
} as AlbumTag).go({ response: 'none' });
console.log(`Mock data inserted into ${albumTagsTableName} table.`);
}
});
} catch (error) {
console.error(`Error creating ${albumTagsTableName}:`, error);
}
} else {
console.log(`${albumTagsTableName} table exists.👍`);
}
});
console.log(`${albumTagsTableName} table all set.👍`);
} catch (error) {
console.error(`Error when checking ${albumTagsTableName}:`, error);
}
};

const initialiseUserTable = async () => {
let response;
try {
response = await getTableStatus(userTableName);
await getTableStatus(userTableName);
} catch (error) {
// DO NOTHING
console.error(error);
throw Error(`Table ${albumTableName} does not exist. Please run 'npm run serverless:deploy' first.`);
}

if (!response?.Table) {
console.log(`${userTableName} table does not exist. Creating table......`);
try {
await ddbDocClient.send(new CreateTableCommand(userPermissionTableSchema));
console.log(`${userTableName} table created.`);

await waitForTable(userTableName, async (value) => {
if (value) {
console.log(`Īnsert mock data into ${userTableName} table......`);
try {
console.log(`Checking ${userTableName} has data......`);
await waitForTable(userTableName, async (value) => {
if (value) {
const items = await UserPermissionEntity.scan.go({ limit: 1, ignoreOwnership: true });
if (items.data.length === 0) {
console.log(`Insert mock data into ${userTableName} table......`);
await UserPermissionEntity.create({
uid: 'test-uid-1',
email: 'test@example.com',
Expand All @@ -132,12 +118,11 @@ const initialiseUserTable = async () => {
} as UserPermission).go({ response: 'none' });
console.log(`Mock data inserted into ${userTableName} table.`);
}
});
} catch (error) {
console.error(`Error creating ${userTableName}:`, error);
}
} else {
console.log(`${userTableName} table exists.👍`);
}
});
console.log(`${userTableName} table all set.👍`);
} catch (error) {
console.error(`Error when checking ${userTableName}:`, error);
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/Album.vue
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const thumbnail = computed(() => `${cdnURL}/${encodeURI(albumItem.value?.albumCo
const thumbnailSize = computed(() => (q.screen.lt.sm ? 60 : 90));
const tagsForDisplay = computed(() => (albumItem.value?.tags ? albumItem.value?.tags.slice(0, 3) : []));
const goToAlbum = () => router.push(`/album/${albumItem.value?.year.replace('/', '')}/${albumItem.value?.id}`);
const goToAlbum = () => router.push(`/album/${albumItem.value?.year}/${albumItem.value?.id}`);
</script>
<style lang="scss" scoped>
.no-album-cover-square {
Expand Down
Loading

0 comments on commit 0d23920

Please sign in to comment.