Closed slackermorris closed 1 year ago
These resources were really helpful when initially setting up CRUD endpoints for users.
I should probably also go through my Read Now
folder for this project and just jot down the notes.
I need to read this to figure out if I can use an Astro Component in this context.
How do I want to fetch stuff from inside of the component front matter? I think I should use a fetch to begin with.
I need proper type support in the front matter when making requests. I might also like to use wretch
instead of fetch.
I think I could start with editing the username? I make sure that the PUT request works as expected.
I am looking at how to handle form submissions from an Astro component.
Keep in my mind how I intend to manage validation for the form. It'd have to be client side, no? Likely both.
I am working [from here](https://docs.astro.build/en/recipes/build-forms/#:~:text=Check%20for%20the%20POST%20method%20in%20the%20frontmatter%20and%20access%20the%20form%20data%20using%20Astro.request.formData().%20Wrap%20this%20in%20a%20try%20...%20catch%20block%20to%20handle%20cases%20when%20the%20POST%20request%20wasn%E2%80%99t%20sent%20by%20a%20form%20and%20the%20formData%20is%20invalid.) where the POST is being handled in the front matter.
This is exactly how to do what I want to do.
Try to understand why one of the resources recommended intercepting the POST call in the front matter.
---
//! I think this can be an Astro component: https://docs.astro.build/en/core-concepts/astro-components/
//? how am I going to represent the "wishlist"?
//? where am I going to import this
const response = await fetch(
"https://eaoql5a9ab.execute-api.ap-southeast-2.amazonaws.com/users/2aff71b0-3ee9-11ee-bdeb-7797f77643a3",
{
method: "GET",
}
);
const data = await response.json();
const { username, wishlist } = data;
if (Astro.request.method === "POST") {
console.log("whoops we made it here");
try {
// const data = await Astro.request.formData();
// console.log("🚀 ~ file: UpdateUserForm.astro:20 ~ data:", data);
// const username = data.get("username");
// const wishlist = data.get("wishlist");
// const response = await fetch(
// "https://eaoql5a9ab.execute-api.ap-southeast-2.amazonaws.com/users/2aff71b0-3ee9-11ee-bdeb-7797f77643a3",
// {
// method: "PUT",
// body: JSON.stringify({
// username,
// wishlist,
// }),
// }
// );
// console.log("🚀 ~ file: UpdateUserForm.astro:34 ~ response:", response);
} catch (error) {
if (error instanceof Error) {
console.error(error.message);
}
}
}
---
<form method="post">
<label>
Username
<input
type="text"
id="username"
name="username"
required
placeholder={username}
value={username}
/>
</label>
<label>
Wishlist
<textarea
id="message"
name="message"
required
placeholder={wishlist.join(", ")}></textarea>
</label>
<button type="submit">Send</button>
</form>
I have a feeling that this is incomplete. I think I need to manually extract the values enclosed in the fields. I can't just magically grab them off of the FormData
object.
Nope, not true. I just needed to name the field correctly. The example was correct.
The dynamo call to update the user should return the updated user.
I really need to plan out some error handling. I'm not sure at what point in the stack I should manage this:
This is completely unrelated, but I am trying to install Wallaby.js
and am having some major difficulties. It works for vscode insider
after I have run tests.
I need to Wallaby: Run Project tests
.
Wallaby.js
works for the bostock-metaball-animation
repo. It works for the repository when tested in isolation but fails when run against the same project when in the context of a workspace.
Meh I think I need to learn how Wallaby.js
works before trying to use it. Too complicated.
This is the table design I am thinking of for storing movie data:
I'm consulting these docs before making any real changes.
This is the API that Letterboxd uses under the hood.
I grabbed this from ChatGPT:
Sure, here's an example of a DynamoDB table design for storing users with their wishlist of movies:
**Table Name:** WishlistTable
| **Primary Key (Partition Key)** | **Sort Key (Optional)** | **Attributes** |
|---------------------------------|-------------------------|------------------------|
| UserId (String) | MovieId (String) | UserName (String) |
| | | MovieTitle (String) |
| | | ReleaseYear (Number) |
| | | Genre (String) |
In this design:
- **UserId**: This would be the primary key (partition key) and represents a unique identifier for each user.
- **MovieId**: This is the sort key and represents a unique identifier for each movie in a user's wishlist. Each user can have multiple movies in their wishlist, and each movie's identifier is unique within that user's wishlist.
- **UserName**: An attribute to store the user's name.
- **MovieTitle**: An attribute to store the title of the movie in the wishlist.
- **ReleaseYear**: An attribute to store the release year of the movie.
- **Genre**: An attribute to store the genre of the movie.
This design allows you to efficiently query for a user's wishlist and retrieve information about the movies they have added. You can use the UserId to retrieve all the movies in a specific user's wishlist or use the combination of UserId and MovieId to fetch specific movie details for a particular user.
Remember that DynamoDB's schema design heavily depends on the access patterns and queries you expect to perform. The example above is a basic starting point, and you might need to adjust it based on your application's specific requirements.
To support the access pattern of listing all movies of a particular genre, you would need to create a Global Secondary Index (GSI) in your DynamoDB table. Here's how you could set up the GSI and access pattern:
**Global Secondary Index (GSI): GenreIndex**
| **Primary Key (Partition Key)** | **Sort Key (Optional)** | **Attributes** |
|---------------------------------|-------------------------|------------------------|
| Genre (String) | MovieId (String) | MovieTitle (String) |
| | | ReleaseYear (Number) |
| | | UserName (String) |
In this GSI design:
- **Genre**: This is the partition key for the GSI and represents the genre of the movie.
- **MovieId**: This is the sort key for the GSI and represents the unique identifier for each movie within a particular genre.
- **MovieTitle**: An attribute to store the title of the movie.
- **ReleaseYear**: An attribute to store the release year of the movie.
- **UserName**: An attribute to store the name of the user who added the movie to their wishlist.
With this GSI in place, you can efficiently query for all movies of a particular genre. Here's how you would perform the access pattern:
1. Query the GSI using the `Genre` partition key. This will give you all the movies belonging to the specified genre.
2. For each item retrieved from the query, you can access the `MovieTitle`, `ReleaseYear`, and `UserName` attributes to display information about the movie and the user who added it to their wishlist.
Keep in mind that GSI creation involves additional costs, and you should carefully plan your index creation based on the actual access patterns you expect in your application. Also, be aware that DynamoDB's pricing and capacity planning can be influenced by the number and size of your indexes.
I want to avoid duplicating data about movies. Each user can have an entry for the same Movie but the Movies' data should not be expressed in this entry.
There should likely be two tables. Users
and Movies
.
Certainly, to avoid duplicating movie data for each user and still support the access pattern of listing all movies of a particular genre, you can use a slightly different table design and indexing strategy.
**Table Name:** WishlistTable
| **Primary Key (Partition Key)** | **Sort Key (Optional)** | **Attributes** |
|---------------------------------|-------------------------|-------------------------|
| MovieId (String) | Genre (String) | MovieTitle (String) |
| | | ReleaseYear (Number) |
| | | UserName (String) |
**Global Secondary Index (GSI): GenreIndex**
| **Primary Key (Partition Key)** | **Sort Key (Optional)** | **Attributes** |
|---------------------------------|-------------------------|------------------------|
| Genre (String) | MovieId (String) | MovieTitle (String) |
| | | ReleaseYear (Number) |
| | | UserName (String) |
With this design:
- **MovieId**: This is the primary key (partition key) for the table, and it uniquely identifies each movie.
- **Genre**: This is the sort key for both the table and the GSI. It is used to group movies by genre.
- **MovieTitle**: An attribute to store the title of the movie.
- **ReleaseYear**: An attribute to store the release year of the movie.
- **UserName**: An attribute to store the name of the user who added the movie to their wishlist.
To implement this design:
1. When a user adds a movie to their wishlist, you insert a new item into the table with the `MovieId` as the partition key and the `Genre` as the sort key. The `MovieTitle`, `ReleaseYear`, and `UserName` attributes are stored in this item.
2. To list all movies of a particular genre, you query the GSI using the `Genre` partition key. This will give you all the movies belonging to the specified genre without duplicating the movie data for each user.
This design eliminates duplication of movie data while still allowing you to efficiently query for movies by genre. Keep in mind that each movie can only be associated with one genre in this design, so if movies can belong to multiple genres, you might need to adjust the design accordingly.
This is how to implement this allowing Movies to belong to multiple genres.
Sure, if you want to allow movies to belong to multiple genres, you can adjust the table design to accommodate this requirement. Here's how you can modify the design:
**Table Name:** WishlistTable
| **Primary Key (Partition Key)** | **Sort Key (Optional)** | **Attributes** |
|---------------------------------|-------------------------|-------------------------|
| MovieId (String) | Type (String) | MovieTitle (String) |
| | | ReleaseYear (Number) |
| | | UserName (String) |
**Global Secondary Index (GSI): GenreIndex**
| **Primary Key (Partition Key)** | **Sort Key (Optional)** | **Attributes** |
|---------------------------------|-------------------------|------------------------|
| Genre (String) | MovieId (String) | MovieTitle (String) |
| | | ReleaseYear (Number) |
| | | UserName (String) |
In this adjusted design:
- **MovieId**: This remains the primary key (partition key) for the table, and it uniquely identifies each movie.
- **Type**: This new attribute represents the type of the entry, and for movies, it will have a value like "movie". This allows you to differentiate between different types of items that might be stored in the table in the future.
- **Genre**: This remains the sort key for both the table and the GSI. It's used to group movies by genre.
- **MovieTitle**: An attribute to store the title of the movie.
- **ReleaseYear**: An attribute to store the release year of the movie.
- **UserName**: An attribute to store the name of the user who added the movie to their wishlist.
To handle movies belonging to multiple genres:
1. When a user adds a movie to their wishlist, you insert a new item into the table with the `MovieId` as the partition key and a `Type` attribute indicating that it's a movie. The `Genre`, `MovieTitle`, `ReleaseYear`, and `UserName` attributes are stored in this item.
2. To associate a movie with multiple genres, you can create multiple items for the same movie, each with a different `Genre` value in the GSI.
3. To list all movies of a particular genre, you query the GSI using the `Genre` partition key. This will give you all the movies belonging to the specified genre.
This design allows movies to be associated with multiple genres without duplicating movie data for each user. Just remember that managing the entries for multiple genres for the same movie might require careful handling and data management.
This is more like what I am after:
Apologies for the misunderstanding. I see what you're looking for now. To avoid duplicating movie data and allowing multiple genres for each movie across users' wishlists, you can use a combination of the previous designs and utilize a separate Movies table. Here's how:
**Table Name:** WishlistTable
| **Primary Key (Partition Key)** | **Sort Key (Optional)** | **Attributes** |
|---------------------------------|-------------------------|-------------------------|
| UserId (String) | MovieId (String) | |
| | | UserName (String) |
**Global Secondary Index (GSI): GenreIndex**
| **Primary Key (Partition Key)** | **Sort Key (Optional)** | **Attributes** |
|---------------------------------|-------------------------|------------------------|
| Genre (String) | MovieId (String) | UserName (String) |
**Table Name:** MoviesTable
| **Primary Key (Partition Key)** | **Sort Key (Optional)** | **Attributes** |
|---------------------------------|-------------------------|-------------------------|
| MovieId (String) | | MovieTitle (String) |
| | | ReleaseYear (Number) |
| | | Genres (List of String)|
With this design:
1. **WishlistTable** stores user wishlists. Each item is identified by the user's ID and the movie's ID. You don't need to duplicate movie details here.
2. **GenreIndex** allows you to query movies by genre. It uses the movie's ID as the sort key and provides access to the user who added it.
3. **MoviesTable** contains the details of each movie, including its title, release year, and genres. The movie's ID serves as the primary key's partition key.
To use this design:
1. When a user adds a movie to their wishlist:
- Insert an item into **WishlistTable** with the user's ID as the partition key and the movie's ID as the sort key.
- No need to duplicate movie data; you reference the movie's ID.
2. To query all movies of a particular genre:
- Use the **GenreIndex** to get a list of movie IDs belonging to that genre.
- Retrieve detailed information for each movie by querying the **MoviesTable** using the movie's ID.
This design effectively separates movie details from user wishlists, minimizing data duplication while enabling multiple genres for each movie.
To keep this following a Single Table Design, I might need to try:
Absolutely, you can achieve this using a single-table design with DynamoDB. This design approach uses hierarchical keys and nested attributes to avoid data duplication while accommodating the requirements of users having multiple wishlist movies and movies belonging to multiple genres. Here's how you can structure it:
**Table Name:** WishlistTable
| **Primary Key (Partition Key)** | **Sort Key (Optional)** | **Attributes** |
|---------------------------------|-------------------------|-------------------------|
| PK (String) | SK (String) | Data (Map) |
In this design:
- **PK**: This is the partition key. It can be a composite value of "USER#" followed by the user's ID, or "MOVIE#" followed by the movie's ID.
- **SK**: This is the sort key. It can be a composite value of "USER#" followed by the user's ID, or "MOVIE#" followed by the movie's ID.
- **Data**: This attribute is a map that contains all the data associated with the entry. For user entries, it would contain wishlist-specific data, and for movie entries, it would contain movie-specific data.
Here's how you'd structure the Data map:
**For User Entries:**
```json
{
"Type": "User",
"UserName": "User's Name",
"Movies": [
{
"MovieId": "Movie's ID",
"Genres": ["Genre 1", "Genre 2"],
"MovieTitle": "Movie Title",
"ReleaseYear": 2023
},
// More movie entries
]
}
For Movie Entries:
{
"Type": "Movie",
"MovieTitle": "Movie Title",
"ReleaseYear": 2023,
"Genres": ["Genre 1", "Genre 2"]
}
In this structure:
Type
attribute helps distinguish between user and movie entries.Movies
list contains all the wishlist movie details.Data
map.To list all movies of a particular genre, you would use a query on the table, filtering entries with Type
set to "Movie" and checking the Genres
attribute to match the desired genre.
This single-table design helps minimize data duplication and supports the required access patterns while providing flexibility for user wishlists and movie details.
This is me still trying to get Wallaby.js to work.
It has something to do with TypeScript compiling to commonJS and me trying to use ESM modules in my test files. This is why I had to do all the work w/r/t using ts-jest
.
This is another interesting forum post about some of the issues I have been having.
What environment do I run my Remix (better-brain-blogging) tests?
Read this tomorrow.
Gold mine in understanding.
So, the conflict was my jest-config
. I stripped it back to:
export default {
preset: "ts-jest",
testEnvironment: "node",
};
I did this after watching Jacks' video.
Alright. Root of the problem is that Wallaby does not like the test environment when it is specified as happy-dom
.
Another helpful resource.
This helped me to find node versions under nvm.
This is where I am, having difficulties getting Wallaby to pick up nvm
:
Alright, I am back to determining the single table design
for my Dynamo table.
This is helpful to see the different access patterns.
So, the two resources I am using at the moment are:
I also need to figure out what extension is causing my workspace to hang.