From 427c4deed467f9753b46f30f20927a376beedc52 Mon Sep 17 00:00:00 2001 From: Cynthia Wang Date: Thu, 30 May 2024 17:32:20 -0400 Subject: [PATCH 01/11] feat: fdc quickstart --- .gitignore | 1 + dataconnect/README.md | 39 + .../.dataconnect/schema/main/implicit.gql | 27 + .../.dataconnect/schema/main/input.gql | 316 ++ .../.dataconnect/schema/main/mutation.gql | 218 ++ .../.dataconnect/schema/main/query.gql | 79 + .../.dataconnect/schema/main/relation.gql | 94 + .../.dataconnect/schema/prelude.gql | 947 ++++++ dataconnect/dataconnect/1_movie_insert.gql | 241 ++ dataconnect/dataconnect/2_actor_insert.gql | 141 + .../dataconnect/3_movie_actor_insert.gql | 283 ++ .../4_user_favorites_review_insert.gql | 184 ++ .../dataconnect/connector/connector.yaml | 14 + .../dataconnect/connector/mutations.gql | 113 + dataconnect/dataconnect/connector/queries.gql | 565 ++++ dataconnect/dataconnect/dataconnect.yaml | 10 + dataconnect/dataconnect/schema/schema.gql | 104 + dataconnect/firebase.json | 32 + dataconnect/movie/.env.local | 6 + dataconnect/movie/app/actor/[id]/page.tsx | 138 + dataconnect/movie/app/advancedsearch/page.tsx | 219 ++ dataconnect/movie/app/genre/[genre]/page.tsx | 70 + dataconnect/movie/app/layout.tsx | 19 + dataconnect/movie/app/movie/[id]/page.tsx | 280 ++ dataconnect/movie/app/myprofile/page.tsx | 210 ++ dataconnect/movie/app/page.tsx | 41 + dataconnect/movie/app/vectors/page.tsx | 82 + dataconnect/movie/assets/firebase_logo.svg | 6 + dataconnect/movie/components/carousel.tsx | 38 + dataconnect/movie/components/moviecard.tsx | 144 + dataconnect/movie/components/navbar.tsx | 97 + .../lib/dataconnect-sdk/esm/index.esm.js | 318 ++ .../lib/dataconnect-sdk/esm/package.json | 1 + .../movie/lib/dataconnect-sdk/index.cjs.js | 403 +++ .../movie/lib/dataconnect-sdk/index.d.ts | 1144 +++++++ .../movie/lib/dataconnect-sdk/package.json | 25 + dataconnect/movie/lib/firebase.tsx | 33 + dataconnect/movie/next-env.d.ts | 5 + dataconnect/movie/package-lock.json | 2653 +++++++++++++++++ dataconnect/movie/package.json | 26 + dataconnect/movie/postcss.config.js | 6 + dataconnect/movie/styles.css | 3 + dataconnect/movie/tailwind.config.js | 13 + dataconnect/movie/tsconfig.json | 25 + 44 files changed, 9413 insertions(+) create mode 100644 dataconnect/README.md create mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql create mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/input.gql create mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql create mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/query.gql create mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/relation.gql create mode 100755 dataconnect/dataconnect/.dataconnect/schema/prelude.gql create mode 100644 dataconnect/dataconnect/1_movie_insert.gql create mode 100644 dataconnect/dataconnect/2_actor_insert.gql create mode 100644 dataconnect/dataconnect/3_movie_actor_insert.gql create mode 100644 dataconnect/dataconnect/4_user_favorites_review_insert.gql create mode 100644 dataconnect/dataconnect/connector/connector.yaml create mode 100644 dataconnect/dataconnect/connector/mutations.gql create mode 100644 dataconnect/dataconnect/connector/queries.gql create mode 100644 dataconnect/dataconnect/dataconnect.yaml create mode 100644 dataconnect/dataconnect/schema/schema.gql create mode 100644 dataconnect/firebase.json create mode 100644 dataconnect/movie/.env.local create mode 100644 dataconnect/movie/app/actor/[id]/page.tsx create mode 100644 dataconnect/movie/app/advancedsearch/page.tsx create mode 100644 dataconnect/movie/app/genre/[genre]/page.tsx create mode 100644 dataconnect/movie/app/layout.tsx create mode 100644 dataconnect/movie/app/movie/[id]/page.tsx create mode 100644 dataconnect/movie/app/myprofile/page.tsx create mode 100644 dataconnect/movie/app/page.tsx create mode 100644 dataconnect/movie/app/vectors/page.tsx create mode 100644 dataconnect/movie/assets/firebase_logo.svg create mode 100644 dataconnect/movie/components/carousel.tsx create mode 100644 dataconnect/movie/components/moviecard.tsx create mode 100644 dataconnect/movie/components/navbar.tsx create mode 100644 dataconnect/movie/lib/dataconnect-sdk/esm/index.esm.js create mode 100644 dataconnect/movie/lib/dataconnect-sdk/esm/package.json create mode 100644 dataconnect/movie/lib/dataconnect-sdk/index.cjs.js create mode 100644 dataconnect/movie/lib/dataconnect-sdk/index.d.ts create mode 100644 dataconnect/movie/lib/dataconnect-sdk/package.json create mode 100644 dataconnect/movie/lib/firebase.tsx create mode 100644 dataconnect/movie/next-env.d.ts create mode 100644 dataconnect/movie/package-lock.json create mode 100644 dataconnect/movie/package.json create mode 100644 dataconnect/movie/postcss.config.js create mode 100644 dataconnect/movie/styles.css create mode 100644 dataconnect/movie/tailwind.config.js create mode 100644 dataconnect/movie/tsconfig.json diff --git a/.gitignore b/.gitignore index 0d634a8e1..dee8c505e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ .firebaserc dist/ **/ui-debug.log +.next diff --git a/dataconnect/README.md b/dataconnect/README.md new file mode 100644 index 000000000..c2b0dca3c --- /dev/null +++ b/dataconnect/README.md @@ -0,0 +1,39 @@ +Firebase DataConnect Quickstart +======================================= + +Introduction +------------ + +This is a sample app for the preview version of the Firebase DataConnect. +This will not work if you don't have access to the preview. + + + +Getting Started +--------------- + +1. Sign up for early access [here](https://firebase.google.com/products/data-connect) and receive an invitation. +2. Upgrade your Firebase project billing to the Blaze plan, you will not be charged for the duration of gated preview. +3. Initialize DataConnect in the [Firebase Console](https://console.firebase.google.com/u/0/). +4. Clone this repository to your local machine. +5. Update `firebase-tools` with `npm install -g firebase-tools`. +6. Enable the DataConnect CLI with `firebase experiments:enable dataconnect`. +7. Initialize your Firebase project in the `dataconnect` folder with `firebase init` and select DataConnect. +8. Replace variables in `.env.local` with your project-specific values. +9. Allow domains for Firebase Auth (e.g., http://localhost or http://127.0.0.1). +10. Deploy DataConnect with `firebase deploy --only dataconnect` (this unlocks hidden vectors search). +11. Navigate to the `movie` directory and install dependencies with `npm i` and start the development server with `npm run dev`. +12. Run the four `_insert.gql` files in the `./dataconnect` directory in order. + + + +License +------- + +© Google, 2024. Licensed under an [Apache-2](../LICENSE) license. diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql b/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql new file mode 100755 index 000000000..a3860ad40 --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql @@ -0,0 +1,27 @@ +extend type FavoriteActor { + userId: String! + actorId: UUID! +} +extend type FavoriteMovie { + userId: String! + movieId: UUID! +} +extend type Movie { + sequelToId: UUID +} +extend type MovieActor { + movieId: UUID! + actorId: UUID! +} +extend type MovieMetadata { + id: UUID! @default(expr: "uuidV4()") + movieId: UUID! +} +extend type Review { + movieId: UUID! + userId: String! +} +extend type WatchedMovie { + userId: String! + movieId: UUID! +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/input.gql b/dataconnect/dataconnect/.dataconnect/schema/main/input.gql new file mode 100755 index 000000000..b7d1c62ae --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/main/input.gql @@ -0,0 +1,316 @@ +scalar Actor_Key +scalar FavoriteActor_Key +scalar FavoriteMovie_Key +scalar Movie_Key +scalar MovieActor_Key +scalar MovieMetadata_Key +scalar Review_Key +scalar User_Key +scalar WatchedMovie_Key +input Actor_Data { + id: UUID + id_expr: UUID_Expr + biography: String + biography_expr: String_Expr + imageUrl: String + imageUrl_expr: String_Expr + name: String + name_expr: String_Expr +} +input Actor_Filter { + _and: [Actor_Filter!] + _not: Actor_Filter + _or: [Actor_Filter!] + id: UUID_Filter + biography: String_Filter + imageUrl: String_Filter + name: String_Filter + favoriteActors_on_actor: FavoriteActor_ListFilter + movieActors_on_actor: MovieActor_ListFilter + movies_via_MovieActor: Movie_ListFilter + users_via_FavoriteActor: User_ListFilter +} +input Actor_ListFilter { + count: Int_Filter + exist: Actor_Filter +} +input Actor_Order { + id: OrderDirection + biography: OrderDirection + imageUrl: OrderDirection + name: OrderDirection +} +input FavoriteActor_Data { + userId: String + userId_expr: String_Expr + actorId: UUID + actorId_expr: UUID_Expr + actor: Actor_Key + user: User_Key +} +input FavoriteActor_Filter { + _and: [FavoriteActor_Filter!] + _not: FavoriteActor_Filter + _or: [FavoriteActor_Filter!] + userId: String_Filter + actorId: UUID_Filter + actor: Actor_Filter + user: User_Filter +} +input FavoriteActor_ListFilter { + count: Int_Filter + exist: FavoriteActor_Filter +} +input FavoriteActor_Order { + userId: OrderDirection + actorId: OrderDirection + actor: Actor_Order + user: User_Order +} +input FavoriteMovie_Data { + userId: String + userId_expr: String_Expr + movieId: UUID + movieId_expr: UUID_Expr + movie: Movie_Key + user: User_Key +} +input FavoriteMovie_Filter { + _and: [FavoriteMovie_Filter!] + _not: FavoriteMovie_Filter + _or: [FavoriteMovie_Filter!] + userId: String_Filter + movieId: UUID_Filter + movie: Movie_Filter + user: User_Filter +} +input FavoriteMovie_ListFilter { + count: Int_Filter + exist: FavoriteMovie_Filter +} +input FavoriteMovie_Order { + userId: OrderDirection + movieId: OrderDirection + movie: Movie_Order + user: User_Order +} +input Movie_Data { + id: UUID + id_expr: UUID_Expr + sequelToId: UUID + sequelToId_expr: UUID_Expr + sequelTo: Movie_Key + description: String + description_expr: String_Expr + descriptionEmbedding: Vector + descriptionEmbedding_embed: Vector_Embed + genre: String + genre_expr: String_Expr + imageUrl: String + imageUrl_expr: String_Expr + rating: Float + releaseYear: Int + tags: [String!] + title: String + title_expr: String_Expr +} +input Movie_Filter { + _and: [Movie_Filter!] + _not: Movie_Filter + _or: [Movie_Filter!] + id: UUID_Filter + sequelToId: UUID_Filter + sequelTo: Movie_Filter + description: String_Filter + descriptionEmbedding: Vector_Filter + genre: String_Filter + imageUrl: String_Filter + rating: Float_Filter + releaseYear: Int_Filter + tags: String_ListFilter + title: String_Filter + favoriteMovies_on_movie: FavoriteMovie_ListFilter + movies_on_sequelTo: Movie_ListFilter + movieActors_on_movie: MovieActor_ListFilter + movieMetadatas_on_movie: MovieMetadata_ListFilter + reviews_on_movie: Review_ListFilter + watchedMovies_on_movie: WatchedMovie_ListFilter + actors_via_MovieActor: Actor_ListFilter + users_via_FavoriteMovie: User_ListFilter + users_via_Review: User_ListFilter + users_via_WatchedMovie: User_ListFilter +} +input Movie_ListFilter { + count: Int_Filter + exist: Movie_Filter +} +input Movie_Order { + id: OrderDirection + sequelToId: OrderDirection + sequelTo: Movie_Order + description: OrderDirection + descriptionEmbedding: OrderDirection + genre: OrderDirection + imageUrl: OrderDirection + rating: OrderDirection + releaseYear: OrderDirection + title: OrderDirection +} +input MovieActor_Data { + movieId: UUID + movieId_expr: UUID_Expr + actorId: UUID + actorId_expr: UUID_Expr + actor: Actor_Key + movie: Movie_Key + role: String + role_expr: String_Expr +} +input MovieActor_Filter { + _and: [MovieActor_Filter!] + _not: MovieActor_Filter + _or: [MovieActor_Filter!] + movieId: UUID_Filter + actorId: UUID_Filter + actor: Actor_Filter + movie: Movie_Filter + role: String_Filter +} +input MovieActor_ListFilter { + count: Int_Filter + exist: MovieActor_Filter +} +input MovieActor_Order { + movieId: OrderDirection + actorId: OrderDirection + actor: Actor_Order + movie: Movie_Order + role: OrderDirection +} +input MovieMetadata_Data { + id: UUID + id_expr: UUID_Expr + movieId: UUID + movieId_expr: UUID_Expr + movie: Movie_Key + director: String + director_expr: String_Expr +} +input MovieMetadata_Filter { + _and: [MovieMetadata_Filter!] + _not: MovieMetadata_Filter + _or: [MovieMetadata_Filter!] + id: UUID_Filter + movieId: UUID_Filter + movie: Movie_Filter + director: String_Filter +} +input MovieMetadata_ListFilter { + count: Int_Filter + exist: MovieMetadata_Filter +} +input MovieMetadata_Order { + id: OrderDirection + movieId: OrderDirection + movie: Movie_Order + director: OrderDirection +} +input Review_Data { + movieId: UUID + movieId_expr: UUID_Expr + userId: String + userId_expr: String_Expr + movie: Movie_Key + user: User_Key + id: UUID + id_expr: UUID_Expr + rating: Int + reviewDate: Date + reviewDate_date: Date_Relative + reviewDate_expr: Date_Expr + reviewText: String + reviewText_expr: String_Expr +} +input Review_Filter { + _and: [Review_Filter!] + _not: Review_Filter + _or: [Review_Filter!] + movieId: UUID_Filter + userId: String_Filter + movie: Movie_Filter + user: User_Filter + id: UUID_Filter + rating: Int_Filter + reviewDate: Date_Filter + reviewText: String_Filter +} +input Review_ListFilter { + count: Int_Filter + exist: Review_Filter +} +input Review_Order { + movieId: OrderDirection + userId: OrderDirection + movie: Movie_Order + user: User_Order + id: OrderDirection + rating: OrderDirection + reviewDate: OrderDirection + reviewText: OrderDirection +} +input User_Data { + id: String + id_expr: String_Expr + username: String + username_expr: String_Expr +} +input User_Filter { + _and: [User_Filter!] + _not: User_Filter + _or: [User_Filter!] + id: String_Filter + username: String_Filter + favoriteActors_on_user: FavoriteActor_ListFilter + favoriteMovies_on_user: FavoriteMovie_ListFilter + reviews_on_user: Review_ListFilter + watchedMovies_on_user: WatchedMovie_ListFilter + actors_via_FavoriteActor: Actor_ListFilter + movies_via_FavoriteMovie: Movie_ListFilter + movies_via_Review: Movie_ListFilter + movies_via_WatchedMovie: Movie_ListFilter +} +input User_ListFilter { + count: Int_Filter + exist: User_Filter +} +input User_Order { + id: OrderDirection + username: OrderDirection +} +input WatchedMovie_Data { + userId: String + userId_expr: String_Expr + movieId: UUID + movieId_expr: UUID_Expr + movie: Movie_Key + user: User_Key +} +input WatchedMovie_Filter { + _and: [WatchedMovie_Filter!] + _not: WatchedMovie_Filter + _or: [WatchedMovie_Filter!] + userId: String_Filter + movieId: UUID_Filter + movie: Movie_Filter + user: User_Filter +} +input WatchedMovie_ListFilter { + count: Int_Filter + exist: WatchedMovie_Filter +} +input WatchedMovie_Order { + userId: OrderDirection + movieId: OrderDirection + movie: Movie_Order + user: User_Order +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql new file mode 100755 index 000000000..89c6e66db --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql @@ -0,0 +1,218 @@ +extend type Mutation { + """ + Insert a single Actor into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + actor_insert(data: Actor_Data!): Actor_Key! + """ + Insert a single FavoriteActor into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + favoriteActor_insert(data: FavoriteActor_Data!): FavoriteActor_Key! + """ + Insert a single FavoriteMovie into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + favoriteMovie_insert(data: FavoriteMovie_Data!): FavoriteMovie_Key! + """ + Insert a single Movie into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + movie_insert(data: Movie_Data!): Movie_Key! + """ + Insert a single MovieActor into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + movieActor_insert(data: MovieActor_Data!): MovieActor_Key! + """ + Insert a single MovieMetadata into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + movieMetadata_insert(data: MovieMetadata_Data!): MovieMetadata_Key! + """ + Insert a single Review into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + review_insert(data: Review_Data!): Review_Key! + """ + Insert a single User into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + user_insert(data: User_Data!): User_Key! + """ + Insert a single WatchedMovie into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + watchedMovie_insert(data: WatchedMovie_Data!): WatchedMovie_Key! + """ + Insert or update a single Actor into the table, based on the primary key. Returns the key of the newly inserted Actor. + """ + actor_upsert(data: Actor_Data!): Actor_Key! + """ + Insert or update a single FavoriteActor into the table, based on the primary key. Returns the key of the newly inserted FavoriteActor. + """ + favoriteActor_upsert(data: FavoriteActor_Data!): FavoriteActor_Key! + """ + Insert or update a single FavoriteMovie into the table, based on the primary key. Returns the key of the newly inserted FavoriteMovie. + """ + favoriteMovie_upsert(data: FavoriteMovie_Data!): FavoriteMovie_Key! + """ + Insert or update a single Movie into the table, based on the primary key. Returns the key of the newly inserted Movie. + """ + movie_upsert(data: Movie_Data!): Movie_Key! + """ + Insert or update a single MovieActor into the table, based on the primary key. Returns the key of the newly inserted MovieActor. + """ + movieActor_upsert(data: MovieActor_Data!): MovieActor_Key! + """ + Insert or update a single MovieMetadata into the table, based on the primary key. Returns the key of the newly inserted MovieMetadata. + """ + movieMetadata_upsert(data: MovieMetadata_Data!): MovieMetadata_Key! + """ + Insert or update a single Review into the table, based on the primary key. Returns the key of the newly inserted Review. + """ + review_upsert(data: Review_Data!): Review_Key! + """ + Insert or update a single User into the table, based on the primary key. Returns the key of the newly inserted User. + """ + user_upsert(data: User_Data!): User_Key! + """ + Insert or update a single WatchedMovie into the table, based on the primary key. Returns the key of the newly inserted WatchedMovie. + """ + watchedMovie_upsert(data: WatchedMovie_Data!): WatchedMovie_Key! + """ + Update a single Actor based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found. + """ + actor_update(id: UUID, key: Actor_Key, data: Actor_Data!): Actor_Key + """ + Update a single FavoriteActor based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found. + """ + favoriteActor_update(key: FavoriteActor_Key, data: FavoriteActor_Data!): FavoriteActor_Key + """ + Update a single FavoriteMovie based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found. + """ + favoriteMovie_update(key: FavoriteMovie_Key, data: FavoriteMovie_Data!): FavoriteMovie_Key + """ + Update a single Movie based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found. + """ + movie_update(id: UUID, key: Movie_Key, data: Movie_Data!): Movie_Key + """ + Update a single MovieActor based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found. + """ + movieActor_update(key: MovieActor_Key, data: MovieActor_Data!): MovieActor_Key + """ + Update a single MovieMetadata based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found. + """ + movieMetadata_update(id: UUID, key: MovieMetadata_Key, data: MovieMetadata_Data!): MovieMetadata_Key + """ + Update a single Review based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found. + """ + review_update(key: Review_Key, data: Review_Data!): Review_Key + """ + Update a single User based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found. + """ + user_update(id: String, id_expr: String_Expr, key: User_Key, data: User_Data!): User_Key + """ + Update a single WatchedMovie based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found. + """ + watchedMovie_update(key: WatchedMovie_Key, data: WatchedMovie_Data!): WatchedMovie_Key + """ + Update Actor entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + actor_updateMany(where: Actor_Filter, all: Boolean = false, data: Actor_Data!): Int! + """ + Update FavoriteActor entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + favoriteActor_updateMany(where: FavoriteActor_Filter, all: Boolean = false, data: FavoriteActor_Data!): Int! + """ + Update FavoriteMovie entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + favoriteMovie_updateMany(where: FavoriteMovie_Filter, all: Boolean = false, data: FavoriteMovie_Data!): Int! + """ + Update Movie entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + movie_updateMany(where: Movie_Filter, all: Boolean = false, data: Movie_Data!): Int! + """ + Update MovieActor entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + movieActor_updateMany(where: MovieActor_Filter, all: Boolean = false, data: MovieActor_Data!): Int! + """ + Update MovieMetadata entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + movieMetadata_updateMany(where: MovieMetadata_Filter, all: Boolean = false, data: MovieMetadata_Data!): Int! + """ + Update Review entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + review_updateMany(where: Review_Filter, all: Boolean = false, data: Review_Data!): Int! + """ + Update User entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + user_updateMany(where: User_Filter, all: Boolean = false, data: User_Data!): Int! + """ + Update WatchedMovie entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + watchedMovie_updateMany(where: WatchedMovie_Filter, all: Boolean = false, data: WatchedMovie_Data!): Int! + """ + Delete a single Actor based on `id` or `key` and return its key (or `null` if not found). + """ + actor_delete(id: UUID, key: Actor_Key): Actor_Key + """ + Delete a single FavoriteActor based on `id` or `key` and return its key (or `null` if not found). + """ + favoriteActor_delete(key: FavoriteActor_Key): FavoriteActor_Key + """ + Delete a single FavoriteMovie based on `id` or `key` and return its key (or `null` if not found). + """ + favoriteMovie_delete(key: FavoriteMovie_Key): FavoriteMovie_Key + """ + Delete a single Movie based on `id` or `key` and return its key (or `null` if not found). + """ + movie_delete(id: UUID, key: Movie_Key): Movie_Key + """ + Delete a single MovieActor based on `id` or `key` and return its key (or `null` if not found). + """ + movieActor_delete(key: MovieActor_Key): MovieActor_Key + """ + Delete a single MovieMetadata based on `id` or `key` and return its key (or `null` if not found). + """ + movieMetadata_delete(id: UUID, key: MovieMetadata_Key): MovieMetadata_Key + """ + Delete a single Review based on `id` or `key` and return its key (or `null` if not found). + """ + review_delete(key: Review_Key): Review_Key + """ + Delete a single User based on `id` or `key` and return its key (or `null` if not found). + """ + user_delete(id: String, id_expr: String_Expr, key: User_Key): User_Key + """ + Delete a single WatchedMovie based on `id` or `key` and return its key (or `null` if not found). + """ + watchedMovie_delete(key: WatchedMovie_Key): WatchedMovie_Key + """ + Delete Actor entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + actor_deleteMany(where: Actor_Filter, all: Boolean = false): Int! + """ + Delete FavoriteActor entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + favoriteActor_deleteMany(where: FavoriteActor_Filter, all: Boolean = false): Int! + """ + Delete FavoriteMovie entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + favoriteMovie_deleteMany(where: FavoriteMovie_Filter, all: Boolean = false): Int! + """ + Delete Movie entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + movie_deleteMany(where: Movie_Filter, all: Boolean = false): Int! + """ + Delete MovieActor entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + movieActor_deleteMany(where: MovieActor_Filter, all: Boolean = false): Int! + """ + Delete MovieMetadata entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + movieMetadata_deleteMany(where: MovieMetadata_Filter, all: Boolean = false): Int! + """ + Delete Review entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + review_deleteMany(where: Review_Filter, all: Boolean = false): Int! + """ + Delete User entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + user_deleteMany(where: User_Filter, all: Boolean = false): Int! + """ + Delete WatchedMovie entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + watchedMovie_deleteMany(where: WatchedMovie_Filter, all: Boolean = false): Int! +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/query.gql b/dataconnect/dataconnect/.dataconnect/schema/main/query.gql new file mode 100755 index 000000000..2784eb715 --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/main/query.gql @@ -0,0 +1,79 @@ +extend type Query { + """ + Look up a single Actor based on `id` or `key` and return selected fields (or `null` if not found). + """ + actor(id: UUID, key: Actor_Key): Actor + """ + Look up a single FavoriteActor based on `id` or `key` and return selected fields (or `null` if not found). + """ + favoriteActor(key: FavoriteActor_Key): FavoriteActor + """ + Look up a single FavoriteMovie based on `id` or `key` and return selected fields (or `null` if not found). + """ + favoriteMovie(key: FavoriteMovie_Key): FavoriteMovie + """ + Look up a single Movie based on `id` or `key` and return selected fields (or `null` if not found). + """ + movie(id: UUID, key: Movie_Key): Movie + """ + Look up a single MovieActor based on `id` or `key` and return selected fields (or `null` if not found). + """ + movieActor(key: MovieActor_Key): MovieActor + """ + Look up a single MovieMetadata based on `id` or `key` and return selected fields (or `null` if not found). + """ + movieMetadata(id: UUID, key: MovieMetadata_Key): MovieMetadata + """ + Look up a single Review based on `id` or `key` and return selected fields (or `null` if not found). + """ + review(key: Review_Key): Review + """ + Look up a single User based on `id` or `key` and return selected fields (or `null` if not found). + """ + user(id: String, id_expr: String_Expr, key: User_Key): User + """ + Look up a single WatchedMovie based on `id` or `key` and return selected fields (or `null` if not found). + """ + watchedMovie(key: WatchedMovie_Key): WatchedMovie + """ + List Actor entries in the table, optionally filtered by `where` conditions. + """ + actors(where: Actor_Filter, orderBy: [Actor_Order!], limit: Int = 100): [Actor!]! + """ + List FavoriteActor entries in the table, optionally filtered by `where` conditions. + """ + favoriteActors(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [FavoriteActor!]! + """ + List FavoriteMovie entries in the table, optionally filtered by `where` conditions. + """ + favoriteMovies(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [FavoriteMovie!]! + """ + List Movie entries in the table, optionally filtered by `where` conditions. + """ + movies(where: Movie_Filter, orderBy: [Movie_Order!], limit: Int = 100): [Movie!]! + """ + List MovieActor entries in the table, optionally filtered by `where` conditions. + """ + movieActors(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [MovieActor!]! + """ + List MovieMetadata entries in the table, optionally filtered by `where` conditions. + """ + movieMetadatas(where: MovieMetadata_Filter, orderBy: [MovieMetadata_Order!], limit: Int = 100): [MovieMetadata!]! + """ + List Review entries in the table, optionally filtered by `where` conditions. + """ + reviews(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Review!]! + """ + List User entries in the table, optionally filtered by `where` conditions. + """ + users(where: User_Filter, orderBy: [User_Order!], limit: Int = 100): [User!]! + """ + List WatchedMovie entries in the table, optionally filtered by `where` conditions. + """ + watchedMovies(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [WatchedMovie!]! + """ + List Movie entries ordered by vector similarity between the `descriptionEmbedding` field and `compare_embed`. + (Alternatively, `compare` can be used if the input is a raw Vector.) + """ + movies_descriptionEmbedding_similarity(compare: Vector, compare_embed: Vector_Embed, method: VectorSimilarityMethod = INNER_PRODUCT, within: Float, where: Movie_Filter, limit: Int = 100): [Movie!]! +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql new file mode 100755 index 000000000..7cc34201b --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql @@ -0,0 +1,94 @@ +extend type Actor { + """ + ✨ List FavoriteActor entries in a one-to-many relationship with this object (i.e. where `FavoriteActor.actor` equals this object). + """ + favoriteActors_on_actor(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [FavoriteActor!]! + """ + ✨ List MovieActor entries in a one-to-many relationship with this object (i.e. where `MovieActor.actor` equals this object). + """ + movieActors_on_actor(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [MovieActor!]! + """ + ✨ List related Movie entries using MovieActor as a join table (i.e. where an entry of MovieActor exists whose actor == this and movie == that). + """ + movies_via_MovieActor(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [Movie!]! + """ + ✨ List related User entries using FavoriteActor as a join table (i.e. where an entry of FavoriteActor exists whose actor == this and user == that). + """ + users_via_FavoriteActor(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [User!]! +} +extend type Movie { + """ + ✨ List FavoriteMovie entries in a one-to-many relationship with this object (i.e. where `FavoriteMovie.movie` equals this object). + """ + favoriteMovies_on_movie(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [FavoriteMovie!]! + """ + ✨ List Movie entries in a one-to-many relationship with this object (i.e. where `Movie.sequelTo` equals this object). + """ + movies_on_sequelTo(where: Movie_Filter, orderBy: [Movie_Order!], limit: Int = 100): [Movie!]! + """ + ✨ List MovieActor entries in a one-to-many relationship with this object (i.e. where `MovieActor.movie` equals this object). + """ + movieActors_on_movie(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [MovieActor!]! + """ + ✨ List MovieMetadata entries in a one-to-many relationship with this object (i.e. where `MovieMetadata.movie` equals this object). + """ + movieMetadatas_on_movie(where: MovieMetadata_Filter, orderBy: [MovieMetadata_Order!], limit: Int = 100): [MovieMetadata!]! + """ + ✨ List Review entries in a one-to-many relationship with this object (i.e. where `Review.movie` equals this object). + """ + reviews_on_movie(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Review!]! + """ + ✨ List WatchedMovie entries in a one-to-many relationship with this object (i.e. where `WatchedMovie.movie` equals this object). + """ + watchedMovies_on_movie(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [WatchedMovie!]! + """ + ✨ List related Actor entries using MovieActor as a join table (i.e. where an entry of MovieActor exists whose movie == this and actor == that). + """ + actors_via_MovieActor(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [Actor!]! + """ + ✨ List related User entries using FavoriteMovie as a join table (i.e. where an entry of FavoriteMovie exists whose movie == this and user == that). + """ + users_via_FavoriteMovie(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [User!]! + """ + ✨ List related User entries using Review as a join table (i.e. where an entry of Review exists whose movie == this and user == that). + """ + users_via_Review(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [User!]! + """ + ✨ List related User entries using WatchedMovie as a join table (i.e. where an entry of WatchedMovie exists whose movie == this and user == that). + """ + users_via_WatchedMovie(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [User!]! +} +extend type User { + """ + ✨ List FavoriteActor entries in a one-to-many relationship with this object (i.e. where `FavoriteActor.user` equals this object). + """ + favoriteActors_on_user(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [FavoriteActor!]! + """ + ✨ List FavoriteMovie entries in a one-to-many relationship with this object (i.e. where `FavoriteMovie.user` equals this object). + """ + favoriteMovies_on_user(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [FavoriteMovie!]! + """ + ✨ List Review entries in a one-to-many relationship with this object (i.e. where `Review.user` equals this object). + """ + reviews_on_user(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Review!]! + """ + ✨ List WatchedMovie entries in a one-to-many relationship with this object (i.e. where `WatchedMovie.user` equals this object). + """ + watchedMovies_on_user(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [WatchedMovie!]! + """ + ✨ List related Actor entries using FavoriteActor as a join table (i.e. where an entry of FavoriteActor exists whose user == this and actor == that). + """ + actors_via_FavoriteActor(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [Actor!]! + """ + ✨ List related Movie entries using FavoriteMovie as a join table (i.e. where an entry of FavoriteMovie exists whose user == this and movie == that). + """ + movies_via_FavoriteMovie(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [Movie!]! + """ + ✨ List related Movie entries using Review as a join table (i.e. where an entry of Review exists whose user == this and movie == that). + """ + movies_via_Review(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Movie!]! + """ + ✨ List related Movie entries using WatchedMovie as a join table (i.e. where an entry of WatchedMovie exists whose user == this and movie == that). + """ + movies_via_WatchedMovie(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [Movie!]! +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/prelude.gql b/dataconnect/dataconnect/.dataconnect/schema/prelude.gql new file mode 100755 index 000000000..3782971fe --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/prelude.gql @@ -0,0 +1,947 @@ +"AccessLevel specifies coarse access policies for common situations." +enum AccessLevel { + """ + This operation can be executed by anyone with or without authentication. + Equivalent to @auth(expr: "true") + """ + PUBLIC + + """ + This operation can only be executed with a valid Firebase Auth ID token. + Note: it allows anonymous auth and unverified accounts, so may be subjected to abuses. + It’s equivalent to @auth(expr: "auth.uid != nil") + """ + USER_ANON + + """ + This operation can only be executed by a non-anonymous Firebase Auth account. + It’s equivalent to @auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")" + """ + USER + + """ + This operation can only be executed by a verified Firebase Auth account. + It’s equivalent to @auth(expr: "auth.uid != nil && auth.token.email_verified")" + """ + USER_EMAIL_VERIFIED + + """ + This operation can not be executed with no IAM credentials. + It’s equivalent to @auth(expr: "false") + """ + NO_ACCESS +} + +""" +Defines the auth policy for a query or mutation. This directive must be added to +any operation you wish to be accessible from a client application. If left +unspecified, defaults to `@auth(level: NO_ACCESS)`. +""" +directive @auth( + "The minimal level of access required to perform this operation." + level: AccessLevel @fdc_oneOf(required: true) + """ + A CEL expression that allows access to this operation if the expression + evaluates to `true`. + """ + expr: Boolean_Expr @fdc_oneOf(required: true) +) on QUERY | MUTATION +"Conditions on a string value" +input String_Filter { + isNull: Boolean + eq: String @fdc_oneOf(group: "eq") + eq_expr: String_Expr @fdc_oneOf(group: "eq") + ne: String @fdc_oneOf(group: "ne") + ne_expr: String_Expr @fdc_oneOf(group: "ne") + in: [String!] + nin: [String!] + gt: String + ge: String + lt: String + le: String + contains: String + startsWith: String + endsWith: String + pattern: String_Pattern +} + +""" +The pattern match condition on a string. Specify either like or regex. +https://www.postgresql.org/docs/current/functions-matching.html +""" +input String_Pattern { + "the LIKE expression to use" + like: String + "the POSIX regular expression" + regex: String + "when true, it's case-insensitive. In Postgres: ILIKE, ~*" + ignoreCase: Boolean + "when true, invert the condition. In Postgres: NOT LIKE, !~" + invert: Boolean +} + +"Conditions on a string list" +input String_ListFilter { + includes: String + excludes: String + includesAll: [String!] + excludesAll: [String!] +} + +"Conditions on a UUID value" +input UUID_Filter { + isNull: Boolean + eq: UUID + ne: UUID + in: [UUID!] + nin: [UUID!] +} + +"Conditions on a UUID list" +input UUID_ListFilter { + includes: UUID + excludes: UUID + includesAll: [UUID!] + excludesAll: [UUID!] +} + +"Conditions on an Int value" +input Int_Filter { + isNull: Boolean + eq: Int + ne: Int + in: [Int!] + nin: [Int!] + gt: Int + ge: Int + lt: Int + le: Int +} + +"Conditions on an Int list" +input Int_ListFilter { + includes: Int + excludes: Int + includesAll: [Int!] + excludesAll: [Int!] +} + +"Conditions on an Int64 value" +input Int64_Filter { + isNull: Boolean + eq: Int64 + ne: Int64 + in: [Int64!] + nin: [Int64!] + gt: Int64 + ge: Int64 + lt: Int64 + le: Int64 +} + +"Conditions on an Int64 list" +input Int64_ListFilter { + includes: Int64 + excludes: Int64 + includesAll: [Int64!] + excludesAll: [Int64!] +} + +"Conditions on a Float value" +input Float_Filter { + isNull: Boolean + eq: Float + ne: Float + in: [Float!] + nin: [Float!] + gt: Float + ge: Float + lt: Float + le: Float +} + +"Conditions on a Float list" +input Float_ListFilter { + includes: Float + excludes: Float + includesAll: [Float!] + excludesAll: [Float!] +} + +"Conditions on a Boolean value" +input Boolean_Filter { + isNull: Boolean + eq: Boolean + ne: Boolean + in: [Boolean!] + nin: [Boolean!] +} + +"Conditions on a Boolean list" +input Boolean_ListFilter { + includes: Boolean + excludes: Boolean + includesAll: [Boolean!] + excludesAll: [Boolean!] +} + +"Conditions on an Any value" +input Any_Filter { + isNull: Boolean + eq: Any + ne: Any + in: [Any!] + nin: [Any!] +} + +"Conditions on a Any list" +input Any_ListFilter { + includes: Any + excludes: Any + includesAll: [Any!] + excludesAll: [Any!] +} +type Query { + _service: _Service! +} + +type Mutation { + # This is just a dummy field so that Mutation is always non-empty. + _firebase: Void @fdc_deprecated(reason: "dummy field -- does nothing useful") +} + +type _Service { + sdl: String! +} + +"(Internal) Added to things that may be removed from FDC and will soon be no longer usable in schema or operations." +directive @fdc_deprecated(reason: String = "No longer supported") on + | SCHEMA + | SCALAR + | OBJECT + | FIELD_DEFINITION + | ARGUMENT_DEFINITION + | INTERFACE + | UNION + | ENUM + | ENUM_VALUE + | INPUT_OBJECT + | INPUT_FIELD_DEFINITION + +"(Internal) Added to scalars representing quoted CEL expressions." +directive @fdc_celExpression( + "The expected CEL type that the expression should evaluate to." + returnType: String +) on SCALAR + +"(Internal) Added to scalars representing quoted SQL expressions." +directive @fdc_sqlExpression( + "The expected SQL type that the expression should evaluate to." + dataType: String +) on SCALAR + +"(Internal) Added to types that may not be used as variables." +directive @fdc_forbiddenAsVariableType on SCALAR | OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT + +"(Internal) Added to types that may not be used as fields in schema." +directive @fdc_forbiddenAsFieldType on SCALAR | OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT + +"Provides a frequently used example for this type / field / argument." +directive @fdc_example( + "A GraphQL literal value (verbatim) whose type matches the target." + value: Any + "A human-readable text description of what `value` means in this context." + description: String +) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | INPUT_OBJECT | INPUT_FIELD_DEFINITION + +"(Internal) Marks this field / argument as conflicting with others in the same group." +directive @fdc_oneOf( + "The group name where fields / arguments conflict with each other." + group: String! = "" + "If true, exactly one field / argument in the group must be specified." + required: Boolean! = false +) repeatable on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION +""" +UUID is a string with hex digits representing an RFC4122 value. + +Outputs will always be 32 lower-case hex digits with no delimiters or curly +braces. Inputs in the following formats are also accepted (case insensitive): + + xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} +""" +scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122") +scalar Int64 + +scalar Any +scalar Void +""" +The `True` scalar type only accepts the boolean `true`. + +An optional field / argument typed `True` may either be set to `true` or omitted +(not provided at all). `false` or `null` is not accepted. +""" +scalar True + @fdc_forbiddenAsFieldType + @fdc_forbiddenAsVariableType + @fdc_example(value: true, description: "The only allowed value.") +"Define the intervals used in timestamps and dates (subset)" +enum TimestampInterval @fdc_deprecated { + second + minute + hour + day + week + month + year +} +""" +A Common Expression Language (CEL) expression that returns a boolean at runtime. + +The expression can reference the `auth` variable, which is null if Firebase Auth +is not used. Otherwise, it contains the following fields: + + - `auth.uid`: The current user ID. + - `auth.token`: A map of all token fields (i.e. "claims"). +""" +scalar Boolean_Expr + @specifiedBy(url: "https://github.com/google/cel-spec") + @fdc_celExpression(returnType: "bool") + @fdc_forbiddenAsVariableType + @fdc_forbiddenAsFieldType + @fdc_example(value: "auth != null", description: "Allow only if a Firebase Auth user is present.") + +""" +A Common Expression Language (CEL) expression that returns a string at runtime. + +Limitation: Right now, only a few expressions are supported. Those are listed +using the @fdc_example directive on this scalar. +""" +scalar String_Expr + @specifiedBy(url: "https://github.com/google/cel-spec") + @fdc_celExpression(returnType: "string") + @fdc_forbiddenAsVariableType + @fdc_forbiddenAsFieldType + @fdc_example(value: "auth.uid", description: "The ID of the currently logged in user in Firebase Auth. (Errors if not logged in.)") + @fdc_example(value: "uuidV4()", description: "Generates a new random UUID (version 4) string, formatted as 32 lower-case hex digits without delimiters.") + +""" +A Common Expression Language (CEL) expression that returns a UUID string at runtime. + +Limitation: Right now, only a few expressions are supported. Those are listed +using the @fdc_example directive on this scalar. +""" +scalar UUID_Expr + @specifiedBy(url: "https://github.com/google/cel-spec") + @fdc_celExpression(returnType: "string") + @fdc_forbiddenAsVariableType + @fdc_forbiddenAsFieldType + @fdc_example(value: "uuidV4()", description: "Generates a new random UUID (version 4) every time.") + +""" +A Common Expression Language (CEL) expression whose return type is unspecified. + +Limitation: Only a limited set of expressions are supported for now for each +type. For type XXX, see the @fdc_example directives on XXX_Expr for a full list. +""" +scalar Any_Expr + @specifiedBy(url: "https://github.com/google/cel-spec") + @fdc_celExpression + @fdc_forbiddenAsVariableType + @fdc_forbiddenAsFieldType + @fdc_example(value: "auth.uid", description: "The ID of the currently logged in user in Firebase Auth. (Errors if not logged in.)") + @fdc_example(value: "uuidV4()", description: "Generates a new random UUID version 4 (formatted as 32 lower-case hex digits without delimiters if result type is String).") + @fdc_example(value: "request.time", description: "The timestamp when the request is received (with microseconds precision).") + +""" +A PostgreSQL value expression whose return type is unspecified. +""" +scalar Any_SQL + @specifiedBy(url: "https://www.postgresql.org/docs/current/sql-expressions.html") + @fdc_sqlExpression + @fdc_forbiddenAsVariableType + @fdc_forbiddenAsFieldType +""" +Defines a relational database table. + +Given `type TableName @table`, + + - `TableName` is the GQL type name. + - `tableName` is the singular name. Override with `@table(singular)`. + - `tableNames` is the plural name. Override with `@table(plural)`. + - `table_name` is the SQL table id. Override with `@table(name)`. + +Only a table type can be configured further with: + + - Customized data types. See `@col`. + - Index. See `@index` + - Unique constraint. See `@unqiue` + - Relation. See `@ref` + - Embedded Json. See `@embed` + +A scalar field map to a SQL database column. +An object field (like `type TableName @table { field: AnotherType }`) are either + + - a relation reference field if `AnotherType` is annotated with `@table`. + - an embedded json field if `field` is annotated with `@embed`. + +""" +directive @table( + "Override the SQL database table name. Defaults to ." + name: String + "Override the singular name. Default is the camel case of the type name." + singular: String + "Override the plural name. Default is generated based on English patterns." + plural: String + "The primary key of the table. Defaults to a single field `id: UUID!`. Generate if missing." + key: [String!] +) on OBJECT + +""" +Defines a relational database view. + +Given `type ViewName @view`, + - `ViewName` is the GQL type name. + - `viewName` is the singular name. Override with `@view(singular)`. + - `viewNames` is the plural name. Override with `@view(plural)`. + - `view_name` is the SQL view id. Override with `@view(name)`. + When `@view(sql)` is defined, it uses the given raw SQL as the view instead. + +A view type can be used just as a table type with queries. +A view type may have a nullable `@ref` field to another table, but cannot be +referenced in a `@ref`. + +WARNING: Firebase Data Connect does not validate the SQL of the view or +evaluate whether it matches the defined fields. + +If the SQL view is invalid or undefined, related requests may fail. +If the SQL view return incompatible types. Firebase Data Connect will surface +an error in the response. +""" +directive @view( + """ + The SQL view name. If no `name` or `sql` are provided, defaults to + snake_case of the singular type name. + """ + name: String @fdc_oneOf + """ + SQL SELECT statement to use as the basis for this type. Note that all SQL + identifiers should be snake_case and all GraphQL identifiers should be + camelCase. + """ + sql: String @fdc_oneOf + "Override the singular name. Default is the camel case of the type name." + singular: String + "Override the plural name. Default is generated based on English patterns." + plural: String +) on OBJECT + +""" +Specify additional column options. + +Given `type TableName @table { fieldName: Int } ` + + - `field_name` is the SQL column name. Override with `@col(name)`. + +""" +directive @col( + "The SQL database column name. Defaults to ." + name: String + """ + Override SQL columns data type. + Each GraphQL type could map to many SQL data types. + Refer to Postgres supported data types and mappings to GQL. + """ + dataType: String + """ + Defines a fixed column size for certain scalar types. + + - For Vector, size is required. It establishes the length of the vector. + - For String, size converts `text` type to `varchar(size)`. + """ + size: Int +) on FIELD_DEFINITION + + +""" +Define a reference field to another table. + +Given `type TableName @table { refField: AnotherTableName }`, it defines a foreign-key constraint + + - with id `table_name_ref_field_fkey` (override with `@ref(constraintName)`) + - from `table_name.ref_field` (override with `@ref(fields)`) + - to `another_table_name.id` (override with `@ref(references)`) + +Does not support `[AnotherTableName]` because array fields cannot have foreign-key constraints. +Nullability determines whether the reference is required. + + - `refField: AnotherTableName`: optional reference, SET_NULL on delete. + - `refField: AnotherTableName!`: required reference, CASCADE on delete. + +Consider all types of SQL relations: + + - many-to-one relations involve a reference field on the many-side. + - many-to-maybe-one if `refField: AnotherTableName`. + - many-to-exactly-one if `refField: AnotherTableName!`. + - one-to-one relations involve a unique reference field on one side. + - maybe-one-to-maybe-one if `refField: AnotherTableName @unique`. + - maybe-one-to-exact-one if `refField: AnotherTableName! @unique`. + - exact-one-to-exact-one shall be represented as a single table instead. + - many-to-many relations involve a join table. + - Its primary keys must be two non-null reference fields to tables bridged together to guarantee at most one relation per pair. + +type TableNameToAnotherTableName @table(key: ["refField", "anotherRefField"]) { + refField: TableName! + anotherRefField: AnotherTableName! +} + +""" +directive @ref( + "The SQL database foreign key constraint name. Default to __fkey." + constraintName: String + """ + Foreign key fields. Default to . + """ + fields: [String!] + "The fields that the foreign key references in the other table. Default to the primary key." + references: [String!] +) on FIELD_DEFINITION + +"Define the direction of an orderby query" +enum OrderDirection { + ASC + DESC +} + +enum ColDefault @fdc_deprecated { + """ + Generates a random UUID (v4) as the default column value. + Compatible with String or UUID typed fields. + """ + UUID + """ + Generates an auto-incrementing sequence as the default column value. + Compatible with Int and Int64 typed fields. + """ + SEQUENCE + """ + Populates the default column value with the current date or timestamp. + Compatible with Date and Timestamp typed fields. + """ + NOW +} + +""" +Specify the default column value. + +The supported arguments vary based on the field type. +""" +directive @default( + "A constant value. Validated against the field GraphQL type at compile-time." + value: Any @fdc_oneOf(required: true) + "(Deprecated) Built-in common ways to generate initial value." + generate: ColDefault @fdc_oneOf(required: true) @deprecated + "A CEL expression, whose return value must match the field data type." + expr: Any_Expr @fdc_oneOf(required: true) + """ + A raw SQL expression, whose SQL data type must match the underlying column. + + The value is any variable-free expression (in particular, cross-references to + other columns in the current table are not allowed). Subqueries are not allowed either. + https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-DEFAULT + """ + sql: Any_SQL @fdc_oneOf(required: true) +) on FIELD_DEFINITION +""" +Date is a string in the YYYY-MM-DD format representing a local-only date. + +See the description for Timestamp for range and limitations. + +As a FDC-specific extension, inputs that includes time portions (as specified by +the Timestamp scalar) are accepted but only the date portion is used. In other +words, only the part before "T" is used and the rest discarded. This effectively +truncates it to the local date in the specified time-zone. + +Outputs will always be in the canonical YYYY-MM-DD format. +""" +scalar Date @specifiedBy(url: "https://scalars.graphql.org/andimarek/local-date.html") + +""" +Timestamp is a RFC 3339 string that represents an exact point in time. + +The serialization format follows https://scalars.graphql.org/andimarek/date-time +except the "Non-optional exact milliseconds" Section. As a FDC-specific +extension, inputs and outputs may contain 0, 3, 6, or 9 fractional digits. + +Specifically, output precision varies by server-side factors such as data source +support and clients must not rely on an exact number of digits. Clients may +truncate extra digits as fit, with the caveat that there may be information loss +if the truncated value is subsequently sent back to the server. + +FDC only supports year 1583 to 9999 (inclusive) and uses the ISO-8601 calendar +system for all date-time calculations. Notably, the expanded year representation +(+/-YYYYY) is rejected and Year 1582 and before may either be rejected or cause +undefined behavior. +""" +scalar Timestamp @specifiedBy(url: "https://scalars.graphql.org/andimarek/date-time") + +""" +A Common Expression Language (CEL) expression that returns a Timestamp at runtime. + +Limitation: Right now, only a few expressions are supported. Those are listed +using the @fdc_example directive on this scalar. +""" +scalar Timestamp_Expr + @specifiedBy(url: "https://github.com/google/cel-spec") + @fdc_celExpression(returnType: "google.protobuf.Timestamp") + @fdc_forbiddenAsVariableType + @fdc_forbiddenAsFieldType + @fdc_example(value: "request.time", description: "The timestamp when the request is received (with microseconds precision).") + +""" +A Common Expression Language (CEL) expression that returns a Timestamp at runtime, +which is then truncated to UTC date only. The time-of-day parts are discarded. + +Limitation: Right now, only a few expressions are supported. Those are listed +using the @fdc_example directive on this scalar. +""" +scalar Date_Expr + @specifiedBy(url: "https://github.com/google/cel-spec") + @fdc_celExpression(returnType: "google.protobuf.Timestamp") + @fdc_forbiddenAsVariableType + @fdc_forbiddenAsFieldType + @fdc_example(value: "request.time", description: "The UTC date on which the request is received.") + +"Conditions on a Date value" +input Date_Filter { + isNull: Boolean + eq: Date @fdc_oneOf(group: "eq") + eq_expr: Date_Expr @fdc_oneOf(group: "eq") + eq_date: Date_Relative @fdc_oneOf(group: "eq") + ne: Date @fdc_oneOf(group: "ne") + ne_expr: Date_Expr @fdc_oneOf(group: "ne") + ne_date: Date_Relative @fdc_oneOf(group: "ne") + in: [Date!] + nin: [Date!] + gt: Date @fdc_oneOf(group: "gt") + gt_expr: Date_Expr @fdc_oneOf(group: "gt") + gt_date: Date_Relative @fdc_oneOf(group: "gt") + ge: Date @fdc_oneOf(group: "ge") + ge_expr: Date_Expr @fdc_oneOf(group: "ge") + ge_date: Date_Relative @fdc_oneOf(group: "ge") + lt: Date @fdc_oneOf(group: "lt") + lt_expr: Date_Expr @fdc_oneOf(group: "lt") + lt_date: Date_Relative @fdc_oneOf(group: "lt") + le: Date @fdc_oneOf(group: "le") + le_expr: Date_Expr @fdc_oneOf(group: "le") + le_date: Date_Relative @fdc_oneOf(group: "le") +} + +"Conditions on a Date list" +input Date_ListFilter { + includes: Date @fdc_oneOf(group: "includes") + includes_expr: Date_Expr @fdc_oneOf(group: "includes") + includes_date: Date_Relative @fdc_oneOf(group: "includes") + excludes: Date @fdc_oneOf(group: "excludes") + excludes_expr: Date_Expr @fdc_oneOf(group: "excludes") + excludes_date: Date_Relative @fdc_oneOf(group: "excludes") + includesAll: [Date!] + excludesAll: [Date!] +} + +"Conditions on an Timestamp value" +input Timestamp_Filter { + isNull: Boolean + eq: Timestamp @fdc_oneOf(group: "eq") + eq_expr: Timestamp_Expr @fdc_oneOf(group: "eq") + eq_time: Timestamp_Relative @fdc_oneOf(group: "eq") + ne: Timestamp @fdc_oneOf(group: "ne") + ne_expr: Timestamp_Expr @fdc_oneOf(group: "ne") + ne_time: Timestamp_Relative @fdc_oneOf(group: "ne") + in: [Timestamp!] + nin: [Timestamp!] + gt: Timestamp @fdc_oneOf(group: "gt") + gt_expr: Timestamp_Expr @fdc_oneOf(group: "gt") + gt_time: Timestamp_Relative @fdc_oneOf(group: "gt") + ge: Timestamp @fdc_oneOf(group: "ge") + ge_expr: Timestamp_Expr @fdc_oneOf(group: "ge") + ge_time: Timestamp_Relative @fdc_oneOf(group: "ge") + lt: Timestamp @fdc_oneOf(group: "lt") + lt_expr: Timestamp_Expr @fdc_oneOf(group: "lt") + lt_time: Timestamp_Relative @fdc_oneOf(group: "lt") + le: Timestamp @fdc_oneOf(group: "le") + le_expr: Timestamp_Expr @fdc_oneOf(group: "le") + le_time: Timestamp_Relative @fdc_oneOf(group: "le") +} + +"Conditions on a Timestamp list" +input Timestamp_ListFilter { + includes: Timestamp @fdc_oneOf(group: "includes") + includes_expr: Timestamp_Expr @fdc_oneOf(group: "includes") + includes_time: Timestamp_Relative @fdc_oneOf(group: "includes") + excludes: Timestamp @fdc_oneOf(group: "excludes") + excludes_expr: Timestamp_Expr @fdc_oneOf(group: "excludes") + excludes_time: Timestamp_Relative @fdc_oneOf(group: "excludes") + includesAll: [Timestamp!] + excludesAll: [Timestamp!] +} + +"Update input of a Date value" +input Date_Update { + set: Date @fdc_oneOf(group: "set") + set_expr: Date_Expr @fdc_oneOf(group: "set") + set_date: Date_Relative @fdc_oneOf(group: "set") +} + +"Update input of a Date list value" +input Date_ListUpdate { + set: [Date!] + append: [Date!] + prepend: [Date!] + delete: Int + i: Int + update: Date +} + +"Update input of a Timestamp value" +input Timestamp_Update { + set: Timestamp @fdc_oneOf(group: "set") + set_expr: Timestamp_Expr @fdc_oneOf(group: "set") + set_time: Timestamp_Relative @fdc_oneOf(group: "set") +} + +"Update input of a Timestamp list value" +input Timestamp_ListUpdate { + set: [Timestamp!] + append: [Timestamp!] + prepend: [Timestamp!] + delete: Int + i: Int + update: Timestamp +} + +"A runtime-calculated Timestamp value relative to `now` or `at`." +input Timestamp_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { + now: True @fdc_oneOf(group: "from", required: true) + at: Timestamp @fdc_oneOf(group: "from", required: true) + + add: Timestamp_Duration + sub: Timestamp_Duration + + truncateTo: Timestamp_Interval +} + +input Timestamp_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { + milliseconds: Int! = 0 + seconds: Int! = 0 + minutes: Int! = 0 + hours: Int! = 0 + days: Int! = 0 + weeks: Int! = 0 + months: Int! = 0 + years: Int! = 0 +} + +enum Timestamp_Interval @fdc_forbiddenAsFieldType { + SECOND + MINUTE + HOUR + DAY + WEEK + MONTH + YEAR +} + +"A runtime-calculated Date value relative to `today` or `on`." +input Date_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { + today: True @fdc_oneOf(group: "from", required: true) + on: Date @fdc_oneOf(group: "from", required: true) + + add: Date_Duration + sub: Date_Duration + + truncateTo: Date_Interval +} + +input Date_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { + days: Int! = 0 + weeks: Int! = 0 + months: Int! = 0 + years: Int! = 0 +} + +enum Date_Interval @fdc_forbiddenAsFieldType { + WEEK + MONTH + YEAR +} +"Update input of a String value" +input String_Update { + set: String @fdc_oneOf(group: "set") + set_expr: String_Expr @fdc_oneOf(group: "set") +} + +"Update input of a String list value" +input String_ListUpdate { + set: [String!] + append: [String!] + prepend: [String!] +} + +"Update input of a UUID value" +input UUID_Update { + set: UUID @fdc_oneOf(group: "set") + set_expr: UUID_Expr @fdc_oneOf(group: "set") +} + +"Update input of an ID list value" +input UUID_ListUpdate { + set: [UUID!] + append: [UUID!] + prepend: [UUID!] +} + +"Update input of an Int value" +input Int_Update { + set: Int + inc: Int + dec: Int +} + +"Update input of an Int list value" +input Int_ListUpdate { + set: [Int!] + append: [Int!] + prepend: [Int!] +} + +"Update input of an Int64 value" +input Int64_Update { + set: Int64 + inc: Int64 + dec: Int64 +} + +"Update input of an Int64 list value" +input Int64_ListUpdate { + set: [Int64!] + append: [Int64!] + prepend: [Int64!] +} + +"Update input of a Float value" +input Float_Update { + set: Float + inc: Float + dec: Float +} + +"Update input of a Float list value" +input Float_ListUpdate { + set: [Float!] + append: [Float!] + prepend: [Float!] +} + +"Update input of a Boolean value" +input Boolean_Update { + set: Boolean +} + +"Update input of a Boolean list value" +input Boolean_ListUpdate { + set: [Boolean!] + append: [Boolean!] + prepend: [Boolean!] +} + +"Update input of an Any value" +input Any_Update { + set: Any +} + +"Update input of an Any list value" +input Any_ListUpdate { + set: [Any!] + append: [Any!] + prepend: [Any!] +} +""" +Vector is an array of single-precision floating-point numbers, serialized +as a JSON array. All elements must be finite (no NaN, Infinity or -Infinity). + +Example: [1.1, 2, 3.3] +""" +scalar Vector + +""" +Defines what siliarlity function to use for fetching vectors. +Details here: https://github.com/pgvector/pgvector?tab=readme-ov-file#vector-functions +""" +enum VectorSimilarityMethod { + L2 + COSINE + INNER_PRODUCT +} + +"Conditions on an Vector value" +input Vector_Filter { + eq: Vector + ne: Vector + in: [Vector!] + nin: [Vector!] + isNull: Boolean +} + +input Vector_ListFilter { + "When true, will match if the list includes the supplied vector." + includes: Vector + excludes: Vector + includesAll: [Vector!] + excludesAll: [Vector!] +} + +"Update input of an Vector value" +input Vector_Update { + set: Vector @fdc_oneOf(group: "set") + set_embed: Vector_Embed @fdc_oneOf(group: "set") +} + +"Update input of a Vector list value" +input Vector_ListUpdate { + set: [Vector] + append: [Vector] + prepend: [Vector] + delete: Int + i: Int + update: Vector +} + +""" +Create a vector embedding of text using the given model on Vertex AI. + +Example: {text: "Hi there", model: "textembedding-gecko@003"} +See: https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-text-embeddings + +Limitation: In the emulator, if Vertex AI is not configured, a pseudorandom +vector is generated from text as a fake implementation for testing only. +""" +input Vector_Embed @fdc_forbiddenAsVariableType { + model: Vector_Embed_Model! + text: String! +} + +""" +A string that specifies a Vertex AI model and version. + +It is strongly recommended to specify a stable model version (for example, +textembedding-gecko@003). The latest version of a model is in Preview and is not +General Availability (GA). Because the latest version is in Preview, it isn't +guaranteed to be production ready. +""" +scalar Vector_Embed_Model + @specifiedBy(url: "https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versioning") + @fdc_forbiddenAsVariableType + @fdc_forbiddenAsFieldType + @fdc_example(value: "textembedding-gecko@003", description: "A stable version of the textembedding-gecko model") diff --git a/dataconnect/dataconnect/1_movie_insert.gql b/dataconnect/dataconnect/1_movie_insert.gql new file mode 100644 index 000000000..1a264ebbc --- /dev/null +++ b/dataconnect/dataconnect/1_movie_insert.gql @@ -0,0 +1,241 @@ +mutation { + movie1: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440000", + title: "Inception", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Finception.jpg?alt=media&token=0a2950ee-0df7-4909-a5fd-e9f44dd803d6", + releaseYear: 2010, + genre: "sci-fi", + rating: 8.8, + description: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move.", + tags: ["thriller", "action"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move."} + }) + + movie2: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440001", + title: "The Matrix", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_matrix.jpg?alt=media&token=9d9a952e-6441-420a-8479-6a58d62655f8", + releaseYear: 1999, + genre: "action", + rating: 8.7, + description: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny.", + tags: ["sci-fi", "adventure"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny."} + }) + + movie3: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440002", + title: "John Wick 4", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fjohn_wick_4.jpg?alt=media&token=98c60306-fbd9-4718-ac7a-2c6cde8706d8", + releaseYear: 2023, + genre: "action", + rating: 8.1, + description: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances.", + tags: ["action", "thriller"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances."} + }) + + movie4: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440003", + title: "The Dark Knight", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_dark_knight.jpg?alt=media&token=7ee322e9-3b27-4952-b4a9-e445a15412de", + releaseYear: 2008, + genre: "action", + rating: 9.0, + description: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice.", + tags: ["action", "drama"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice."} + }) + + movie5: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440004", + title: "Fight Club", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Ffight_club.jpg?alt=media&token=1dcfbea5-feb3-4345-92bc-7551c671cb49", + releaseYear: 1999, + genre: "drama", + rating: 8.8, + description: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity.", + tags: ["drama", "thriller"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity."} + }) + + movie6: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440005", + title: "Pulp Fiction", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fpulp_fiction.jpg?alt=media&token=d9ccbe88-c19b-4aab-bb89-016a7cbd4051", + releaseYear: 1994, + genre: "crime", + rating: 8.9, + description: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references.", + tags: ["crime", "drama"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references."} + }) + + movie7: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440006", + title: "The Lord of the Rings: The Fellowship of the Ring", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Flotr_fellowship.jpg?alt=media&token=f98d137b-f37f-43e6-86f2-7f49e946e133", + releaseYear: 2001, + genre: "fantasy", + rating: 8.8, + description: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond.", + tags: ["fantasy", "adventure"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond."} + }) + + movie8: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440007", + title: "The Shawshank Redemption", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_shawshanks_redemption.jpg?alt=media&token=8fae5b0c-8797-4607-9c2b-3ecc09b48a8e", + releaseYear: 1994, + genre: "drama", + rating: 9.3, + description: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman).", + tags: ["drama", "crime"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman)."} + }) + + movie9: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440008", + title: "Forrest Gump", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fforrest_gump.jpeg?alt=media&token=decc25fa-d88e-49cc-a2ca-fc9a77e3a651", + releaseYear: 1994, + genre: "drama", + rating: 8.8, + description: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright).", + tags: ["drama", "romance"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright)."} + }) + + movie10: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440009", + title: "The Godfather", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_godfather.jpg?alt=media&token=52cc0cbd-0fc7-4afa-a44e-f44ab4880079", + releaseYear: 1972, + genre: "crime", + rating: 9.2, + description: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal.", + tags: ["crime", "drama"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal."} + }) + + movie11: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440010", + title: "The Silence of the Lambs", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_silence_of_the_lambs.jpg?alt=media&token=064778c8-8b0e-4412-8235-511082613118", + releaseYear: 1991, + genre: "thriller", + rating: 8.6, + description: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer.", + tags: ["thriller", "crime"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer."} + }) + + movie12: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440011", + title: "Saving Private Ryan", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fsaving_private_ryan.jpg?alt=media&token=54b5ade0-e41d-4f53-a39d-56fd5be270f9", + releaseYear: 1998, + genre: "war", + rating: 8.6, + description: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war.", + tags: ["war", "drama"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war."} + }) + + movie13: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440012", + title: "The Avengers", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_avengers.jpg?alt=media&token=54cd8f43-cf29-4e86-9f78-a4c43c9ac79c", + releaseYear: 2012, + genre: "action", + rating: 8.0, + description: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast.", + tags: ["action", "sci-fi"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast."} + }) + + movie14: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440013", + title: "Gladiator", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fgladiator.jpg?alt=media&token=aa112d9f-de39-4b5e-80c4-621c7af842bd", + releaseYear: 2000, + genre: "action", + rating: 8.5, + description: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance.", + tags: ["action", "drama"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance."} + }) + + movie15: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440014", + title: "Titanic", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Ftitanic.png?alt=media&token=5f594626-19d8-4043-9d09-81104e128ed2", + releaseYear: 1997, + genre: "romance", + rating: 7.8, + description: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals.", + tags: ["romance", "drama"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals."} + }) + + movie16: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440015", + title: "Avatar", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Favatar.jpg?alt=media&token=2d858616-4033-408a-aea0-9add07a67c88", + releaseYear: 2009, + genre: "sci-fi", + rating: 7.8, + description: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience.", + tags: ["sci-fi", "adventure"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience."} + }) + + movie17: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440016", + title: "Jurassic Park", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fjurassic_park.jpg?alt=media&token=040b46b8-c974-4825-85e5-2652bc375ed7", + releaseYear: 1993, + genre: "adventure", + rating: 8.1, + description: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures.", + tags: ["adventure", "sci-fi"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures."} + }) + + movie18: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440017", + title: "The Lion King", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_lion_king.jpg?alt=media&token=4778e0ac-96e7-44fd-9422-423d5aad353f", + releaseYear: 1994, + genre: "animation", + rating: 8.5, + description: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption.", + tags: ["animation", "drama"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption."} + }) + + movie19: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440018", + title: "Star Wars: Episode IV - A New Hope", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fstar_wars_4.jpg?alt=media&token=cad4cb98-89ce-4c8a-a735-d7cdaf884b26", + releaseYear: 1977, + genre: "sci-fi", + rating: 8.6, + description: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters.", + tags: ["sci-fi", "adventure"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters."} + }) + + movie20: movie_insert(data: { + id: "550e8400-e29b-41d4-a716-446655440019", + title: "Blade Runner", + imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fblade_runner.jpg?alt=media&token=4c7e7c9d-c9c7-4cef-9eb7-4302b2610905", + releaseYear: 1982, + genre: "sci-fi", + rating: 8.1, + description: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity.", + tags: ["sci-fi", "thriller"], + descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity."} + }) +} diff --git a/dataconnect/dataconnect/2_actor_insert.gql b/dataconnect/dataconnect/2_actor_insert.gql new file mode 100644 index 000000000..a4a0c1c49 --- /dev/null +++ b/dataconnect/dataconnect/2_actor_insert.gql @@ -0,0 +1,141 @@ +mutation { + actor1: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174000", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/46/Leonardo_Dicaprio_Cannes_2019.jpg/440px-Leonardo_Dicaprio_Cannes_2019.jpg", + name: "Leonardo DiCaprio", + biography: "Leonardo DiCaprio is an American actor and producer. He has received numerous awards, including an Academy Award and three Golden Globe Awards. DiCaprio is known for his roles in Titanic, Inception, and The Revenant." + }) + + actor2: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174001", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Reuni%C3%A3o_com_o_ator_norte-americano_Keanu_Reeves_%2846806576944%29_%28cropped%29.jpg/440px-Reuni%C3%A3o_com_o_ator_norte-americano_Keanu_Reeves_%2846806576944%29_%28cropped%29.jpg", + name: "Keanu Reeves", + biography: "Keanu Reeves is a Canadian actor known for his roles in The Matrix and John Wick series. He has gained acclaim for his versatility and has also directed and produced several films." + }) + + actor3: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174002", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Matthew_McConaughey_2019_%2848648344772%29.jpg/440px-Matthew_McConaughey_2019_%2848648344772%29.jpg", + name: "Matthew McConaughey", + biography: "Matthew McConaughey is an American actor and producer. He gained fame with his breakout role in Dazed and Confused and has won an Academy Award for his performance in Dallas Buyers Club." + }) + + actor4: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174003", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Christian_Bale-7837.jpg/440px-Christian_Bale-7837.jpg", + name: "Christian Bale", + biography: "Christian Bale is an English actor known for his versatility and physical transformations for roles. He has starred in The Dark Knight Trilogy and won an Academy Award for The Fighter." + }) + + actor5: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174004", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Brad_Pitt_2019_by_Glenn_Francis.jpg/440px-Brad_Pitt_2019_by_Glenn_Francis.jpg", + name: "Brad Pitt", + biography: "Brad Pitt is an American actor and producer. He has won two Academy Awards and is known for his roles in Fight Club, Ocean's Eleven, and Once Upon a Time in Hollywood." + }) + + actor6: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174005", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/SamuelLJackson.jpg/440px-SamuelLJackson.jpg", + name: "Samuel L. Jackson", + biography: "Samuel L. Jackson is an American actor and producer. He is one of the most widely recognized actors of his generation, known for his roles in Pulp Fiction, the Marvel Cinematic Universe, and Jurassic Park." + }) + + actor7: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174006", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/6/64/Viggo_Mortensen_B_%282020%29.jpg", + name: "Viggo Mortensen", + biography: "Viggo Mortensen is an American actor, author, and musician. He is best known for his role as Aragorn in The Lord of the Rings trilogy and has been nominated for three Academy Awards." + }) + + actor8: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174007", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/42/Morgan_Freeman_at_The_Pentagon_on_2_August_2023_-_230802-D-PM193-3363_%28cropped%29.jpg/440px-Morgan_Freeman_at_The_Pentagon_on_2_August_2023_-_230802-D-PM193-3363_%28cropped%29.jpg", + name: "Morgan Freeman", + biography: "Morgan Freeman is an American actor, director, and narrator. He is known for his distinctive voice and has won an Academy Award for his role in Million Dollar Baby." + }) + + actor9: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174008", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Tom_Hanks_TIFF_2019.jpg/440px-Tom_Hanks_TIFF_2019.jpg", + name: "Tom Hanks", + biography: "Tom Hanks is an American actor and filmmaker. He is known for his roles in Forrest Gump, Saving Private Ryan, and Toy Story, and has won two Academy Awards for Best Actor." + }) + + actor10: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174009", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Al_Pacino_2016_%2830401544240%29.jpg/440px-Al_Pacino_2016_%2830401544240%29.jpg", + name: "Al Pacino", + biography: "Al Pacino is an American actor and filmmaker. He has won an Academy Award, two Tony Awards, and two Primetime Emmy Awards. He is known for his roles in The Godfather series, Scarface, and Scent of a Woman." + }) + + actor11: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174010", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/3/3f/Jodie_Foster_C%C3%A9sars_2011_2_%28cropped%29.jpg", + name: "Jodie Foster", + biography: "Jodie Foster is an American actress and director. She has won two Academy Awards for Best Actress for her roles in The Accused and The Silence of the Lambs." + }) + + actor12: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174011", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Tom_Cruise_by_Gage_Skidmore_2.jpg/440px-Tom_Cruise_by_Gage_Skidmore_2.jpg", + name: "Tom Cruise", + biography: "Tom Cruise is an American actor and producer. He is one of the highest-paid actors in the world and is known for his roles in Top Gun, the Mission: Impossible series, and Jerry Maguire." + }) + + actor13: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174012", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/9/94/Robert_Downey_Jr_2014_Comic_Con_%28cropped%29.jpg/440px-Robert_Downey_Jr_2014_Comic_Con_%28cropped%29.jpg", + name: "Robert Downey Jr.", + biography: "Robert Downey Jr. is an American actor and producer. He is known for his roles in Iron Man, Sherlock Holmes, and Chaplin, and has been a major figure in the Marvel Cinematic Universe." + }) + + actor14: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174013", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Russell_Crowe_%2833994020424%29.jpg/440px-Russell_Crowe_%2833994020424%29.jpg", + name: "Russell Crowe", + biography: "Russell Crowe is an Australian actor, film producer, and musician. He gained international fame for his role in Gladiator, for which he won the Academy Award for Best Actor." + }) + + actor15: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174014", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Kate_Winslet_at_the_2017_Toronto_International_Film_Festival_%28cropped%29.jpg/440px-Kate_Winslet_at_the_2017_Toronto_International_Film_Festival_%28cropped%29.jpg", + name: "Kate Winslet", + biography: "Kate Winslet is an English actress known for her roles in Titanic, The Reader, and Eternal Sunshine of the Spotless Mind. She has won numerous awards, including an Academy Award and an Emmy." + }) + + actor16: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174015", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Sigourney_Weaver_by_Gage_Skidmore_4.jpg/862px-Sigourney_Weaver_by_Gage_Skidmore_4.jpg", + name: "Sigourney Weaver", + biography: "Sigourney Weaver is an American actress best known for her roles in the Alien franchise, Ghostbusters, and Avatar. She has been nominated for three Academy Awards and has won two Golden Globe Awards." + }) + + actor17: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174016", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Jeff_Goldblum_by_Gage_Skidmore_3.jpg/440px-Jeff_Goldblum_by_Gage_Skidmore_3.jpg", + name: "Jeff Goldblum", + biography: "Jeff Goldblum is an American actor and musician known for his roles in Jurassic Park, Independence Day, and The Fly. His unique delivery and eccentric characters have made him a cult icon." + }) + + actor18: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174017", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/James_Earl_Jones_%288516667383%29.jpg/440px-James_Earl_Jones_%288516667383%29.jpg", + name: "James Earl Jones", + biography: "James Earl Jones is an American actor known for his deep resonant voice, which has been featured in roles such as Darth Vader in Star Wars and Mufasa in The Lion King. He has won multiple awards, including a Tony, Emmy, and Grammy." + }) + + actor19: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174018", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/Harrison_Ford_by_Gage_Skidmore_3.jpg/440px-Harrison_Ford_by_Gage_Skidmore_3.jpg", + name: "Harrison Ford", + biography: "Harrison Ford is an American actor known for his iconic roles as Han Solo in Star Wars and Indiana Jones in the Indiana Jones series. He has been nominated for an Academy Award and has received numerous other accolades." + }) + + actor20: actor_insert(data: { + id: "123e4567-e89b-12d3-a456-426614174019", + imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Arnold_Schwarzenegger_by_Gage_Skidmore_4.jpg/440px-Arnold_Schwarzenegger_by_Gage_Skidmore_4.jpg", + name: "Arnold Schwarzenegger", + biography: "Arnold Schwarzenegger is an Austrian-American actor, businessman, and former politician. He is best known for his roles in The Terminator series and Total Recall, and for serving as the 38th Governor of California." + }) +} diff --git a/dataconnect/dataconnect/3_movie_actor_insert.gql b/dataconnect/dataconnect/3_movie_actor_insert.gql new file mode 100644 index 000000000..b8a270541 --- /dev/null +++ b/dataconnect/dataconnect/3_movie_actor_insert.gql @@ -0,0 +1,283 @@ +mutation { + metadata1: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440000", + director: "Christopher Nolan" + }) + + metadata2: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440001", + director: "Lana Wachowski, Lilly Wachowski" + }) + + metadata3: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440002", + director: "Chad Stahelski" + }) + + metadata4: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440003", + director: "Christopher Nolan" + }) + + metadata5: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440004", + director: "David Fincher" + }) + + metadata6: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440005", + director: "Quentin Tarantino" + }) + + metadata7: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440006", + director: "Peter Jackson" + }) + + metadata8: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440007", + director: "Frank Darabont" + }) + + metadata9: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440008", + director: "Robert Zemeckis" + }) + + metadata10: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440009", + director: "Francis Ford Coppola" + }) + + metadata11: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440010", + director: "Jonathan Demme" + }) + + metadata12: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440011", + director: "Steven Spielberg" + }) + + metadata13: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440012", + director: "Joss Whedon" + }) + + metadata14: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440013", + director: "Ridley Scott" + }) + + metadata15: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440014", + director: "James Cameron" + }) + + metadata16: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440015", + director: "James Cameron" + }) + + metadata17: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440016", + director: "Steven Spielberg" + }) + + metadata18: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440017", + director: "Roger Allers, Rob Minkoff" + }) + + metadata19: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440018", + director: "George Lucas" + }) + + metadata20: movieMetadata_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440019", + director: "Ridley Scott" + }) + + movieActor1: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440000", + actorId: "123e4567-e89b-12d3-a456-426614174000", + role: "main" + }) + + movieActor2: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440001", + actorId: "123e4567-e89b-12d3-a456-426614174001", + role: "main" + }) + + movieActor3: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440002", + actorId: "123e4567-e89b-12d3-a456-426614174001", + role: "main" + }) + + movieActor4: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440003", + actorId: "123e4567-e89b-12d3-a456-426614174003", + role: "main" + }) + + movieActor5: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440004", + actorId: "123e4567-e89b-12d3-a456-426614174004", + role: "main" + }) + + movieActor6: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440005", + actorId: "123e4567-e89b-12d3-a456-426614174005", + role: "main" + }) + + movieActor7: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440006", + actorId: "123e4567-e89b-12d3-a456-426614174006", + role: "main" + }) + + movieActor8: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440007", + actorId: "123e4567-e89b-12d3-a456-426614174007", + role: "main" + }) + + movieActor9: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440008", + actorId: "123e4567-e89b-12d3-a456-426614174008", + role: "main" + }) + + movieActor10: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440009", + actorId: "123e4567-e89b-12d3-a456-426614174009", + role: "main" + }) + + movieActor11: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440010", + actorId: "123e4567-e89b-12d3-a456-426614174010", + role: "main" + }) + + movieActor12: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440011", + actorId: "123e4567-e89b-12d3-a456-426614174011", + role: "main" + }) + + movieActor13: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440012", + actorId: "123e4567-e89b-12d3-a456-426614174012", + role: "main" + }) + + movieActor14: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440013", + actorId: "123e4567-e89b-12d3-a456-426614174013", + role: "main" + }) + + movieActor15: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440014", + actorId: "123e4567-e89b-12d3-a456-426614174014", + role: "main" + }) + + movieActor16: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440015", + actorId: "123e4567-e89b-12d3-a456-426614174015", + role: "main" + }) + + movieActor17: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440016", + actorId: "123e4567-e89b-12d3-a456-426614174016", + role: "main" + }) + + movieActor18: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440017", + actorId: "123e4567-e89b-12d3-a456-426614174017", + role: "main" + }) + + movieActor19: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440018", + actorId: "123e4567-e89b-12d3-a456-426614174018", + role: "main" + }) + + movieActor20: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440019", + actorId: "123e4567-e89b-12d3-a456-426614174019", + role: "main" + }) + + # Adding supporting actors + movieActor21: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440000", + actorId: "123e4567-e89b-12d3-a456-426614174001", + role: "supporting" + }) + + movieActor22: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440001", + actorId: "123e4567-e89b-12d3-a456-426614174002", + role: "supporting" + }) + + movieActor23: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440002", + actorId: "123e4567-e89b-12d3-a456-426614174003", + role: "supporting" + }) + + movieActor24: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440003", + actorId: "123e4567-e89b-12d3-a456-426614174004", + role: "supporting" + }) + + movieActor25: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440004", + actorId: "123e4567-e89b-12d3-a456-426614174005", + role: "supporting" + }) + + movieActor26: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440005", + actorId: "123e4567-e89b-12d3-a456-426614174006", + role: "supporting" + }) + + movieActor27: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440006", + actorId: "123e4567-e89b-12d3-a456-426614174007", + role: "supporting" + }) + + movieActor28: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440007", + actorId: "123e4567-e89b-12d3-a456-426614174008", + role: "supporting" + }) + + movieActor29: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440008", + actorId: "123e4567-e89b-12d3-a456-426614174009", + role: "supporting" + }) + + movieActor30: movieActor_insert(data: { + movieId: "550e8400-e29b-41d4-a716-446655440009", + actorId: "123e4567-e89b-12d3-a456-426614174010", + role: "supporting" + }) + +} diff --git a/dataconnect/dataconnect/4_user_favorites_review_insert.gql b/dataconnect/dataconnect/4_user_favorites_review_insert.gql new file mode 100644 index 000000000..70bf8fa23 --- /dev/null +++ b/dataconnect/dataconnect/4_user_favorites_review_insert.gql @@ -0,0 +1,184 @@ +mutation { + user1: user_insert(data: { + id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", + username: "cynthia_w" + }) + + user2: user_insert(data: { + id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", + username: "momo_h" + }) + + user3: user_insert(data: { + id: "TBedjwCX0Jf955Uuoxk6k74sY0l1", + username: "siyi_w" + }) + + review1: review_insert(data: { + id: "345e4567-e89b-12d3-a456-426614174000", + + userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", + movieId: "550e8400-e29b-41d4-a716-446655440000", + rating: 5, + reviewText: "An incredible movie with a mind-blowing plot!", + reviewDate_date: { today: true } + }) + + review2: review_insert(data: { + id: "345e4567-e89b-12d3-a456-426614174001", + userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", + + movieId: "550e8400-e29b-41d4-a716-446655440001", + rating: 5, + reviewText: "A revolutionary film that changed cinema forever.", + reviewDate_date: { today: true } + }) + + review3: review_insert(data: { + id: "345e4567-e89b-12d3-a456-426614174002", + userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1", + + movieId: "550e8400-e29b-41d4-a716-446655440002", + rating: 5, + reviewText: "A visually stunning and emotionally impactful movie.", + reviewDate_date: { today: true } + }) + + review4: review_insert(data: { + id: "345e4567-e89b-12d3-a456-426614174003", + userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", + + movieId: "550e8400-e29b-41d4-a716-446655440003", + rating: 4, + reviewText: "A fantastic superhero film with great performances.", + reviewDate_date: { today: true } + }) + + review5: review_insert(data: { + id: "345e4567-e89b-12d3-a456-426614174004", + userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", + + movieId: "550e8400-e29b-41d4-a716-446655440004", + rating: 5, + reviewText: "An amazing film that keeps you on the edge of your seat.", + reviewDate_date: { today: true } + }) + + review6: review_insert(data: { + id: "345e4567-e89b-12d3-a456-426614174005", + userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1", + + movieId: "550e8400-e29b-41d4-a716-446655440005", + rating: 5, + reviewText: "An absolute classic with unforgettable dialogue.", + reviewDate_date: { today: true } + }) + + favoriteMovie1: favoriteMovie_insert(data: { + userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", + + movieId: "550e8400-e29b-41d4-a716-446655440000" + }) + + favoriteMovie2: favoriteMovie_insert(data: { + userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", + + movieId: "550e8400-e29b-41d4-a716-446655440001" + }) + + favoriteMovie3: favoriteMovie_insert(data: { + userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1", + + movieId: "550e8400-e29b-41d4-a716-446655440002" + }) + + favoriteMovie4: favoriteMovie_insert(data: { + userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", + + movieId: "550e8400-e29b-41d4-a716-446655440003" + }) + + favoriteMovie5: favoriteMovie_insert(data: { + userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", + + movieId: "550e8400-e29b-41d4-a716-446655440004" + }) + + favoriteMovie6: favoriteMovie_insert(data: { + userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1", + + movieId: "550e8400-e29b-41d4-a716-446655440005" + }) + + favoriteActor1: favoriteActor_insert(data: { + userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", + + actorId: "123e4567-e89b-12d3-a456-426614174000" + }) + + favoriteActor2: favoriteActor_insert(data: { + userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", + + actorId: "123e4567-e89b-12d3-a456-426614174001" + }) + + favoriteActor3: favoriteActor_insert(data: { + userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1", + + actorId: "123e4567-e89b-12d3-a456-426614174002" + }) + + favoriteActor4: favoriteActor_insert(data: { + userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", + + actorId: "123e4567-e89b-12d3-a456-426614174003" + }) + + favoriteActor5: favoriteActor_insert(data: { + userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", + + actorId: "123e4567-e89b-12d3-a456-426614174004" + }) + + favoriteActor6: favoriteActor_insert(data: { + userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1", + + actorId: "123e4567-e89b-12d3-a456-426614174005" + }) + + watchedMovie1: watchedMovie_insert(data: { + userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", + + movieId: "550e8400-e29b-41d4-a716-446655440000" + }) + + watchedMovie2: watchedMovie_insert(data: { + userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", + + movieId: "550e8400-e29b-41d4-a716-446655440001" + }) + + watchedMovie3: watchedMovie_insert(data: { + userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1", + + movieId: "550e8400-e29b-41d4-a716-446655440002" + }) + + watchedMovie4: watchedMovie_insert(data: { + userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", + + movieId: "550e8400-e29b-41d4-a716-446655440003" + }) + + watchedMovie5: watchedMovie_insert(data: { + userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", + + movieId: "550e8400-e29b-41d4-a716-446655440004" + }) + + watchedMovie6: watchedMovie_insert(data: { + userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1", + + movieId: "550e8400-e29b-41d4-a716-446655440005" + }) +} diff --git a/dataconnect/dataconnect/connector/connector.yaml b/dataconnect/dataconnect/connector/connector.yaml new file mode 100644 index 000000000..66d17e5e5 --- /dev/null +++ b/dataconnect/dataconnect/connector/connector.yaml @@ -0,0 +1,14 @@ +connectorId: movie-connector +# Required. Accepted values are either "PUBLIC" or "ADMIN" (only "PUBLIC" for gated private +# preview). If "ADMIN", the connector in this directory is an AdminConnector and its operations +# are gated by IAM. +authMode: PUBLIC +generate: + javascriptSdk: + # Create a custom package name for your generated SDK + package: "@movie/sdk" + # Tells Data Connect where to store the generated SDK code, this should be in the same + # directory as your app code + outputDir: "../../movie/lib/dataconnect-sdk" + # This property tells Data Connect what directory to install the generated SDK to + # packageJsonDir: "../../movie/lib/dataconnect-sdk" diff --git a/dataconnect/dataconnect/connector/mutations.gql b/dataconnect/dataconnect/connector/mutations.gql new file mode 100644 index 000000000..57a6920ef --- /dev/null +++ b/dataconnect/dataconnect/connector/mutations.gql @@ -0,0 +1,113 @@ +# Create a movie based on user input +mutation createMovie( + $title: String! + $releaseYear: Int! + $genre: String! + $rating: Float + $description: String + $imageUrl: String! + $tags: [String!] = [] +) { + movie_insert( + data: { + title: $title + releaseYear: $releaseYear + genre: $genre + rating: $rating + description: $description + imageUrl: $imageUrl + tags: $tags + } + ) +} + +# Update movie information based on the provided ID +mutation updateMovie( + $id: UUID! + $title: String + $releaseYear: Int + $genre: String + $rating: Float + $description: String + $imageUrl: String + $tags: [String!] = [] +) { + movie_update( + id: $id + data: { + title: $title + releaseYear: $releaseYear + genre: $genre + rating: $rating + description: $description + imageUrl: $imageUrl + tags: $tags + } + ) +} + +# Delete a movie by its ID +mutation deleteMovie($id: UUID!) { + movie_delete(id: $id) +} + +# Delete movies with a rating lower than the specified minimum rating +mutation deleteUnpopularMovies($minRating: Float!) { + movie_deleteMany(where: { rating: { le: $minRating } }) +} + +# Add a movie to the user's watched list +mutation addWatchedMovie($movieId: UUID!) @auth(level: USER) { + watchedMovie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId }) +} + +# Remove a movie from the user's watched list +mutation deleteWatchedMovie($userId: String!, $movieId: UUID!) @auth(level: USER) { + watchedMovie_delete(key: { userId: $userId, movieId: $movieId }) +} + +# Add a movie to the user's favorites list +mutation addFavoritedMovie($movieId: UUID!) @auth(level: USER) { + favoriteMovie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId }) +} + +# Remove a movie from the user's favorites list +mutation deleteFavoritedMovie($userId: String!, $movieId: UUID!) @auth(level: USER) { + favoriteMovie_delete(key: { userId: $userId, movieId: $movieId }) +} + +# Add an actor to the user's favorites list +mutation addFavoritedActor($actorId: UUID!) @auth(level: USER) { + favoriteActor_upsert(data: { userId_expr: "auth.uid", actorId: $actorId }) +} + +# Remove an actor from the user's favorites list +mutation deleteFavoriteActor($userId: String!, $actorId: UUID!) @auth(level: USER) { + favoriteActor_delete(key: { userId: $userId, actorId: $actorId }) +} + +# Add a review for a movie +mutation addReview($movieId: UUID!, $rating: Int!, $reviewText: String!) @auth(level: USER) { + review_upsert( + data: { + userId_expr: "auth.uid" + movieId: $movieId + rating: $rating + reviewText: $reviewText + reviewDate_date: { today: true } + } + ) +} + +# Delete a user's review for a movie +mutation deleteReview($movieId: UUID!, $userId: String!) @auth(level: USER) { + review_delete(key: { userId: $userId, movieId: $movieId }) +} + +# Upsert (update or insert) a user based on their username +mutation upsertUser($username: String!) @auth(level: USER) { + user_upsert(data: { + id_expr: "auth.uid", + username: $username + }) +} diff --git a/dataconnect/dataconnect/connector/queries.gql b/dataconnect/dataconnect/connector/queries.gql new file mode 100644 index 000000000..f191debfc --- /dev/null +++ b/dataconnect/dataconnect/connector/queries.gql @@ -0,0 +1,565 @@ +# List subset of fields for movies +query ListMovies @auth(level: PUBLIC) { + movies { + id + title + imageUrl + releaseYear + genre + rating + tags + } +} + +# List subset of fields for users +query ListUsers @auth(level: PUBLIC) { + users { + id + username + favoriteActors_on_user { + actor { + id + name + imageUrl + } + } + favoriteMovies_on_user { + movie { + id + title + genre + imageUrl + tags + } + } + reviews_on_user { + id + rating + reviewText + reviewDate + movie { + id + title + } + } + watchedMovies_on_user { + movie { + id + title + genre + imageUrl + } + } + } +} + +# List movies of a certain genre +query ListMoviesByGenre($genre: String!) @auth(level: PUBLIC) { + mostPopular: movies( + where: { genre: { eq: $genre } } + orderBy: { rating: DESC } + ) { + id + title + imageUrl + rating + tags + } + mostRecent: movies( + where: { genre: { eq: $genre } } + orderBy: { releaseYear: DESC } + ) { + id + title + imageUrl + rating + tags + } +} + +# List movies by the order of release +query ListMoviesByReleaseYear @auth(level: PUBLIC) { + movies(orderBy: [{ releaseYear: DESC }]) { + id + title + imageUrl + } +} + +# Get movie by id +query GetMovieById($id: UUID!) @auth(level: PUBLIC) { + movie(id: $id) { + id + title + imageUrl + releaseYear + genre + rating + description + tags + metadata: movieMetadatas_on_movie { + director + } + mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) { + id + name + imageUrl + } + supportingActors: actors_via_MovieActor( + where: { role: { eq: "supporting" } } + ) { + id + name + imageUrl + } + sequelTo { + id + title + imageUrl + } + reviews: reviews_on_movie { + id + reviewText + reviewDate + rating + user { + id + username + } + } + } +} + +# Get actor by id +query GetActorById($id: UUID!) @auth(level: PUBLIC) { + actor(id: $id) { + id + name + imageUrl + biography + mainActors: movies_via_MovieActor(where: { role: { eq: "main" } }) { + id + title + genre + tags + imageUrl + } + supportingActors: movies_via_MovieActor( + where: { role: { eq: "supporting" } } + ) { + id + title + genre + tags + imageUrl + } + } +} + +# User movie preferences +query UserMoviePreferences($username: String!) @auth(level: USER) { + users(where: { username: { eq: $username } }) { + likedMovies: movies_via_Review(where: { rating: { ge: 4 } }) { + title + imageUrl + genre + description + } + dislikedMovies: movies_via_Review(where: { rating: { le: 2 } }) { + title + imageUrl + genre + description + } + } +} + +# Get movie metadata +query GetMovieMetadata($id: UUID!) @auth(level: PUBLIC) { + movie(id: $id) { + movieMetadatas_on_movie { + director + } + } +} + +# Get movie cast and actor roles +query GetMovieCast($movieId: UUID!, $actorId: UUID!) @auth(level: PUBLIC) { + movie(id: $movieId) { + mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) { + id + name + imageUrl + } + supportingActors: actors_via_MovieActor( + where: { role: { eq: "supporting" } } + ) { + id + name + imageUrl + } + } + actor(id: $actorId) { + mainRoles: movies_via_MovieActor(where: { role: { eq: "main" } }) { + id + title + imageUrl + } + supportingRoles: movies_via_MovieActor( + where: { role: { eq: "supporting" } } + ) { + id + title + imageUrl + } + } +} + +# List movies by partial title match +query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) { + movies(where: { title: { contains: $input } }) { + id + title + genre + rating + imageUrl + } +} + +# Fetch a single movie using key scalars (same as get movie by id) +query MovieByKey($key: Movie_Key!) @auth(level: PUBLIC) { + movie(key: $key) { + title + imageUrl + } +} + +# Fetch movies by title +query MovieByTitle($title: String!) @auth(level: PUBLIC) { + movies(where: { title: { eq: $title } }) { + id + title + imageUrl + genre + rating + } +} + +# Fetch top-rated movies by genre +query MovieByTopRating($genre: String) @auth(level: PUBLIC) { + mostPopular: movies( + where: { genre: { eq: $genre } } + orderBy: { rating: DESC } + ) { + id + title + imageUrl + rating + tags + } +} + +# List movies by tag +query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) { + movies(where: { tags: { includes: $tag } }) { + id + title + imageUrl + genre + rating + } +} + +# List top 10 movies +query MoviesTop10 @auth(level: PUBLIC) { + movies(orderBy: [{ rating: DESC }], limit: 10) { + id + title + imageUrl + rating + genre + tags + metadata: movieMetadatas_on_movie { + director + } + mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) { + id + name + imageUrl + } + supportingActors: actors_via_MovieActor(where: { role: { eq: "supporting" } }) { + id + name + imageUrl + } + } +} + +# List movies by release year range +query MoviesByReleaseYear($min: Int, $max: Int) @auth(level: PUBLIC) { + movies( + where: { releaseYear: { le: $max, ge: $min } } + orderBy: [{ releaseYear: ASC }] + ) { + id + rating + title + imageUrl + } +} + +# List recently released movies +query MoviesRecentlyReleased @auth(level: PUBLIC) { + movies(where: { releaseYear: { ge: 2010 } }) { + id + title + rating + imageUrl + genre + tags + } +} + +# List movies with filtering on fields +query ListMoviesFilter($genre: String, $limit: Int) @auth(level: PUBLIC) { + movies(where: { genre: { eq: $genre } }, limit: $limit) { + title + imageUrl + } +} + +# List movies by partial title string match +query ListMoviesByTitleString( + $prefix: String + $suffix: String + $contained: String +) @auth(level: PUBLIC) { + prefixed: movies(where: { description: { startsWith: $prefix } }) { + title + } + suffixed: movies(where: { description: { endsWith: $suffix } }) { + title + } + contained: movies(where: { description: { contains: $contained } }) { + title + } +} + +# List movies by rating and genre with OR/AND filters +query ListMoviesByRatingAndGenre($minRating: Float!, $genre: String) +@auth(level: PUBLIC) { + movies( + where: { _or: [{ rating: { ge: $minRating } }, { genre: { eq: $genre } }] } + ) { + title + imageUrl + } +} + +# Get favorite movies by user ID +query GetFavoriteMoviesById($id: String!) @auth(level: USER) { + user(id: $id) { + favoriteMovies_on_user { + movie { + id + title + genre + imageUrl + releaseYear + rating + description + } + } + } +} + +# Get favorite actors by user ID +query GetFavoriteActorsById($id: String!) @auth(level: USER) { + user(id: $id) { + favoriteActors_on_user { + actor { + id + name + imageUrl + } + } + } +} + +# Get watched movies by user ID +query GetWatchedMoviesByAuthId($id: String!) @auth(level: USER) { + user(id: $id) { + watchedMovies_on_user { + movie { + id + title + genre + imageUrl + releaseYear + rating + description + } + } + } +} + +# Get user by ID +query GetUserById($id: String!) @auth(level: USER) { + user(id: $id) { + id + username + reviews: reviews_on_user { + id + rating + reviewDate + reviewText + movie { + id + title + } + } + watched: watchedMovies_on_user { + movie { + id + title + genre + imageUrl + releaseYear + rating + description + tags + metadata: movieMetadatas_on_movie { + director + } + } + } + favoriteMovies: favoriteMovies_on_user { + movie { + id + title + genre + imageUrl + releaseYear + rating + description + tags + metadata: movieMetadatas_on_movie { + director + } + } + } + favoriteActors: favoriteActors_on_user { + actor { + id + name + imageUrl + } + } + } +} + +# Check if a movie is watched by user +query GetIfWatched($id: String!, $movieId: UUID!) @auth(level: USER) { + watchedMovie(key: { userId: $id, movieId: $movieId }) { + movieId + } +} + +# Check if a movie is favorited by user +query GetIfFavoritedMovie($id: String!, $movieId: UUID!) @auth(level: USER) { + favoriteMovie(key: { userId: $id, movieId: $movieId }) { + movieId + } +} + +# Check if an actor is favorited by user +query GetIfFavoritedActor($id: String!, $actorId: UUID!) @auth(level: USER) { + favoriteActor(key: { userId: $id, actorId: $actorId }) { + actorId + } +} + +# Fuzzy search for movies, actors, and reviews +query fuzzySearch( + $input: String + $minYear: Int! + $maxYear: Int! + $minRating: Float! + $maxRating: Float! + $genre: String! +) @auth(level: PUBLIC) { + moviesMatchingTitle: movies( + where: { + _and: [ + { releaseYear: { ge: $minYear } } + { releaseYear: { le: $maxYear } } + { rating: { ge: $minRating } } + { rating: { le: $maxRating } } + { genre: { contains: $genre } } + { title: { contains: $input } } + ] + } + ) { + id + title + genre + rating + imageUrl + } + moviesMatchingDescription: movies( + where: { + _and: [ + { releaseYear: { ge: $minYear } } + { releaseYear: { le: $maxYear } } + { rating: { ge: $minRating } } + { rating: { le: $maxRating } } + { genre: { contains: $genre } } + { description: { contains: $input } } + ] + } + ) { + id + title + genre + rating + imageUrl + } + actorsMatchingName: actors(where: { name: { contains: $input } }) { + id + name + imageUrl + } + reviewsMatchingText: reviews(where: { reviewText: { contains: $input } }) { + id + rating + reviewText + reviewDate + movie { + id + title + } + user { + id + username + } + } +} + +# Search movie descriptions using L2 similarity with Vertex AI +query searchMovieDescriptionUsingL2Similarity($query: String!) +@auth(level: PUBLIC) { + movies_descriptionEmbedding_similarity( + compare_embed: { model: "textembedding-gecko@001", text: $query } + method: L2 + within: 2 + where: { description: { ne: "" } } + limit: 5 + ) { + id + title + description + tags + rating + imageUrl + } +} diff --git a/dataconnect/dataconnect/dataconnect.yaml b/dataconnect/dataconnect/dataconnect.yaml new file mode 100644 index 000000000..9dd8a336b --- /dev/null +++ b/dataconnect/dataconnect/dataconnect.yaml @@ -0,0 +1,10 @@ +specVersion: "v1alpha" +serviceId: "dataconnect" +schema: + source: "./schema" + datasource: + postgresql: + database: "postgres" + cloudSql: + instanceId: "your-instanceId" +connectorDirs: ["./connector"] diff --git a/dataconnect/dataconnect/schema/schema.gql b/dataconnect/dataconnect/schema/schema.gql new file mode 100644 index 000000000..01260143a --- /dev/null +++ b/dataconnect/dataconnect/schema/schema.gql @@ -0,0 +1,104 @@ +# Movies +type Movie + @table(name: "Movies", singular: "movie", plural: "movies", key: ["id"]) { + id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()") + title: String! + imageUrl: String! @col(name: "image_url") + releaseYear: Int @col(name: "release_year") + genre: String + rating: Float @col(name: "rating") + description: String @col(name: "description") + tags: [String] @col(name: "tags") + # Vectors + descriptionEmbedding: Vector @col(size:768) # vector +} + +# Movie Metadata +# Movie - MovieMetadata is a one-to-one relationship +type MovieMetadata + @table( + name: "MovieMetadata" + ) { + # @ref creates a field in the current table (MovieMetadata) that holds the primary key of the referenced type + # In this case, @ref(fields: "id") is implied + movie: Movie! @ref + # movieId: UUID <- this is created by the above @ref + director: String @col(name: "director") + # TODO: optional other fields +} + +# Actors +# Suppose an actor can participate in multiple movies and movies can have multiple actors +# Movie - Actors (or vice versa) is a many to many relationship +type Actor @table(name: "Actors", singular: "actor", plural: "actors") { + id: UUID! @col(name: "actor_id") @default(expr: "uuidV4()") + imageUrl: String! @col(name: "image_url") + name: String! @col(name: "name", dataType: "varchar(30)") + biography: String @col(name: "biography") +} + +# Join table for many-to-many relationship for movies and actors +# The 'key' param signifies the primary key(s) of this table +# In this case, the keys are [movieId, actorId], the generated fields of the reference types [movie, actor] +type MovieActor @table(key: ["movie", "actor"]) { + # @ref creates a field in the current table (MovieActor) that holds the primary key of the referenced type + # In this case, @ref(fields: "id") is implied + movie: Movie! @ref + # movieId: UUID! <- this is created by the above @ref, see: implicit.gql + + actor: Actor! @ref + # actorId: UUID! <- this is created by the above @ref, see: implicit.gql + + role: String! @col(name: "role") # "main" or "supporting" + # TODO: optional other fields +} + +# Users +# Suppose a user can leave reviews for movies +# user:reviews is a one to many relationship, movie:reviews is a one to many relationship, movie:user is a many to many relationship +type User + @table(name: "Users", singular: "user", plural: "users", key: ["id"]) { + # id: UUID! @col(name: "user_id") @default(expr: "uuidV4()") + id: String! @col(name: "user_auth") + username: String! @col(name: "username", dataType: "varchar(50)") + # The following are generated from the @ref in the Review table + # reviews_on_user + # movies_via_Review +} + +# Join table for many-to-many relationship for users and favorite movies +type FavoriteMovie + @table(name: "FavoriteMovies", key: ["user", "movie"]) { + user: User! @ref + movie: Movie! @ref +} + +# Join table for many-to-many relationship for users and favorite actors +type FavoriteActor + @table(name: "FavoriteActors", key: ["user", "actor"]) { + user: User! @ref + actor: Actor! @ref +} + +# Join table for many-to-many relationship for users and watched movies +type WatchedMovie + @table(name: "WatchedMovies", key: ["user", "movie"]) { + user: User! @ref + movie: Movie! @ref +} + +# Reviews +type Review @table(name: "Reviews", key: ["movie", "user"]) { + id: UUID! @col(name: "review_id") @default(expr: "uuidV4()") + user: User! @ref + movie: Movie! @ref + rating: Int + reviewText: String + reviewDate: Date! @default(expr: "request.time") +} + +# Self Joins +extend type Movie { + sequelTo: Movie +} + diff --git a/dataconnect/firebase.json b/dataconnect/firebase.json new file mode 100644 index 000000000..d333fb6ea --- /dev/null +++ b/dataconnect/firebase.json @@ -0,0 +1,32 @@ +{ + "dataconnect": { + "source": "./dataconnect", + "location": "us-central1" + }, + "emulators": { + "dataconnect": { + "port": 9399 + }, + "ui": { + "enabled": false + }, + "singleProjectMode": true, + "auth": { + "port": 9099 + }, + "hosting": { + "port": 5000 + } + }, + "hosting": { + "source": "movie", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ], + "frameworksBackend": { + "region": "us-central1" + } + } +} diff --git a/dataconnect/movie/.env.local b/dataconnect/movie/.env.local new file mode 100644 index 000000000..d080f30d3 --- /dev/null +++ b/dataconnect/movie/.env.local @@ -0,0 +1,6 @@ +NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key +NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-auth-domain +NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id +NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-storage-bucket +NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-messaging-sender-id +NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id \ No newline at end of file diff --git a/dataconnect/movie/app/actor/[id]/page.tsx b/dataconnect/movie/app/actor/[id]/page.tsx new file mode 100644 index 000000000..d057ce327 --- /dev/null +++ b/dataconnect/movie/app/actor/[id]/page.tsx @@ -0,0 +1,138 @@ +'use client'; +import { useEffect, useState } from 'react'; +import { useParams, useRouter } from 'next/navigation'; +import Link from 'next/link'; +import { MdFavorite, MdFavoriteBorder } from 'react-icons/md'; +import { getActorById, GetActorByIdResponse, GetActorByIdVariables, addFavoritedActor, deleteFavoriteActor, getIfFavoritedActor } from '../../../lib/dataconnect-sdk'; +import { getAuth, onAuthStateChanged, User } from 'firebase/auth'; + +const Page = () => { + const router = useRouter(); + const { id } = useParams() as { id: string }; + const [actor, setActor] = useState(null); + const [loading, setLoading] = useState(true); + const [authUser, setAuthUser] = useState(null); + const [isFavorited, setIsFavorited] = useState(false); + + useEffect(() => { + const auth = getAuth(); + const unsubscribe = onAuthStateChanged(auth, (user) => { + if (user) { + setAuthUser(user); + checkIfFavorited(user.uid); + } + }); + + return () => unsubscribe(); + }, [id]); + + useEffect(() => { + if (id) { + const fetchActor = async () => { + try { + const response = await getActorById({ id }); + setActor(response.data.actor); + } catch (error) { + console.error('Error fetching actor:', error); + } finally { + setLoading(false); + } + }; + + fetchActor(); + } + }, [id]); + + const checkIfFavorited = async (userId: string) => { + try { + const response = await getIfFavoritedActor({ id: userId, actorId: id }); + setIsFavorited(!!response.data.favoriteActor); + } catch (error) { + console.error('Error checking if favorited:', error); + } + }; + + const handleFavoriteToggle = async () => { + if (!authUser) return; + try { + if (isFavorited) { + await deleteFavoriteActor({ userId: authUser.uid, actorId: id }); + } else { + await addFavoritedActor({ actorId: id }); + } + setIsFavorited(!isFavorited); + } catch (error) { + console.error('Error updating favorite status:', error); + } + }; + + if (loading) return

Loading...

; + if (!actor) return

Actor not found.

; + + return ( +
+
+ {actor.name} +
+

{actor.name}

+
+ +
+

{actor.biography}

+
+
+ +
+

Main Roles

+
+ {actor.mainActors.map((movie) => ( + +
+ {movie.title} +
+

{movie.title}

+

{movie.genre}

+
+ {movie.tags.map((tag, index) => ( + {tag} + ))} +
+
+
+ + ))} +
+
+ +
+

Supporting Roles

+
+ {actor.supportingActors.map((movie) => ( + +
+ {movie.title} +
+

{movie.title}

+

{movie.genre}

+
+ {movie.tags.map((tag, index) => ( + {tag} + ))} +
+
+
+ + ))} +
+
+
+ ); +}; + +export default Page; diff --git a/dataconnect/movie/app/advancedsearch/page.tsx b/dataconnect/movie/app/advancedsearch/page.tsx new file mode 100644 index 000000000..042010999 --- /dev/null +++ b/dataconnect/movie/app/advancedsearch/page.tsx @@ -0,0 +1,219 @@ +'use client'; +import { useState } from 'react'; +import Link from 'next/link'; +import { FaSearch } from 'react-icons/fa'; +import { MdStar } from 'react-icons/md'; +import { fuzzySearch } from '../../lib/dataconnect-sdk'; + +const genres = ['', 'action', 'crime', 'drama', 'sci-fi', 'thriller', 'adventure']; + +const Page = () => { + const [searchQuery, setSearchQuery] = useState(''); + const [releaseYearRange, setReleaseYearRange] = useState({ min: 1900, max: 2030 }); + const [genre, setGenre] = useState(''); + const [ratingRange, setRatingRange] = useState({ min: 1, max: 10 }); + const [results, setResults] = useState({ + moviesMatchingTitle: [], + moviesMatchingDescription: [], + actors: [], + reviews: [], + }); + + const handleSearch = async (e: React.FormEvent) => { + e.preventDefault(); + try { + const response = await fuzzySearch({ + input: searchQuery, + minYear: releaseYearRange.min, + maxYear: releaseYearRange.max, + minRating: ratingRange.min, + maxRating: ratingRange.max, + genre, + }); + setResults({ + moviesMatchingTitle: response.data.moviesMatchingTitle, + moviesMatchingDescription: response.data.moviesMatchingDescription, + actors: response.data.actorsMatchingName, + reviews: response.data.reviewsMatchingText, + }); + } catch (error) { + console.error('Error fetching search results:', error); + } + }; + + return ( +
+

Advanced Search

+
+
+ + setSearchQuery(e.target.value)} + /> + +
+
+
+ + setReleaseYearRange({ ...releaseYearRange, min: Number(e.target.value) })} + min="1900" + max="2030" + /> + + setReleaseYearRange({ ...releaseYearRange, max: Number(e.target.value) })} + min="1900" + max="2030" + /> +
+
+ + +
+
+ + setRatingRange({ ...ratingRange, min: Number(e.target.value) })} + min="1" + max="10" + /> + + setRatingRange({ ...ratingRange, max: Number(e.target.value) })} + min="1" + max="10" + /> +
+
+
+
+

Results

+
+

Movies Matching Title

+
+ {results.moviesMatchingTitle?.map((movie) => ( + +
+ {movie.title} +
+

{movie.title}

+
+ + {movie.rating} +
+
+ {movie?.tags?.map((tag, index) => ( + {tag} + ))} +
+
+
+ + ))} +
+
+
+

Movies Matching Description

+
+ {results.moviesMatchingDescription?.map((movie) => ( + +
+ {movie.title} +
+

{movie.title}

+
+ + {movie.rating} +
+
+ {movie?.tags?.map((tag, index) => ( + {tag} + ))} +
+
+
+ + ))} +
+
+
+

Actors

+
+ {results.actors?.map((actor) => ( + +
+ {actor.name} +
+

{actor.name}

+
+
+ + ))} +
+
+
+

Reviews

+
+ {results?.reviews?.map((review) => ( +
+

{review?.user?.username}

+

{review.reviewDate}

+

{review.reviewText}

+
+ + {review.rating} +
+ + {review?.movie?.title} + +
+ ))} +
+
+
+
+ ); +}; + +export default Page; diff --git a/dataconnect/movie/app/genre/[genre]/page.tsx b/dataconnect/movie/app/genre/[genre]/page.tsx new file mode 100644 index 000000000..48ab5697e --- /dev/null +++ b/dataconnect/movie/app/genre/[genre]/page.tsx @@ -0,0 +1,70 @@ +'use client'; +import { useEffect, useState } from 'react'; +import { useParams } from 'next/navigation'; +import MovieCard from '../../../components/moviecard'; +import { ListMoviesByGenreResponse, ListMoviesByGenreVariables, listMoviesByGenre } from '../../../lib/dataconnect-sdk'; + +const Page = () => { + const { genre } = useParams() as { genre: string }; + const [mostPopular, setMostPopular] = useState([]); + const [mostRecent, setMostRecent] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchMovies = async () => { + try { + const response = await listMoviesByGenre({ genre }); + setMostPopular(response.data.mostPopular); + setMostRecent(response.data.mostRecent); + } catch (error) { + console.error('Error fetching movies:', error); + } finally { + setLoading(false); + } + }; + + fetchMovies(); + }, [genre]); + + if (loading) return

Loading...

; + + return ( +
+

{genre} Movies

+ +
+

Most Popular

+
+ {mostPopular.map((movie) => ( + + ))} +
+
+ +
+

Most Recent

+
+ {mostRecent.map((movie) => ( + + ))} +
+
+
+ ); +}; + +export default Page; diff --git a/dataconnect/movie/app/layout.tsx b/dataconnect/movie/app/layout.tsx new file mode 100644 index 000000000..1d3a8e1b2 --- /dev/null +++ b/dataconnect/movie/app/layout.tsx @@ -0,0 +1,19 @@ +"use client"; +import Navbar from "../components/navbar"; +import "../styles.css"; +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + +
+ {children} +
+ + + ); +} diff --git a/dataconnect/movie/app/movie/[id]/page.tsx b/dataconnect/movie/app/movie/[id]/page.tsx new file mode 100644 index 000000000..c15c4e488 --- /dev/null +++ b/dataconnect/movie/app/movie/[id]/page.tsx @@ -0,0 +1,280 @@ +'use client'; +import { useEffect, useState } from 'react'; +import { useParams, useRouter } from 'next/navigation'; +import Link from 'next/link'; +import { MdFavorite, MdFavoriteBorder, MdCheck, MdCheckBoxOutlineBlank, MdStar } from 'react-icons/md'; +import { + getMovieById, + GetMovieByIdResponse, + addFavoritedMovie, + deleteFavoritedMovie, + addWatchedMovie, + deleteWatchedMovie, + getIfWatched, + getIfFavoritedMovie, + addReview, + deleteReview, +} from '../../../lib/dataconnect-sdk'; +import { getAuth, onAuthStateChanged, User } from 'firebase/auth'; + +const Page = () => { + const router = useRouter(); + const { id } = useParams() as { id: string }; + const [movie, setMovie] = useState(null); + const [loading, setLoading] = useState(true); + const [authUser, setAuthUser] = useState(null); + const [isFavorited, setIsFavorited] = useState(false); + const [isWatched, setIsWatched] = useState(false); + const [reviewText, setReviewText] = useState(''); + const [userReview, setUserReview] = useState(null); + const [rating, setRating] = useState(0); + + useEffect(() => { + const auth = getAuth(); + const unsubscribe = onAuthStateChanged(auth, (user) => { + if (user) { + setAuthUser(user); + checkIfFavorited(user.uid); + checkIfWatched(user.uid); + } + }); + + return () => unsubscribe(); + }, [id]); + + useEffect(() => { + if (id) { + const fetchMovie = async () => { + try { + const response = await getMovieById({ id }); + setMovie(response.data.movie); + const userReview = response.data.movie.reviews.find(review => review.user.id === authUser?.uid); + setUserReview(userReview || null); + } catch (error) { + console.error('Error fetching movie:', error); + } finally { + setLoading(false); + } + }; + + fetchMovie(); + } + }, [id, authUser, movie]); + + const checkIfFavorited = async (userId: string) => { + try { + const response = await getIfFavoritedMovie({ id: userId, movieId: id }); + setIsFavorited(!!response.data.favoriteMovie); + } catch (error) { + console.error('Error checking if favorited:', error); + } + }; + + const checkIfWatched = async (userId: string) => { + try { + const response = await getIfWatched({ id: userId, movieId: id }); + setIsWatched(!!response.data.watchedMovie); + } catch (error) { + console.error('Error checking if watched:', error); + } + }; + + const handleFavoriteToggle = async (e: React.MouseEvent) => { + e.stopPropagation(); + e.preventDefault(); + if (!authUser) return; + try { + if (isFavorited) { + await deleteFavoritedMovie({ userId: authUser.uid, movieId: id }); + } else { + await addFavoritedMovie({ movieId: id }); + } + setIsFavorited(!isFavorited); + } catch (error) { + console.error('Error updating favorite status:', error); + } + }; + + const handleWatchedToggle = async (e: React.MouseEvent) => { + e.stopPropagation(); + e.preventDefault(); + if (!authUser) return; + try { + if (isWatched) { + await deleteWatchedMovie({ userId: authUser.uid, movieId: id }); + } else { + await addWatchedMovie({ movieId: id }); + } + setIsWatched(!isWatched); + } catch (error) { + console.error('Error updating watched status:', error); + } + }; + + const handleReviewSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!authUser) return; + try { + const response = await addReview({ movieId: id, rating, reviewText }); + setReviewText(''); + setRating(0); + const updatedMovie = await getMovieById({ id }); + setMovie(updatedMovie.data.movie); + } catch (error) { + console.error('Error adding review:', error); + } + }; + + const handleReviewDelete = async (e: React.MouseEvent) => { + e.stopPropagation(); + e.preventDefault(); + if (!authUser || !userReview) return; + try { + await deleteReview({ movieId: id, userId: authUser.uid }); + setUserReview(null); + const updatedMovie = await getMovieById({ id }); + setMovie(updatedMovie.data.movie); + } catch (error) { + console.error('Error deleting review:', error); + } + }; + + if (loading) return

Loading...

; + if (!movie) return

Movie not found.

; + + return ( +
+
+ {movie.title} +
+

{movie.title}

+
+ + {movie.rating} +
+

{movie.description}

+
+

Genre: {movie.genre}

+

Release Year: {movie.releaseYear}

+

Director: {movie.metadata[0]?.director}

+

Tags: {movie.tags.join(', ')}

+
+
+ + +
+
+
+ +
+

Main Actors

+
+ {movie.mainActors.map((actor) => ( + +
+ {actor.name} +
+

{actor.name}

+
+
+ + ))} +
+
+ +
+

Supporting Actors

+
+ {movie.supportingActors.map((actor) => ( + +
+ {actor.name} +
+

{actor.name}

+
+
+ + ))} +
+
+ + {movie.sequelTo && ( +
+

Sequel

+ +
+ {movie.sequelTo.title} + {movie.sequelTo.title} +
+ +
+ )} + +
+

User Reviews

+ {!userReview ? ( +
+

Leave a Review

+