From c20034c5998d66cfdfb7eb039f20668456a3c433 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 13 Nov 2024 10:53:39 -0800 Subject: [PATCH 01/17] Created movie detail page --- .../.dataconnect/schema/main/implicit.gql | 40 + .../.dataconnect/schema/main/input.gql | 1080 +++++++++ .../.dataconnect/schema/main/mutation.gql | 766 +++++++ .../.dataconnect/schema/main/query.gql | 293 +++ .../.dataconnect/schema/main/relation.gql | 318 +++ .../.dataconnect/schema/prelude.gql | 2026 +++++++++++++++++ .../connector/connector.yaml | 0 .../{ => dataconnect}/connector/mutations.gql | 0 .../{ => dataconnect}/connector/queries.gql | 0 .../{ => dataconnect}/dataconnect.yaml | 4 +- .../movies_connector/add_favorited_movie.dart | 192 ++ .../lib/movies_connector/add_review.dart | 240 ++ .../delete_favorited_movie.dart | 194 ++ .../lib/movies_connector/delete_review.dart | 194 ++ .../lib/movies_connector/get_actor_by_id.dart | 573 +++++ .../movies_connector/get_current_user.dart | 763 +++++++ .../get_if_favorited_movie.dart | 171 ++ .../lib/movies_connector/get_movie_by_id.dart | 912 ++++++++ .../lib/movies_connector/list_movies.dart | 403 ++++ .../lib/movies_connector/movies.dart | 129 ++ .../lib/movies_connector/search_all.dart | 1021 +++++++++ .../lib/movies_connector/update_review.dart | 242 ++ .../lib/movies_connector/upsert_user.dart | 169 ++ dataconnect/dataconnect/moviedata_insert.gql | 687 ++++++ .../{ => dataconnect}/schema/schema.gql | 0 dataconnect/firebase.json | 45 +- dataconnect/ios/Flutter/Debug.xcconfig | 1 + dataconnect/ios/Flutter/Release.xcconfig | 1 + dataconnect/lib/firebase_options.dart | 63 +- dataconnect/lib/main.dart | 118 +- dataconnect/lib/movie_detail.dart | 241 ++ .../macos/Flutter/Flutter-Debug.xcconfig | 1 + .../macos/Flutter/Flutter-Release.xcconfig | 1 + .../macos/Runner.xcodeproj/project.pbxproj | 6 +- dataconnect/pubspec.lock | 18 +- dataconnect/pubspec.yaml | 2 + 36 files changed, 10827 insertions(+), 87 deletions(-) create mode 100644 dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql create mode 100644 dataconnect/dataconnect/.dataconnect/schema/main/input.gql create mode 100644 dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql create mode 100644 dataconnect/dataconnect/.dataconnect/schema/main/query.gql create mode 100644 dataconnect/dataconnect/.dataconnect/schema/main/relation.gql create mode 100644 dataconnect/dataconnect/.dataconnect/schema/prelude.gql rename dataconnect/{ => dataconnect}/connector/connector.yaml (100%) rename dataconnect/{ => dataconnect}/connector/mutations.gql (100%) rename dataconnect/{ => dataconnect}/connector/queries.gql (100%) rename dataconnect/{ => dataconnect}/dataconnect.yaml (77%) create mode 100644 dataconnect/dataconnect/lib/movies_connector/add_favorited_movie.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/add_review.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/delete_favorited_movie.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/delete_review.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/get_actor_by_id.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/get_current_user.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/get_if_favorited_movie.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/get_movie_by_id.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/list_movies.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/movies.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/search_all.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/update_review.dart create mode 100644 dataconnect/dataconnect/lib/movies_connector/upsert_user.dart create mode 100644 dataconnect/dataconnect/moviedata_insert.gql rename dataconnect/{ => dataconnect}/schema/schema.gql (100%) create mode 100644 dataconnect/lib/movie_detail.dart diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql b/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql new file mode 100644 index 00000000..c7944ef7 --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql @@ -0,0 +1,40 @@ +extend type FavoriteMovie { + """ + ✨ Implicit foreign key field based on `FavoriteMovie`.`user`. It must match the value of `User`.`id`. See `@ref` for how to customize it. + """ + userId: String! @fdc_generated(from: "FavoriteMovie.user", purpose: IMPLICIT_REF_FIELD) + """ + ✨ Implicit foreign key field based on `FavoriteMovie`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it. + """ + movieId: UUID! @fdc_generated(from: "FavoriteMovie.movie", purpose: IMPLICIT_REF_FIELD) +} +extend type MovieActor { + """ + ✨ Implicit foreign key field based on `MovieActor`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it. + """ + movieId: UUID! @fdc_generated(from: "MovieActor.movie", purpose: IMPLICIT_REF_FIELD) + """ + ✨ Implicit foreign key field based on `MovieActor`.`actor`. It must match the value of `Actor`.`id`. See `@ref` for how to customize it. + """ + actorId: UUID! @fdc_generated(from: "MovieActor.actor", purpose: IMPLICIT_REF_FIELD) +} +extend type MovieMetadata { + """ + ✨ Implicit primary key field. It's a UUID column default to a generated new value. See `@table` for how to customize it. + """ + id: UUID! @default(expr: "uuidV4()") @fdc_generated(from: "MovieMetadata", purpose: IMPLICIT_KEY_FIELD) + """ + ✨ Implicit foreign key field based on `MovieMetadata`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it. + """ + movieId: UUID! @fdc_generated(from: "MovieMetadata.movie", purpose: IMPLICIT_REF_FIELD) +} +extend type Review { + """ + ✨ Implicit foreign key field based on `Review`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it. + """ + movieId: UUID! @fdc_generated(from: "Review.movie", purpose: IMPLICIT_REF_FIELD) + """ + ✨ Implicit foreign key field based on `Review`.`user`. It must match the value of `User`.`id`. See `@ref` for how to customize it. + """ + userId: String! @fdc_generated(from: "Review.user", purpose: IMPLICIT_REF_FIELD) +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/input.gql b/dataconnect/dataconnect/.dataconnect/schema/main/input.gql new file mode 100644 index 00000000..c904887b --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/main/input.gql @@ -0,0 +1,1080 @@ +""" +✨ `Actor_KeyOutput` returns the primary key fields of table type `Actor`. + +It has the same format as `Actor_Key`, but is only used as mutation return value. +""" +scalar Actor_KeyOutput +""" +✨ `FavoriteMovie_KeyOutput` returns the primary key fields of table type `FavoriteMovie`. + +It has the same format as `FavoriteMovie_Key`, but is only used as mutation return value. +""" +scalar FavoriteMovie_KeyOutput +""" +✨ `Movie_KeyOutput` returns the primary key fields of table type `Movie`. + +It has the same format as `Movie_Key`, but is only used as mutation return value. +""" +scalar Movie_KeyOutput +""" +✨ `MovieActor_KeyOutput` returns the primary key fields of table type `MovieActor`. + +It has the same format as `MovieActor_Key`, but is only used as mutation return value. +""" +scalar MovieActor_KeyOutput +""" +✨ `MovieMetadata_KeyOutput` returns the primary key fields of table type `MovieMetadata`. + +It has the same format as `MovieMetadata_Key`, but is only used as mutation return value. +""" +scalar MovieMetadata_KeyOutput +""" +✨ `Review_KeyOutput` returns the primary key fields of table type `Review`. + +It has the same format as `Review_Key`, but is only used as mutation return value. +""" +scalar Review_KeyOutput +""" +✨ `User_KeyOutput` returns the primary key fields of table type `User`. + +It has the same format as `User_Key`, but is only used as mutation return value. +""" +scalar User_KeyOutput +""" +✨ Generated data input type for table 'Actor'. It includes all necessary fields for creating or upserting rows into table. +""" +input Actor_Data { + """ + ✨ Generated from Field `Actor`.`id` of type `UUID!` + """ + id: UUID + """ + ✨ `_expr` server value variant of `id` (✨ Generated from Field `Actor`.`id` of type `UUID!`) + """ + id_expr: UUID_Expr + """ + ✨ Generated from Field `Actor`.`imageUrl` of type `String!` + """ + imageUrl: String + """ + ✨ `_expr` server value variant of `imageUrl` (✨ Generated from Field `Actor`.`imageUrl` of type `String!`) + """ + imageUrl_expr: String_Expr + """ + ✨ Generated from Field `Actor`.`name` of type `String!` + """ + name: String + """ + ✨ `_expr` server value variant of `name` (✨ Generated from Field `Actor`.`name` of type `String!`) + """ + name_expr: String_Expr +} +""" +✨ Generated filter input type for table 'Actor'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. +""" +input Actor_Filter { + """ + Apply multiple filter conditions using `AND` logic. + """ + _and: [Actor_Filter!] + """ + Negate the result of the provided filter condition. + """ + _not: Actor_Filter + """ + Apply multiple filter conditions using `OR` logic. + """ + _or: [Actor_Filter!] + """ + ✨ Generated from Field `Actor`.`id` of type `UUID!` + """ + id: UUID_Filter + """ + ✨ Generated from Field `Actor`.`imageUrl` of type `String!` + """ + imageUrl: String_Filter + """ + ✨ Generated from Field `Actor`.`name` of type `String!` + """ + name: String_Filter + """ + ✨ Generated from Field `Actor`.`movieActors_on_actor` of type `[MovieActor!]!` + """ + movieActors_on_actor: MovieActor_ListFilter + """ + ✨ Generated from Field `Actor`.`movies_via_MovieActor` of type `[Movie!]!` + """ + movies_via_MovieActor: Movie_ListFilter +} +""" +✨ Generated first-row input type for table 'Actor'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. +""" +input Actor_FirstRow { + """ + Order the result by the specified fields. + """ + orderBy: [Actor_Order!] + """ + Filters rows based on the specified conditions. + """ + where: Actor_Filter +} +""" +✨ Generated key input type for table 'Actor'. It represents the primary key fields used to uniquely identify a row in the table. +""" +input Actor_Key { + """ + ✨ Generated from Field `Actor`.`id` of type `UUID!` + """ + id: UUID + """ + ✨ `_expr` server value variant of `id` (✨ Generated from Field `Actor`.`id` of type `UUID!`) + """ + id_expr: UUID_Expr +} +""" +✨ Generated list filter input type for table 'Actor'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. +""" +input Actor_ListFilter { + """ + The desired number of objects that match the condition (defaults to at least one). + """ + count: Int_Filter = {gt:0} + """ + Condition of the related objects to filter for. + """ + exist: Actor_Filter +} +""" +✨ Generated order input type for table 'Actor'. This input defines the sorting order of rows in query results based on one or more fields. +""" +input Actor_Order { + """ + ✨ Generated from Field `Actor`.`id` of type `UUID!` + """ + id: OrderDirection + """ + ✨ Generated from Field `Actor`.`imageUrl` of type `String!` + """ + imageUrl: OrderDirection + """ + ✨ Generated from Field `Actor`.`name` of type `String!` + """ + name: OrderDirection +} +""" +✨ Generated data input type for table 'FavoriteMovie'. It includes all necessary fields for creating or upserting rows into table. +""" +input FavoriteMovie_Data { + """ + ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!` + """ + userId: String + """ + ✨ `_expr` server value variant of `userId` (✨ Generated from Field `FavoriteMovie`.`userId` of type `String!`) + """ + userId_expr: String_Expr + """ + ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!` + """ + movieId: UUID + """ + ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!`) + """ + movieId_expr: UUID_Expr + """ + ✨ Generated from Field `FavoriteMovie`.`movie` of type `Movie!` + """ + movie: Movie_Key + """ + ✨ Generated from Field `FavoriteMovie`.`user` of type `User!` + """ + user: User_Key +} +""" +✨ Generated filter input type for table 'FavoriteMovie'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. +""" +input FavoriteMovie_Filter { + """ + Apply multiple filter conditions using `AND` logic. + """ + _and: [FavoriteMovie_Filter!] + """ + Negate the result of the provided filter condition. + """ + _not: FavoriteMovie_Filter + """ + Apply multiple filter conditions using `OR` logic. + """ + _or: [FavoriteMovie_Filter!] + """ + ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!` + """ + userId: String_Filter + """ + ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!` + """ + movieId: UUID_Filter + """ + ✨ Generated from Field `FavoriteMovie`.`movie` of type `Movie!` + """ + movie: Movie_Filter + """ + ✨ Generated from Field `FavoriteMovie`.`user` of type `User!` + """ + user: User_Filter +} +""" +✨ Generated first-row input type for table 'FavoriteMovie'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. +""" +input FavoriteMovie_FirstRow { + """ + Order the result by the specified fields. + """ + orderBy: [FavoriteMovie_Order!] + """ + Filters rows based on the specified conditions. + """ + where: FavoriteMovie_Filter +} +""" +✨ Generated key input type for table 'FavoriteMovie'. It represents the primary key fields used to uniquely identify a row in the table. +""" +input FavoriteMovie_Key { + """ + ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!` + """ + userId: String + """ + ✨ `_expr` server value variant of `userId` (✨ Generated from Field `FavoriteMovie`.`userId` of type `String!`) + """ + userId_expr: String_Expr + """ + ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!` + """ + movieId: UUID + """ + ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!`) + """ + movieId_expr: UUID_Expr +} +""" +✨ Generated list filter input type for table 'FavoriteMovie'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. +""" +input FavoriteMovie_ListFilter { + """ + The desired number of objects that match the condition (defaults to at least one). + """ + count: Int_Filter = {gt:0} + """ + Condition of the related objects to filter for. + """ + exist: FavoriteMovie_Filter +} +""" +✨ Generated order input type for table 'FavoriteMovie'. This input defines the sorting order of rows in query results based on one or more fields. +""" +input FavoriteMovie_Order { + """ + ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!` + """ + userId: OrderDirection + """ + ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!` + """ + movieId: OrderDirection + """ + ✨ Generated from Field `FavoriteMovie`.`movie` of type `Movie!` + """ + movie: Movie_Order + """ + ✨ Generated from Field `FavoriteMovie`.`user` of type `User!` + """ + user: User_Order +} +""" +✨ Generated data input type for table 'Movie'. It includes all necessary fields for creating or upserting rows into table. +""" +input Movie_Data { + """ + ✨ Generated from Field `Movie`.`id` of type `UUID!` + """ + id: UUID + """ + ✨ `_expr` server value variant of `id` (✨ Generated from Field `Movie`.`id` of type `UUID!`) + """ + id_expr: UUID_Expr + """ + ✨ Generated from Field `Movie`.`description` of type `String` + """ + description: String + """ + ✨ `_expr` server value variant of `description` (✨ Generated from Field `Movie`.`description` of type `String`) + """ + description_expr: String_Expr + """ + ✨ Generated from Field `Movie`.`genre` of type `String` + """ + genre: String + """ + ✨ `_expr` server value variant of `genre` (✨ Generated from Field `Movie`.`genre` of type `String`) + """ + genre_expr: String_Expr + """ + ✨ Generated from Field `Movie`.`imageUrl` of type `String!` + """ + imageUrl: String + """ + ✨ `_expr` server value variant of `imageUrl` (✨ Generated from Field `Movie`.`imageUrl` of type `String!`) + """ + imageUrl_expr: String_Expr + """ + ✨ Generated from Field `Movie`.`rating` of type `Float` + """ + rating: Float + """ + ✨ Generated from Field `Movie`.`releaseYear` of type `Int` + """ + releaseYear: Int + """ + ✨ Generated from Field `Movie`.`tags` of type `[String]` + """ + tags: [String!] + """ + ✨ Generated from Field `Movie`.`title` of type `String!` + """ + title: String + """ + ✨ `_expr` server value variant of `title` (✨ Generated from Field `Movie`.`title` of type `String!`) + """ + title_expr: String_Expr +} +""" +✨ Generated filter input type for table 'Movie'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. +""" +input Movie_Filter { + """ + Apply multiple filter conditions using `AND` logic. + """ + _and: [Movie_Filter!] + """ + Negate the result of the provided filter condition. + """ + _not: Movie_Filter + """ + Apply multiple filter conditions using `OR` logic. + """ + _or: [Movie_Filter!] + """ + ✨ Generated from Field `Movie`.`id` of type `UUID!` + """ + id: UUID_Filter + """ + ✨ Generated from Field `Movie`.`description` of type `String` + """ + description: String_Filter + """ + ✨ Generated from Field `Movie`.`genre` of type `String` + """ + genre: String_Filter + """ + ✨ Generated from Field `Movie`.`imageUrl` of type `String!` + """ + imageUrl: String_Filter + """ + ✨ Generated from Field `Movie`.`rating` of type `Float` + """ + rating: Float_Filter + """ + ✨ Generated from Field `Movie`.`releaseYear` of type `Int` + """ + releaseYear: Int_Filter + """ + ✨ Generated from Field `Movie`.`tags` of type `[String]` + """ + tags: String_ListFilter + """ + ✨ Generated from Field `Movie`.`title` of type `String!` + """ + title: String_Filter + """ + ✨ Generated from Field `Movie`.`favorite_movies_on_movie` of type `[FavoriteMovie!]!` + """ + favorite_movies_on_movie: FavoriteMovie_ListFilter + """ + ✨ Generated from Field `Movie`.`movieActors_on_movie` of type `[MovieActor!]!` + """ + movieActors_on_movie: MovieActor_ListFilter + """ + ✨ Generated from Field `Movie`.`movieMetadatas_on_movie` of type `[MovieMetadata!]!` + """ + movieMetadatas_on_movie: MovieMetadata_ListFilter + """ + ✨ Generated from Field `Movie`.`reviews_on_movie` of type `[Review!]!` + """ + reviews_on_movie: Review_ListFilter + """ + ✨ Generated from Field `Movie`.`actors_via_MovieActor` of type `[Actor!]!` + """ + actors_via_MovieActor: Actor_ListFilter + """ + ✨ Generated from Field `Movie`.`users_via_FavoriteMovie` of type `[User!]!` + """ + users_via_FavoriteMovie: User_ListFilter + """ + ✨ Generated from Field `Movie`.`users_via_Review` of type `[User!]!` + """ + users_via_Review: User_ListFilter +} +""" +✨ Generated first-row input type for table 'Movie'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. +""" +input Movie_FirstRow { + """ + Order the result by the specified fields. + """ + orderBy: [Movie_Order!] + """ + Filters rows based on the specified conditions. + """ + where: Movie_Filter +} +""" +✨ Generated key input type for table 'Movie'. It represents the primary key fields used to uniquely identify a row in the table. +""" +input Movie_Key { + """ + ✨ Generated from Field `Movie`.`id` of type `UUID!` + """ + id: UUID + """ + ✨ `_expr` server value variant of `id` (✨ Generated from Field `Movie`.`id` of type `UUID!`) + """ + id_expr: UUID_Expr +} +""" +✨ Generated list filter input type for table 'Movie'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. +""" +input Movie_ListFilter { + """ + The desired number of objects that match the condition (defaults to at least one). + """ + count: Int_Filter = {gt:0} + """ + Condition of the related objects to filter for. + """ + exist: Movie_Filter +} +""" +✨ Generated order input type for table 'Movie'. This input defines the sorting order of rows in query results based on one or more fields. +""" +input Movie_Order { + """ + ✨ Generated from Field `Movie`.`id` of type `UUID!` + """ + id: OrderDirection + """ + ✨ Generated from Field `Movie`.`description` of type `String` + """ + description: OrderDirection + """ + ✨ Generated from Field `Movie`.`genre` of type `String` + """ + genre: OrderDirection + """ + ✨ Generated from Field `Movie`.`imageUrl` of type `String!` + """ + imageUrl: OrderDirection + """ + ✨ Generated from Field `Movie`.`rating` of type `Float` + """ + rating: OrderDirection + """ + ✨ Generated from Field `Movie`.`releaseYear` of type `Int` + """ + releaseYear: OrderDirection + """ + ✨ Generated from Field `Movie`.`title` of type `String!` + """ + title: OrderDirection +} +""" +✨ Generated data input type for table 'MovieActor'. It includes all necessary fields for creating or upserting rows into table. +""" +input MovieActor_Data { + """ + ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!` + """ + movieId: UUID + """ + ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `MovieActor`.`movieId` of type `UUID!`) + """ + movieId_expr: UUID_Expr + """ + ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!` + """ + actorId: UUID + """ + ✨ `_expr` server value variant of `actorId` (✨ Generated from Field `MovieActor`.`actorId` of type `UUID!`) + """ + actorId_expr: UUID_Expr + """ + ✨ Generated from Field `MovieActor`.`actor` of type `Actor!` + """ + actor: Actor_Key + """ + ✨ Generated from Field `MovieActor`.`movie` of type `Movie!` + """ + movie: Movie_Key + """ + ✨ Generated from Field `MovieActor`.`role` of type `String!` + """ + role: String + """ + ✨ `_expr` server value variant of `role` (✨ Generated from Field `MovieActor`.`role` of type `String!`) + """ + role_expr: String_Expr +} +""" +✨ Generated filter input type for table 'MovieActor'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. +""" +input MovieActor_Filter { + """ + Apply multiple filter conditions using `AND` logic. + """ + _and: [MovieActor_Filter!] + """ + Negate the result of the provided filter condition. + """ + _not: MovieActor_Filter + """ + Apply multiple filter conditions using `OR` logic. + """ + _or: [MovieActor_Filter!] + """ + ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!` + """ + movieId: UUID_Filter + """ + ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!` + """ + actorId: UUID_Filter + """ + ✨ Generated from Field `MovieActor`.`actor` of type `Actor!` + """ + actor: Actor_Filter + """ + ✨ Generated from Field `MovieActor`.`movie` of type `Movie!` + """ + movie: Movie_Filter + """ + ✨ Generated from Field `MovieActor`.`role` of type `String!` + """ + role: String_Filter +} +""" +✨ Generated first-row input type for table 'MovieActor'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. +""" +input MovieActor_FirstRow { + """ + Order the result by the specified fields. + """ + orderBy: [MovieActor_Order!] + """ + Filters rows based on the specified conditions. + """ + where: MovieActor_Filter +} +""" +✨ Generated key input type for table 'MovieActor'. It represents the primary key fields used to uniquely identify a row in the table. +""" +input MovieActor_Key { + """ + ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!` + """ + movieId: UUID + """ + ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `MovieActor`.`movieId` of type `UUID!`) + """ + movieId_expr: UUID_Expr + """ + ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!` + """ + actorId: UUID + """ + ✨ `_expr` server value variant of `actorId` (✨ Generated from Field `MovieActor`.`actorId` of type `UUID!`) + """ + actorId_expr: UUID_Expr +} +""" +✨ Generated list filter input type for table 'MovieActor'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. +""" +input MovieActor_ListFilter { + """ + The desired number of objects that match the condition (defaults to at least one). + """ + count: Int_Filter = {gt:0} + """ + Condition of the related objects to filter for. + """ + exist: MovieActor_Filter +} +""" +✨ Generated order input type for table 'MovieActor'. This input defines the sorting order of rows in query results based on one or more fields. +""" +input MovieActor_Order { + """ + ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!` + """ + movieId: OrderDirection + """ + ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!` + """ + actorId: OrderDirection + """ + ✨ Generated from Field `MovieActor`.`actor` of type `Actor!` + """ + actor: Actor_Order + """ + ✨ Generated from Field `MovieActor`.`movie` of type `Movie!` + """ + movie: Movie_Order + """ + ✨ Generated from Field `MovieActor`.`role` of type `String!` + """ + role: OrderDirection +} +""" +✨ Generated data input type for table 'MovieMetadata'. It includes all necessary fields for creating or upserting rows into table. +""" +input MovieMetadata_Data { + """ + ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!` + """ + id: UUID + """ + ✨ `_expr` server value variant of `id` (✨ Generated from Field `MovieMetadata`.`id` of type `UUID!`) + """ + id_expr: UUID_Expr + """ + ✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!` + """ + movieId: UUID + """ + ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!`) + """ + movieId_expr: UUID_Expr + """ + ✨ Generated from Field `MovieMetadata`.`movie` of type `Movie!` + """ + movie: Movie_Key + """ + ✨ Generated from Field `MovieMetadata`.`director` of type `String` + """ + director: String + """ + ✨ `_expr` server value variant of `director` (✨ Generated from Field `MovieMetadata`.`director` of type `String`) + """ + director_expr: String_Expr +} +""" +✨ Generated filter input type for table 'MovieMetadata'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. +""" +input MovieMetadata_Filter { + """ + Apply multiple filter conditions using `AND` logic. + """ + _and: [MovieMetadata_Filter!] + """ + Negate the result of the provided filter condition. + """ + _not: MovieMetadata_Filter + """ + Apply multiple filter conditions using `OR` logic. + """ + _or: [MovieMetadata_Filter!] + """ + ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!` + """ + id: UUID_Filter + """ + ✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!` + """ + movieId: UUID_Filter + """ + ✨ Generated from Field `MovieMetadata`.`movie` of type `Movie!` + """ + movie: Movie_Filter + """ + ✨ Generated from Field `MovieMetadata`.`director` of type `String` + """ + director: String_Filter +} +""" +✨ Generated first-row input type for table 'MovieMetadata'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. +""" +input MovieMetadata_FirstRow { + """ + Order the result by the specified fields. + """ + orderBy: [MovieMetadata_Order!] + """ + Filters rows based on the specified conditions. + """ + where: MovieMetadata_Filter +} +""" +✨ Generated key input type for table 'MovieMetadata'. It represents the primary key fields used to uniquely identify a row in the table. +""" +input MovieMetadata_Key { + """ + ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!` + """ + id: UUID + """ + ✨ `_expr` server value variant of `id` (✨ Generated from Field `MovieMetadata`.`id` of type `UUID!`) + """ + id_expr: UUID_Expr +} +""" +✨ Generated list filter input type for table 'MovieMetadata'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. +""" +input MovieMetadata_ListFilter { + """ + The desired number of objects that match the condition (defaults to at least one). + """ + count: Int_Filter = {gt:0} + """ + Condition of the related objects to filter for. + """ + exist: MovieMetadata_Filter +} +""" +✨ Generated order input type for table 'MovieMetadata'. This input defines the sorting order of rows in query results based on one or more fields. +""" +input MovieMetadata_Order { + """ + ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!` + """ + id: OrderDirection + """ + ✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!` + """ + movieId: OrderDirection + """ + ✨ Generated from Field `MovieMetadata`.`movie` of type `Movie!` + """ + movie: Movie_Order + """ + ✨ Generated from Field `MovieMetadata`.`director` of type `String` + """ + director: OrderDirection +} +""" +✨ Generated data input type for table 'Review'. It includes all necessary fields for creating or upserting rows into table. +""" +input Review_Data { + """ + ✨ Generated from Field `Review`.`movieId` of type `UUID!` + """ + movieId: UUID + """ + ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `Review`.`movieId` of type `UUID!`) + """ + movieId_expr: UUID_Expr + """ + ✨ Generated from Field `Review`.`userId` of type `String!` + """ + userId: String + """ + ✨ `_expr` server value variant of `userId` (✨ Generated from Field `Review`.`userId` of type `String!`) + """ + userId_expr: String_Expr + """ + ✨ Generated from Field `Review`.`movie` of type `Movie!` + """ + movie: Movie_Key + """ + ✨ Generated from Field `Review`.`user` of type `User!` + """ + user: User_Key + """ + ✨ Generated from Field `Review`.`id` of type `UUID!` + """ + id: UUID + """ + ✨ `_expr` server value variant of `id` (✨ Generated from Field `Review`.`id` of type `UUID!`) + """ + id_expr: UUID_Expr + """ + ✨ Generated from Field `Review`.`rating` of type `Int` + """ + rating: Int + """ + ✨ Generated from Field `Review`.`reviewDate` of type `Date!` + """ + reviewDate: Date + """ + ✨ `_date` server value variant of `reviewDate` (✨ Generated from Field `Review`.`reviewDate` of type `Date!`) + """ + reviewDate_date: Date_Relative + """ + ✨ `_expr` server value variant of `reviewDate` (✨ Generated from Field `Review`.`reviewDate` of type `Date!`) + """ + reviewDate_expr: Date_Expr + """ + ✨ Generated from Field `Review`.`reviewText` of type `String` + """ + reviewText: String + """ + ✨ `_expr` server value variant of `reviewText` (✨ Generated from Field `Review`.`reviewText` of type `String`) + """ + reviewText_expr: String_Expr +} +""" +✨ Generated filter input type for table 'Review'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. +""" +input Review_Filter { + """ + Apply multiple filter conditions using `AND` logic. + """ + _and: [Review_Filter!] + """ + Negate the result of the provided filter condition. + """ + _not: Review_Filter + """ + Apply multiple filter conditions using `OR` logic. + """ + _or: [Review_Filter!] + """ + ✨ Generated from Field `Review`.`movieId` of type `UUID!` + """ + movieId: UUID_Filter + """ + ✨ Generated from Field `Review`.`userId` of type `String!` + """ + userId: String_Filter + """ + ✨ Generated from Field `Review`.`movie` of type `Movie!` + """ + movie: Movie_Filter + """ + ✨ Generated from Field `Review`.`user` of type `User!` + """ + user: User_Filter + """ + ✨ Generated from Field `Review`.`id` of type `UUID!` + """ + id: UUID_Filter + """ + ✨ Generated from Field `Review`.`rating` of type `Int` + """ + rating: Int_Filter + """ + ✨ Generated from Field `Review`.`reviewDate` of type `Date!` + """ + reviewDate: Date_Filter + """ + ✨ Generated from Field `Review`.`reviewText` of type `String` + """ + reviewText: String_Filter +} +""" +✨ Generated first-row input type for table 'Review'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. +""" +input Review_FirstRow { + """ + Order the result by the specified fields. + """ + orderBy: [Review_Order!] + """ + Filters rows based on the specified conditions. + """ + where: Review_Filter +} +""" +✨ Generated key input type for table 'Review'. It represents the primary key fields used to uniquely identify a row in the table. +""" +input Review_Key { + """ + ✨ Generated from Field `Review`.`movieId` of type `UUID!` + """ + movieId: UUID + """ + ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `Review`.`movieId` of type `UUID!`) + """ + movieId_expr: UUID_Expr + """ + ✨ Generated from Field `Review`.`userId` of type `String!` + """ + userId: String + """ + ✨ `_expr` server value variant of `userId` (✨ Generated from Field `Review`.`userId` of type `String!`) + """ + userId_expr: String_Expr +} +""" +✨ Generated list filter input type for table 'Review'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. +""" +input Review_ListFilter { + """ + The desired number of objects that match the condition (defaults to at least one). + """ + count: Int_Filter = {gt:0} + """ + Condition of the related objects to filter for. + """ + exist: Review_Filter +} +""" +✨ Generated order input type for table 'Review'. This input defines the sorting order of rows in query results based on one or more fields. +""" +input Review_Order { + """ + ✨ Generated from Field `Review`.`movieId` of type `UUID!` + """ + movieId: OrderDirection + """ + ✨ Generated from Field `Review`.`userId` of type `String!` + """ + userId: OrderDirection + """ + ✨ Generated from Field `Review`.`movie` of type `Movie!` + """ + movie: Movie_Order + """ + ✨ Generated from Field `Review`.`user` of type `User!` + """ + user: User_Order + """ + ✨ Generated from Field `Review`.`id` of type `UUID!` + """ + id: OrderDirection + """ + ✨ Generated from Field `Review`.`rating` of type `Int` + """ + rating: OrderDirection + """ + ✨ Generated from Field `Review`.`reviewDate` of type `Date!` + """ + reviewDate: OrderDirection + """ + ✨ Generated from Field `Review`.`reviewText` of type `String` + """ + reviewText: OrderDirection +} +""" +✨ Generated data input type for table 'User'. It includes all necessary fields for creating or upserting rows into table. +""" +input User_Data { + """ + ✨ Generated from Field `User`.`id` of type `String!` + """ + id: String + """ + ✨ `_expr` server value variant of `id` (✨ Generated from Field `User`.`id` of type `String!`) + """ + id_expr: String_Expr + """ + ✨ Generated from Field `User`.`username` of type `String!` + """ + username: String + """ + ✨ `_expr` server value variant of `username` (✨ Generated from Field `User`.`username` of type `String!`) + """ + username_expr: String_Expr +} +""" +✨ Generated filter input type for table 'User'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. +""" +input User_Filter { + """ + Apply multiple filter conditions using `AND` logic. + """ + _and: [User_Filter!] + """ + Negate the result of the provided filter condition. + """ + _not: User_Filter + """ + Apply multiple filter conditions using `OR` logic. + """ + _or: [User_Filter!] + """ + ✨ Generated from Field `User`.`id` of type `String!` + """ + id: String_Filter + """ + ✨ Generated from Field `User`.`username` of type `String!` + """ + username: String_Filter + """ + ✨ Generated from Field `User`.`favorite_movies_on_user` of type `[FavoriteMovie!]!` + """ + favorite_movies_on_user: FavoriteMovie_ListFilter + """ + ✨ Generated from Field `User`.`reviews_on_user` of type `[Review!]!` + """ + reviews_on_user: Review_ListFilter + """ + ✨ Generated from Field `User`.`movies_via_FavoriteMovie` of type `[Movie!]!` + """ + movies_via_FavoriteMovie: Movie_ListFilter + """ + ✨ Generated from Field `User`.`movies_via_Review` of type `[Movie!]!` + """ + movies_via_Review: Movie_ListFilter +} +""" +✨ Generated first-row input type for table 'User'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. +""" +input User_FirstRow { + """ + Order the result by the specified fields. + """ + orderBy: [User_Order!] + """ + Filters rows based on the specified conditions. + """ + where: User_Filter +} +""" +✨ Generated key input type for table 'User'. It represents the primary key fields used to uniquely identify a row in the table. +""" +input User_Key { + """ + ✨ Generated from Field `User`.`id` of type `String!` + """ + id: String + """ + ✨ `_expr` server value variant of `id` (✨ Generated from Field `User`.`id` of type `String!`) + """ + id_expr: String_Expr +} +""" +✨ Generated list filter input type for table 'User'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. +""" +input User_ListFilter { + """ + The desired number of objects that match the condition (defaults to at least one). + """ + count: Int_Filter = {gt:0} + """ + Condition of the related objects to filter for. + """ + exist: User_Filter +} +""" +✨ Generated order input type for table 'User'. This input defines the sorting order of rows in query results based on one or more fields. +""" +input User_Order { + """ + ✨ Generated from Field `User`.`id` of type `String!` + """ + id: OrderDirection + """ + ✨ Generated from Field `User`.`username` of type `String!` + """ + username: OrderDirection +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql new file mode 100644 index 00000000..1dad2178 --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql @@ -0,0 +1,766 @@ +extend type Mutation { + """ + ✨ Insert a single `Actor` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + actor_insert( + """ + Data object to insert into the table. + """ + data: Actor_Data! + ): Actor_KeyOutput! @fdc_generated(from: "Actor", purpose: INSERT_SINGLE) + """ + ✨ Insert a single `FavoriteMovie` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + favorite_movie_insert( + """ + Data object to insert into the table. + """ + data: FavoriteMovie_Data! + ): FavoriteMovie_KeyOutput! @fdc_generated(from: "FavoriteMovie", purpose: INSERT_SINGLE) + """ + ✨ Insert a single `Movie` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + movie_insert( + """ + Data object to insert into the table. + """ + data: Movie_Data! + ): Movie_KeyOutput! @fdc_generated(from: "Movie", purpose: INSERT_SINGLE) + """ + ✨ Insert a single `MovieActor` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + movieActor_insert( + """ + Data object to insert into the table. + """ + data: MovieActor_Data! + ): MovieActor_KeyOutput! @fdc_generated(from: "MovieActor", purpose: INSERT_SINGLE) + """ + ✨ Insert a single `MovieMetadata` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + movieMetadata_insert( + """ + Data object to insert into the table. + """ + data: MovieMetadata_Data! + ): MovieMetadata_KeyOutput! @fdc_generated(from: "MovieMetadata", purpose: INSERT_SINGLE) + """ + ✨ Insert a single `Review` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + review_insert( + """ + Data object to insert into the table. + """ + data: Review_Data! + ): Review_KeyOutput! @fdc_generated(from: "Review", purpose: INSERT_SINGLE) + """ + ✨ Insert a single `User` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + user_insert( + """ + Data object to insert into the table. + """ + data: User_Data! + ): User_KeyOutput! @fdc_generated(from: "User", purpose: INSERT_SINGLE) + """ + ✨ Insert `Actor` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + actor_insertMany( + """ + List of data objects to insert into the table. + """ + data: [Actor_Data!]! + ): [Actor_KeyOutput!]! @fdc_generated(from: "Actor", purpose: INSERT_MULTIPLE) + """ + ✨ Insert `FavoriteMovie` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + favorite_movie_insertMany( + """ + List of data objects to insert into the table. + """ + data: [FavoriteMovie_Data!]! + ): [FavoriteMovie_KeyOutput!]! @fdc_generated(from: "FavoriteMovie", purpose: INSERT_MULTIPLE) + """ + ✨ Insert `Movie` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + movie_insertMany( + """ + List of data objects to insert into the table. + """ + data: [Movie_Data!]! + ): [Movie_KeyOutput!]! @fdc_generated(from: "Movie", purpose: INSERT_MULTIPLE) + """ + ✨ Insert `MovieActor` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + movieActor_insertMany( + """ + List of data objects to insert into the table. + """ + data: [MovieActor_Data!]! + ): [MovieActor_KeyOutput!]! @fdc_generated(from: "MovieActor", purpose: INSERT_MULTIPLE) + """ + ✨ Insert `MovieMetadata` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + movieMetadata_insertMany( + """ + List of data objects to insert into the table. + """ + data: [MovieMetadata_Data!]! + ): [MovieMetadata_KeyOutput!]! @fdc_generated(from: "MovieMetadata", purpose: INSERT_MULTIPLE) + """ + ✨ Insert `Review` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + review_insertMany( + """ + List of data objects to insert into the table. + """ + data: [Review_Data!]! + ): [Review_KeyOutput!]! @fdc_generated(from: "Review", purpose: INSERT_MULTIPLE) + """ + ✨ Insert `User` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + user_insertMany( + """ + List of data objects to insert into the table. + """ + data: [User_Data!]! + ): [User_KeyOutput!]! @fdc_generated(from: "User", purpose: INSERT_MULTIPLE) + """ + ✨ 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 object to insert or update if it already exists. + """ + data: Actor_Data! + ): Actor_KeyOutput! @fdc_generated(from: "Actor", purpose: UPSERT_SINGLE) + """ + ✨ Insert or update a single `FavoriteMovie` into the table, based on the primary key. Returns the key of the newly inserted `FavoriteMovie`. + """ + favorite_movie_upsert( + """ + Data object to insert or update if it already exists. + """ + data: FavoriteMovie_Data! + ): FavoriteMovie_KeyOutput! @fdc_generated(from: "FavoriteMovie", purpose: UPSERT_SINGLE) + """ + ✨ 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 object to insert or update if it already exists. + """ + data: Movie_Data! + ): Movie_KeyOutput! @fdc_generated(from: "Movie", purpose: UPSERT_SINGLE) + """ + ✨ 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 object to insert or update if it already exists. + """ + data: MovieActor_Data! + ): MovieActor_KeyOutput! @fdc_generated(from: "MovieActor", purpose: UPSERT_SINGLE) + """ + ✨ 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 object to insert or update if it already exists. + """ + data: MovieMetadata_Data! + ): MovieMetadata_KeyOutput! @fdc_generated(from: "MovieMetadata", purpose: UPSERT_SINGLE) + """ + ✨ 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 object to insert or update if it already exists. + """ + data: Review_Data! + ): Review_KeyOutput! @fdc_generated(from: "Review", purpose: UPSERT_SINGLE) + """ + ✨ 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 object to insert or update if it already exists. + """ + data: User_Data! + ): User_KeyOutput! @fdc_generated(from: "User", purpose: UPSERT_SINGLE) + """ + ✨ Insert or update `Actor` objects into the table, based on the primary key. Returns the key of the newly inserted `Actor`. + """ + actor_upsertMany( + """ + List of data objects to insert or update if it already exists. + """ + data: [Actor_Data!]! + ): [Actor_KeyOutput!]! @fdc_generated(from: "Actor", purpose: UPSERT_MULTIPLE) + """ + ✨ Insert or update `FavoriteMovie` objects into the table, based on the primary key. Returns the key of the newly inserted `FavoriteMovie`. + """ + favorite_movie_upsertMany( + """ + List of data objects to insert or update if it already exists. + """ + data: [FavoriteMovie_Data!]! + ): [FavoriteMovie_KeyOutput!]! @fdc_generated(from: "FavoriteMovie", purpose: UPSERT_MULTIPLE) + """ + ✨ Insert or update `Movie` objects into the table, based on the primary key. Returns the key of the newly inserted `Movie`. + """ + movie_upsertMany( + """ + List of data objects to insert or update if it already exists. + """ + data: [Movie_Data!]! + ): [Movie_KeyOutput!]! @fdc_generated(from: "Movie", purpose: UPSERT_MULTIPLE) + """ + ✨ Insert or update `MovieActor` objects into the table, based on the primary key. Returns the key of the newly inserted `MovieActor`. + """ + movieActor_upsertMany( + """ + List of data objects to insert or update if it already exists. + """ + data: [MovieActor_Data!]! + ): [MovieActor_KeyOutput!]! @fdc_generated(from: "MovieActor", purpose: UPSERT_MULTIPLE) + """ + ✨ Insert or update `MovieMetadata` objects into the table, based on the primary key. Returns the key of the newly inserted `MovieMetadata`. + """ + movieMetadata_upsertMany( + """ + List of data objects to insert or update if it already exists. + """ + data: [MovieMetadata_Data!]! + ): [MovieMetadata_KeyOutput!]! @fdc_generated(from: "MovieMetadata", purpose: UPSERT_MULTIPLE) + """ + ✨ Insert or update `Review` objects into the table, based on the primary key. Returns the key of the newly inserted `Review`. + """ + review_upsertMany( + """ + List of data objects to insert or update if it already exists. + """ + data: [Review_Data!]! + ): [Review_KeyOutput!]! @fdc_generated(from: "Review", purpose: UPSERT_MULTIPLE) + """ + ✨ Insert or update `User` objects into the table, based on the primary key. Returns the key of the newly inserted `User`. + """ + user_upsertMany( + """ + List of data objects to insert or update if it already exists. + """ + data: [User_Data!]! + ): [User_KeyOutput!]! @fdc_generated(from: "User", purpose: UPSERT_MULTIPLE) + """ + ✨ Update a single `Actor` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. + """ + actor_update( + """ + The unique ID of the object. + """ + id: UUID + + """ + The key used to identify the object. + """ + key: Actor_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: Actor_FirstRow + + """ + Data object containing fields to be updated. + """ + data: Actor_Data! + ): Actor_KeyOutput @fdc_generated(from: "Actor", purpose: UPDATE_SINGLE) + """ + ✨ Update a single `FavoriteMovie` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. + """ + favorite_movie_update( + """ + The key used to identify the object. + """ + key: FavoriteMovie_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: FavoriteMovie_FirstRow + + """ + Data object containing fields to be updated. + """ + data: FavoriteMovie_Data! + ): FavoriteMovie_KeyOutput @fdc_generated(from: "FavoriteMovie", purpose: UPDATE_SINGLE) + """ + ✨ Update a single `Movie` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. + """ + movie_update( + """ + The unique ID of the object. + """ + id: UUID + + """ + The key used to identify the object. + """ + key: Movie_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: Movie_FirstRow + + """ + Data object containing fields to be updated. + """ + data: Movie_Data! + ): Movie_KeyOutput @fdc_generated(from: "Movie", purpose: UPDATE_SINGLE) + """ + ✨ Update a single `MovieActor` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. + """ + movieActor_update( + """ + The key used to identify the object. + """ + key: MovieActor_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: MovieActor_FirstRow + + """ + Data object containing fields to be updated. + """ + data: MovieActor_Data! + ): MovieActor_KeyOutput @fdc_generated(from: "MovieActor", purpose: UPDATE_SINGLE) + """ + ✨ Update a single `MovieMetadata` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. + """ + movieMetadata_update( + """ + The unique ID of the object. + """ + id: UUID + + """ + The key used to identify the object. + """ + key: MovieMetadata_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: MovieMetadata_FirstRow + + """ + Data object containing fields to be updated. + """ + data: MovieMetadata_Data! + ): MovieMetadata_KeyOutput @fdc_generated(from: "MovieMetadata", purpose: UPDATE_SINGLE) + """ + ✨ Update a single `Review` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. + """ + review_update( + """ + The key used to identify the object. + """ + key: Review_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: Review_FirstRow + + """ + Data object containing fields to be updated. + """ + data: Review_Data! + ): Review_KeyOutput @fdc_generated(from: "Review", purpose: UPDATE_SINGLE) + """ + ✨ Update a single `User` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. + """ + user_update( + """ + The unique ID of the object. + """ + id: String + + """ + ✨ `_expr` server value variant of `id` (The unique ID of the object.) + """ + id_expr: String_Expr + + """ + The key used to identify the object. + """ + key: User_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: User_FirstRow + + """ + Data object containing fields to be updated. + """ + data: User_Data! + ): User_KeyOutput @fdc_generated(from: "User", purpose: UPDATE_SINGLE) + """ + ✨ Update `Actor` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + actor_updateMany( + """ + Filter condition to specify which rows to update. + """ + where: Actor_Filter + + """ + Set to true to update all rows. + """ + all: Boolean = false + + """ + Data object containing fields to update. + """ + data: Actor_Data! + ): Int! @fdc_generated(from: "Actor", purpose: UPDATE_MULTIPLE) + """ + ✨ Update `FavoriteMovie` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + favorite_movie_updateMany( + """ + Filter condition to specify which rows to update. + """ + where: FavoriteMovie_Filter + + """ + Set to true to update all rows. + """ + all: Boolean = false + + """ + Data object containing fields to update. + """ + data: FavoriteMovie_Data! + ): Int! @fdc_generated(from: "FavoriteMovie", purpose: UPDATE_MULTIPLE) + """ + ✨ Update `Movie` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + movie_updateMany( + """ + Filter condition to specify which rows to update. + """ + where: Movie_Filter + + """ + Set to true to update all rows. + """ + all: Boolean = false + + """ + Data object containing fields to update. + """ + data: Movie_Data! + ): Int! @fdc_generated(from: "Movie", purpose: UPDATE_MULTIPLE) + """ + ✨ Update `MovieActor` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + movieActor_updateMany( + """ + Filter condition to specify which rows to update. + """ + where: MovieActor_Filter + + """ + Set to true to update all rows. + """ + all: Boolean = false + + """ + Data object containing fields to update. + """ + data: MovieActor_Data! + ): Int! @fdc_generated(from: "MovieActor", purpose: UPDATE_MULTIPLE) + """ + ✨ Update `MovieMetadata` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + movieMetadata_updateMany( + """ + Filter condition to specify which rows to update. + """ + where: MovieMetadata_Filter + + """ + Set to true to update all rows. + """ + all: Boolean = false + + """ + Data object containing fields to update. + """ + data: MovieMetadata_Data! + ): Int! @fdc_generated(from: "MovieMetadata", purpose: UPDATE_MULTIPLE) + """ + ✨ Update `Review` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + review_updateMany( + """ + Filter condition to specify which rows to update. + """ + where: Review_Filter + + """ + Set to true to update all rows. + """ + all: Boolean = false + + """ + Data object containing fields to update. + """ + data: Review_Data! + ): Int! @fdc_generated(from: "Review", purpose: UPDATE_MULTIPLE) + """ + ✨ Update `User` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + user_updateMany( + """ + Filter condition to specify which rows to update. + """ + where: User_Filter + + """ + Set to true to update all rows. + """ + all: Boolean = false + + """ + Data object containing fields to update. + """ + data: User_Data! + ): Int! @fdc_generated(from: "User", purpose: UPDATE_MULTIPLE) + """ + ✨ Delete a single `Actor` based on `id`, `key` or `first` and return its key (or `null` if not found). + """ + actor_delete( + """ + The unique ID of the object. + """ + id: UUID + + """ + The key used to identify the object. + """ + key: Actor_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: Actor_FirstRow + ): Actor_KeyOutput @fdc_generated(from: "Actor", purpose: DELETE_SINGLE) + """ + ✨ Delete a single `FavoriteMovie` based on `id`, `key` or `first` and return its key (or `null` if not found). + """ + favorite_movie_delete( + """ + The key used to identify the object. + """ + key: FavoriteMovie_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: FavoriteMovie_FirstRow + ): FavoriteMovie_KeyOutput @fdc_generated(from: "FavoriteMovie", purpose: DELETE_SINGLE) + """ + ✨ Delete a single `Movie` based on `id`, `key` or `first` and return its key (or `null` if not found). + """ + movie_delete( + """ + The unique ID of the object. + """ + id: UUID + + """ + The key used to identify the object. + """ + key: Movie_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: Movie_FirstRow + ): Movie_KeyOutput @fdc_generated(from: "Movie", purpose: DELETE_SINGLE) + """ + ✨ Delete a single `MovieActor` based on `id`, `key` or `first` and return its key (or `null` if not found). + """ + movieActor_delete( + """ + The key used to identify the object. + """ + key: MovieActor_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: MovieActor_FirstRow + ): MovieActor_KeyOutput @fdc_generated(from: "MovieActor", purpose: DELETE_SINGLE) + """ + ✨ Delete a single `MovieMetadata` based on `id`, `key` or `first` and return its key (or `null` if not found). + """ + movieMetadata_delete( + """ + The unique ID of the object. + """ + id: UUID + + """ + The key used to identify the object. + """ + key: MovieMetadata_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: MovieMetadata_FirstRow + ): MovieMetadata_KeyOutput @fdc_generated(from: "MovieMetadata", purpose: DELETE_SINGLE) + """ + ✨ Delete a single `Review` based on `id`, `key` or `first` and return its key (or `null` if not found). + """ + review_delete( + """ + The key used to identify the object. + """ + key: Review_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: Review_FirstRow + ): Review_KeyOutput @fdc_generated(from: "Review", purpose: DELETE_SINGLE) + """ + ✨ Delete a single `User` based on `id`, `key` or `first` and return its key (or `null` if not found). + """ + user_delete( + """ + The unique ID of the object. + """ + id: String + + """ + ✨ `_expr` server value variant of `id` (The unique ID of the object.) + """ + id_expr: String_Expr + + """ + The key used to identify the object. + """ + key: User_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: User_FirstRow + ): User_KeyOutput @fdc_generated(from: "User", purpose: DELETE_SINGLE) + """ + ✨ Delete `Actor` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + actor_deleteMany( + """ + Filter condition to specify which rows to delete. + """ + where: Actor_Filter + + """ + Set to true to delete all rows. + """ + all: Boolean = false + ): Int! @fdc_generated(from: "Actor", purpose: DELETE_MULTIPLE) + """ + ✨ Delete `FavoriteMovie` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + favorite_movie_deleteMany( + """ + Filter condition to specify which rows to delete. + """ + where: FavoriteMovie_Filter + + """ + Set to true to delete all rows. + """ + all: Boolean = false + ): Int! @fdc_generated(from: "FavoriteMovie", purpose: DELETE_MULTIPLE) + """ + ✨ Delete `Movie` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + movie_deleteMany( + """ + Filter condition to specify which rows to delete. + """ + where: Movie_Filter + + """ + Set to true to delete all rows. + """ + all: Boolean = false + ): Int! @fdc_generated(from: "Movie", purpose: DELETE_MULTIPLE) + """ + ✨ Delete `MovieActor` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + movieActor_deleteMany( + """ + Filter condition to specify which rows to delete. + """ + where: MovieActor_Filter + + """ + Set to true to delete all rows. + """ + all: Boolean = false + ): Int! @fdc_generated(from: "MovieActor", purpose: DELETE_MULTIPLE) + """ + ✨ Delete `MovieMetadata` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + movieMetadata_deleteMany( + """ + Filter condition to specify which rows to delete. + """ + where: MovieMetadata_Filter + + """ + Set to true to delete all rows. + """ + all: Boolean = false + ): Int! @fdc_generated(from: "MovieMetadata", purpose: DELETE_MULTIPLE) + """ + ✨ Delete `Review` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + review_deleteMany( + """ + Filter condition to specify which rows to delete. + """ + where: Review_Filter + + """ + Set to true to delete all rows. + """ + all: Boolean = false + ): Int! @fdc_generated(from: "Review", purpose: DELETE_MULTIPLE) + """ + ✨ Delete `User` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + user_deleteMany( + """ + Filter condition to specify which rows to delete. + """ + where: User_Filter + + """ + Set to true to delete all rows. + """ + all: Boolean = false + ): Int! @fdc_generated(from: "User", purpose: DELETE_MULTIPLE) +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/query.gql b/dataconnect/dataconnect/.dataconnect/schema/main/query.gql new file mode 100644 index 00000000..cbbc2571 --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/main/query.gql @@ -0,0 +1,293 @@ +extend type Query { + """ + ✨ Look up a single `Actor` based on `id`, `key` or `first` and return selected fields (or `null` if not found). + """ + actor( + """ + The unique ID of the object. + """ + id: UUID + + """ + The key used to identify the object. + """ + key: Actor_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: Actor_FirstRow + ): Actor @fdc_generated(from: "Actor", purpose: QUERY_SINGLE) + """ + ✨ Look up a single `FavoriteMovie` based on `id`, `key` or `first` and return selected fields (or `null` if not found). + """ + favorite_movie( + """ + The key used to identify the object. + """ + key: FavoriteMovie_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: FavoriteMovie_FirstRow + ): FavoriteMovie @fdc_generated(from: "FavoriteMovie", purpose: QUERY_SINGLE) + """ + ✨ Look up a single `Movie` based on `id`, `key` or `first` and return selected fields (or `null` if not found). + """ + movie( + """ + The unique ID of the object. + """ + id: UUID + + """ + The key used to identify the object. + """ + key: Movie_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: Movie_FirstRow + ): Movie @fdc_generated(from: "Movie", purpose: QUERY_SINGLE) + """ + ✨ Look up a single `MovieActor` based on `id`, `key` or `first` and return selected fields (or `null` if not found). + """ + movieActor( + """ + The key used to identify the object. + """ + key: MovieActor_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: MovieActor_FirstRow + ): MovieActor @fdc_generated(from: "MovieActor", purpose: QUERY_SINGLE) + """ + ✨ Look up a single `MovieMetadata` based on `id`, `key` or `first` and return selected fields (or `null` if not found). + """ + movieMetadata( + """ + The unique ID of the object. + """ + id: UUID + + """ + The key used to identify the object. + """ + key: MovieMetadata_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: MovieMetadata_FirstRow + ): MovieMetadata @fdc_generated(from: "MovieMetadata", purpose: QUERY_SINGLE) + """ + ✨ Look up a single `Review` based on `id`, `key` or `first` and return selected fields (or `null` if not found). + """ + review( + """ + The key used to identify the object. + """ + key: Review_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: Review_FirstRow + ): Review @fdc_generated(from: "Review", purpose: QUERY_SINGLE) + """ + ✨ Look up a single `User` based on `id`, `key` or `first` and return selected fields (or `null` if not found). + """ + user( + """ + The unique ID of the object. + """ + id: String + + """ + ✨ `_expr` server value variant of `id` (The unique ID of the object.) + """ + id_expr: String_Expr + + """ + The key used to identify the object. + """ + key: User_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: User_FirstRow + ): User @fdc_generated(from: "User", purpose: QUERY_SINGLE) + """ + ✨ List `Actor` objects in the table, optionally filtered by `where` conditions. + """ + actors( + """ + Filter condition to narrow down the query results. + """ + where: Actor_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [Actor_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [Actor!]! @fdc_generated(from: "Actor", purpose: QUERY_MULTIPLE) + """ + ✨ List `FavoriteMovie` objects in the table, optionally filtered by `where` conditions. + """ + favorite_movies( + """ + Filter condition to narrow down the query results. + """ + where: FavoriteMovie_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [FavoriteMovie_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [FavoriteMovie!]! @fdc_generated(from: "FavoriteMovie", purpose: QUERY_MULTIPLE) + """ + ✨ List `Movie` objects in the table, optionally filtered by `where` conditions. + """ + movies( + """ + Filter condition to narrow down the query results. + """ + where: Movie_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [Movie_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [Movie!]! @fdc_generated(from: "Movie", purpose: QUERY_MULTIPLE) + """ + ✨ List `MovieActor` objects in the table, optionally filtered by `where` conditions. + """ + movieActors( + """ + Filter condition to narrow down the query results. + """ + where: MovieActor_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [MovieActor_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [MovieActor!]! @fdc_generated(from: "MovieActor", purpose: QUERY_MULTIPLE) + """ + ✨ List `MovieMetadata` objects in the table, optionally filtered by `where` conditions. + """ + movieMetadatas( + """ + Filter condition to narrow down the query results. + """ + where: MovieMetadata_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [MovieMetadata_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [MovieMetadata!]! @fdc_generated(from: "MovieMetadata", purpose: QUERY_MULTIPLE) + """ + ✨ List `Review` objects in the table, optionally filtered by `where` conditions. + """ + reviews( + """ + Filter condition to narrow down the query results. + """ + where: Review_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [Review_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [Review!]! @fdc_generated(from: "Review", purpose: QUERY_MULTIPLE) + """ + ✨ List `User` objects in the table, optionally filtered by `where` conditions. + """ + users( + """ + Filter condition to narrow down the query results. + """ + where: User_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [User_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [User!]! @fdc_generated(from: "User", purpose: QUERY_MULTIPLE) +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql new file mode 100644 index 00000000..5b1d7799 --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql @@ -0,0 +1,318 @@ +extend type Actor { + """ + ✨ List `MovieActor` objects in a one-to-many relationship (where `MovieActor`.`actor` is this object). + """ + movieActors_on_actor( + """ + Filter condition to narrow down the query results. + """ + where: MovieActor_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [MovieActor_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [MovieActor!]! @fdc_generated(from: "MovieActor.actor", purpose: QUERY_MULTIPLE_ONE_TO_MANY) + """ + ✨ List `Movie` objects using `MovieActor` as the join table (a `MovieActor` object exists where its `actor` is this and its `movie` is that). + """ + movies_via_MovieActor( + """ + Filter condition to narrow down the query results. + """ + where: MovieActor_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [MovieActor_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [Movie!]! @fdc_generated(from: "MovieActor", purpose: QUERY_MULTIPLE_MANY_TO_MANY) +} +extend type Movie { + """ + ✨ List `FavoriteMovie` objects in a one-to-many relationship (where `FavoriteMovie`.`movie` is this object). + """ + favorite_movies_on_movie( + """ + Filter condition to narrow down the query results. + """ + where: FavoriteMovie_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [FavoriteMovie_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [FavoriteMovie!]! @fdc_generated(from: "FavoriteMovie.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY) + """ + ✨ List `MovieActor` objects in a one-to-many relationship (where `MovieActor`.`movie` is this object). + """ + movieActors_on_movie( + """ + Filter condition to narrow down the query results. + """ + where: MovieActor_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [MovieActor_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [MovieActor!]! @fdc_generated(from: "MovieActor.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY) + """ + ✨ List `MovieMetadata` objects in a one-to-many relationship (where `MovieMetadata`.`movie` is this object). + """ + movieMetadatas_on_movie( + """ + Filter condition to narrow down the query results. + """ + where: MovieMetadata_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [MovieMetadata_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [MovieMetadata!]! @fdc_generated(from: "MovieMetadata.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY) + """ + ✨ List `Review` objects in a one-to-many relationship (where `Review`.`movie` is this object). + """ + reviews_on_movie( + """ + Filter condition to narrow down the query results. + """ + where: Review_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [Review_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [Review!]! @fdc_generated(from: "Review.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY) + """ + ✨ List `Actor` objects using `MovieActor` as the join table (a `MovieActor` object exists where its `movie` is this and its `actor` is that). + """ + actors_via_MovieActor( + """ + Filter condition to narrow down the query results. + """ + where: MovieActor_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [MovieActor_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [Actor!]! @fdc_generated(from: "MovieActor", purpose: QUERY_MULTIPLE_MANY_TO_MANY) + """ + ✨ List `User` objects using `FavoriteMovie` as the join table (a `FavoriteMovie` object exists where its `movie` is this and its `user` is that). + """ + users_via_FavoriteMovie( + """ + Filter condition to narrow down the query results. + """ + where: FavoriteMovie_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [FavoriteMovie_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [User!]! @fdc_generated(from: "FavoriteMovie", purpose: QUERY_MULTIPLE_MANY_TO_MANY) + """ + ✨ List `User` objects using `Review` as the join table (a `Review` object exists where its `movie` is this and its `user` is that). + """ + users_via_Review( + """ + Filter condition to narrow down the query results. + """ + where: Review_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [Review_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [User!]! @fdc_generated(from: "Review", purpose: QUERY_MULTIPLE_MANY_TO_MANY) +} +extend type User { + """ + ✨ List `FavoriteMovie` objects in a one-to-many relationship (where `FavoriteMovie`.`user` is this object). + """ + favorite_movies_on_user( + """ + Filter condition to narrow down the query results. + """ + where: FavoriteMovie_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [FavoriteMovie_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [FavoriteMovie!]! @fdc_generated(from: "FavoriteMovie.user", purpose: QUERY_MULTIPLE_ONE_TO_MANY) + """ + ✨ List `Review` objects in a one-to-many relationship (where `Review`.`user` is this object). + """ + reviews_on_user( + """ + Filter condition to narrow down the query results. + """ + where: Review_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [Review_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [Review!]! @fdc_generated(from: "Review.user", purpose: QUERY_MULTIPLE_ONE_TO_MANY) + """ + ✨ List `Movie` objects using `FavoriteMovie` as the join table (a `FavoriteMovie` object exists where its `user` is this and its `movie` is that). + """ + movies_via_FavoriteMovie( + """ + Filter condition to narrow down the query results. + """ + where: FavoriteMovie_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [FavoriteMovie_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [Movie!]! @fdc_generated(from: "FavoriteMovie", purpose: QUERY_MULTIPLE_MANY_TO_MANY) + """ + ✨ List `Movie` objects using `Review` as the join table (a `Review` object exists where its `user` is this and its `movie` is that). + """ + movies_via_Review( + """ + Filter condition to narrow down the query results. + """ + where: Review_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [Review_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [Movie!]! @fdc_generated(from: "Review", purpose: QUERY_MULTIPLE_MANY_TO_MANY) +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/prelude.gql b/dataconnect/dataconnect/.dataconnect/schema/prelude.gql new file mode 100644 index 00000000..7fac870c --- /dev/null +++ b/dataconnect/dataconnect/.dataconnect/schema/prelude.gql @@ -0,0 +1,2026 @@ +"AccessLevel specifies coarse access policies for common situations." +enum AccessLevel { + """ + This operation is accessible to anyone, with or without authentication. + Equivalent to: `@auth(expr: "true")` + """ + PUBLIC + + """ + This operation can be executed only with a valid Firebase Auth ID token. + **Note:** This access level allows anonymous and unverified accounts, + which may present security and abuse risks. + Equivalent to: `@auth(expr: "auth.uid != nil")` + """ + USER_ANON + + """ + This operation is restricted to non-anonymous Firebase Auth accounts. + Equivalent to: `@auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")` + """ + USER + + """ + This operation is restricted to Firebase Auth accounts with verified email addresses. + Equivalent to: `@auth(expr: "auth.uid != nil && auth.token.email_verified")` + """ + USER_EMAIL_VERIFIED + + """ + This operation cannot be executed by anyone. The operation can only be performed + by using the Admin SDK from a privileged environment. + Equivalent to: `@auth(expr: "false")` + """ + NO_ACCESS +} + +""" +The `@auth` directive defines the authentication policy for a query or mutation. + +It must be added to any operation that you wish to be accessible from a client +application. If not specified, the operation defaults to `@auth(level: NO_ACCESS)`. + +Refer to [Data Connect Auth Guide](https://firebase.google.com/docs/data-connect/authorization-and-security) for the best practices. +""" +directive @auth( + """ + The minimal level of access required to perform this operation. + Exactly one of `level` and `expr` should be specified. + """ + level: AccessLevel @fdc_oneOf(required: true) + """ + A CEL expression that grants access to this operation if the expression + evaluates to `true`. + Exactly one of `level` and `expr` should be specified. + """ + expr: Boolean_Expr @fdc_oneOf(required: true) +) on QUERY | MUTATION + + +""" +Require that this mutation always run in a DB transaction. + +Mutations with `@transaction` are guaranteed to either fully succeed or fully +fail. If any of the fields within the transaction fails, the entire transaction +is rolled back. From a client standpoint, any failure behaves as if the entire +request had failed with a request error and execution had not begun. + +Mutations without `@transaction` would execute each root field one after +another in sequence. It surfaces any errors as partial [field errors](https://spec.graphql.org/October2021/#sec-Errors.Field-errors), +but not impacts the subsequent executions. + +The `@transaction` directive cannot be added to queries for now. +Currently, queries cannot fail partially, the response data is not guaranteed +to be a consistent snapshot. +""" +directive @transaction on MUTATION + +"Query filter criteria for `String` scalar fields." +input String_Filter { + "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." + isNull: Boolean + "Match if field is exactly equal to provided value." + eq: String @fdc_oneOf(group: "eq") + """ + Match if field is exactly equal to the result of the provided server value + expression. Currently only `auth.uid` is supported as an expression. + """ + eq_expr: String_Expr @fdc_oneOf(group: "eq") + "Match if field is not equal to provided value." + ne: String @fdc_oneOf(group: "ne") + """ + Match if field is not equal to the result of the provided server value + expression. Currently only `auth.uid` is supported as an expression. + """ + ne_expr: String_Expr @fdc_oneOf(group: "ne") + "Match if field value is among the provided list of values." + in: [String!] + "Match if field value is not among the provided list of values." + nin: [String!] + "Match if field value is greater than the provided value." + gt: String + "Match if field value is greater than or equal to the provided value." + ge: String + "Match if field value is less than the provided value." + lt: String + "Match if field value is less than or equal to the provided value." + le: String + """ + Match if field value contains the provided value as a substring. Equivalent + to `LIKE '%value%'` + """ + contains: String + """ + Match if field value starts with the provided value. Equivalent to + `LIKE 'value%'` + """ + startsWith: String + """ + Match if field value ends with the provided value. Equivalent to + `LIKE '%value'` + """ + endsWith: String + """ + Match if field value matches the provided pattern. See `String_Pattern` for + more details. + """ + 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 { + "Match using the provided `LIKE` expression." + like: String + "Match using the provided POSIX regular expression." + regex: String + "When true, ignore case when matching." + ignoreCase: Boolean + "When true, invert the match result. Equivalent to `NOT LIKE` or `!~`." + invert: Boolean +} + +"Query filter criteris for `[String!]` scalar fields." +input String_ListFilter { + "Match if list field contains the provided value as a member." + includes: String + "Match if list field does not contain the provided value as a member." + excludes: String + "Match if list field contains all of the provided values as members." + includesAll: [String!] + "Match if list field does not contain any of the provided values as members." + excludesAll: [String!] +} + +"Query filter criteria for `UUID` scalar fields." +input UUID_Filter { + "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." + isNull: Boolean + "Match if field is exactly equal to provided value." + eq: UUID + "Match if field is not equal to provided value." + ne: UUID + "Match if field value is among the provided list of values." + in: [UUID!] + "Match if field value is not among the provided list of values." + nin: [UUID!] +} + +"Query filter criteris for `[UUID!]` scalar fields." +input UUID_ListFilter { + "Match if list field contains the provided value as a member." + includes: UUID + "Match if list field does not contain the provided value as a member." + excludes: UUID + "Match if list field contains all of the provided values as members." + includesAll: [UUID!] + "Match if list field does not contain any of the provided values as members." + excludesAll: [UUID!] +} + +"Query filter criteria for `Int` scalar fields." +input Int_Filter { + "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." + isNull: Boolean + "Match if field is exactly equal to provided value." + eq: Int + "Match if field is not equal to provided value." + ne: Int + "Match if field value is among the provided list of values." + in: [Int!] + "Match if field value is not among the provided list of values." + nin: [Int!] + "Match if field value is greater than the provided value." + gt: Int + "Match if field value is greater than or equal to the provided value." + ge: Int + "Match if field value is less than the provided value." + lt: Int + "Match if field value is less than or equal to the provided value." + le: Int +} + +"Query filter criteris for `[Int!]` scalar fields." +input Int_ListFilter { + "Match if list field contains the provided value as a member." + includes: Int + "Match if list field does not contain the provided value as a member." + excludes: Int + "Match if list field contains all of the provided values as members." + includesAll: [Int!] + "Match if list field does not contain any of the provided values as members." + excludesAll: [Int!] +} + +"Query filter criteria for `Int64` scalar fields." +input Int64_Filter { + "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." + isNull: Boolean + "Match if field is exactly equal to provided value." + eq: Int64 + "Match if field is not equal to provided value." + ne: Int64 + "Match if field value is among the provided list of values." + in: [Int64!] + "Match if field value is not among the provided list of values." + nin: [Int64!] + "Match if field value is greater than the provided value." + gt: Int64 + "Match if field value is greater than or equal to the provided value." + ge: Int64 + "Match if field value is less than the provided value." + lt: Int64 + "Match if field value is less than or equal to the provided value." + le: Int64 +} + +"Query filter criteria for `[Int64!]` scalar fields." +input Int64_ListFilter { + "Match if list field contains the provided value as a member." + includes: Int64 + "Match if list field does not contain the provided value as a member." + excludes: Int64 + "Match if list field contains all of the provided values as members." + includesAll: [Int64!] + "Match if list field does not contain any of the provided values as members." + excludesAll: [Int64!] +} + +"Query filter criteria for `Float` scalar fields." +input Float_Filter { + "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." + isNull: Boolean + "Match if field is exactly equal to provided value." + eq: Float + "Match if field is not equal to provided value." + ne: Float + "Match if field value is among the provided list of values." + in: [Float!] + "Match if field value is not among the provided list of values." + nin: [Float!] + "Match if field value is greater than the provided value." + gt: Float + "Match if field value is greater than or equal to the provided value." + ge: Float + "Match if field value is less than the provided value." + lt: Float + "Match if field value is less than or equal to the provided value." + le: Float +} + +"Query filter criteria for `[Float!]` scalar fields." +input Float_ListFilter { + "Match if list field contains the provided value as a member." + includes: Float + "Match if list field does not contain the provided value as a member." + excludes: Float + "Match if list field contains all of the provided values as members." + includesAll: [Float!] + "Match if list field does not contain any of the provided values as members." + excludesAll: [Float!] +} + +"Query filter criteria for `Boolean` scalar fields." +input Boolean_Filter { + "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." + isNull: Boolean + "Match if field is exactly equal to provided value." + eq: Boolean + "Match if field is not equal to provided value." + ne: Boolean + "Match if field value is among the provided list of values." + in: [Boolean!] + "Match if field value is not among the provided list of values." + nin: [Boolean!] +} + +"Query filter criteria for `[Boolean!]` scalar fields." +input Boolean_ListFilter { + "Match if list field contains the provided value as a member." + includes: Boolean + "Match if list field does not contain the provided value as a member." + excludes: Boolean + "Match if list field contains all of the provided values as members." + includesAll: [Boolean!] + "Match if list field does not contain any of the provided values as members." + excludesAll: [Boolean!] +} + +"Query filter criteria for `Any` scalar fields." +input Any_Filter { + "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." + isNull: Boolean + "Match if field is exactly equal to provided value." + eq: Any + "Match if field is not equal to provided value." + ne: Any + "Match if field value is among the provided list of values." + in: [Any!] + "Match if field value is not among the provided list of values." + nin: [Any!] +} + +"Query filter criteria for `[Any!]` scalar fields." +input Any_ListFilter { + "Match if list field contains the provided value as a member." + includes: Any + "Match if list field does not contain the provided value as a member." + excludes: Any + "Match if list field contains all of the provided values as members." + includesAll: [Any!] + "Match if list field does not contain any of the provided values as members." + excludesAll: [Any!] +} + +""" +(Internal) A string that uniquely identifies a type, field, and so on. + +The most common usage in FDC is `SomeType` or `SomeType.someField`. See the +linked page in the @specifiedBy directive for the GraphQL RFC with more details. +""" +scalar SchemaCoordinate + @specifiedBy(url: "https://github.com/graphql/graphql-wg/blob/6d02705dea034fb65ebc6799632adb7bd550d0aa/rfcs/SchemaCoordinates.md") + @fdc_forbiddenAsFieldType + @fdc_forbiddenAsVariableType + +"(Internal) The purpose of a generated type or field." +enum GeneratedPurpose { + # Implicit fields added to the table types as columns. + IMPLICIT_KEY_FIELD + IMPLICIT_REF_FIELD + + # Relational non-column fields extended to table types. + QUERY_MULTIPLE_ONE_TO_MANY + QUERY_MULTIPLE_MANY_TO_MANY + + # Top-level Query fields. + QUERY_SINGLE + QUERY_MULTIPLE + QUERY_MULTIPLE_BY_SIMILARITY + + # Top-level Mutation fields. + INSERT_SINGLE + INSERT_MULTIPLE + UPSERT_SINGLE + UPSERT_MULTIPLE + UPDATE_SINGLE + UPDATE_MULTIPLE + DELETE_SINGLE + DELETE_MULTIPLE +} + +"(Internal) Added to definitions generated by FDC." +directive @fdc_generated( + "The source type or field that causes this definition to be generated." + from: SchemaCoordinate! + "The reason why this definition is generated, such as the intended use case." + purpose: GeneratedPurpose! +) on + | SCALAR + | OBJECT + | FIELD_DEFINITION + | ARGUMENT_DEFINITION + | INTERFACE + | UNION + | ENUM + | ENUM_VALUE + | INPUT_OBJECT + | INPUT_FIELD_DEFINITION + +type _Service { + "Full Service Definition Language of the Frebase Data Connect Schema, including normalized schema, predefined and generated types." + sdl( + """ + Whether or not to omit Data Connect builtin GraphQL preludes. + They are static GraphQL publically available in the docsite. + """ + omitBuiltin: Boolean = false + """ + Whether or not to omit GQL description in the SDL. + We generate description to document generated schema. + It may bloat the size of SDL. + """ + omitDescription: Boolean = false + ): String! + "Orignal Schema Sources in the service." + schema: String! + "Generated documentation from the schema of the Firebase Data Connect Service." + docs: [_Doc!]! +} + +type _Doc { + "Name of the Doc Page." + page: String! + "The markdown content of the doc page." + markdown: 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 of hexadecimal digits representing an RFC4122-compliant UUID. + +UUIDs are always output as 32 lowercase hexadecimal digits without 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}` + +In the PostgreSQL table, it's stored as [`uuid`](https://www.postgresql.org/docs/current/datatype-uuid.html). +""" +scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122") + +""" +`Int64` is a scalar that represents a 64-bit signed integer. + +In the PostgreSQL table, it's stored as [`bigint`](https://www.postgresql.org/docs/current/datatype-numeric.html). + +On the wire, it's encoded as string because 64-bit integer exceeds the range of JSON number. +""" +scalar Int64 + +""" +The `Any` scalar type accommodates any valid [JSON value](https://www.json.org/json-en.html) +(e.g., numbers, strings, booleans, arrays, objects). PostgreSQL efficiently +stores this data as jsonb, providing flexibility for schemas with evolving structures. + +Caution: JSON doesn't distinguish Int and Float. + +##### Example: + +#### Schema + +```graphql +type Movie @table { + name: String! + metadata: Any! +} +``` + +#### Mutation + +Insert a movie with name and metadata from JSON literal. + +```graphql +mutation InsertMovie { + movie_insert( + data: { + name: "The Dark Knight" + metadata: { + release_year: 2008 + genre: ["Action", "Adventure", "Superhero"] + cast: [ + { name: "Christopher Bale", age: 31 } + { name: "Heath Ledger", age: 28 } + ] + director: "Christopher Nolan" + } + } + ) +} +``` + +Insert a movie with name and metadata that's constructed from a few GQL variables. + +```graphql +mutation InsertMovie($name: String!, $releaseDate: Date!, $genre: [String], $cast: [Any], $director: String!, $boxOfficeInUSD: Int) { + movie_insert(data: { + name: $name, + release_date: $releaseDate, + genre: $genre, + cast: $cast, + director: $director, + box_office: $boxOfficeInUSD + }) +} +``` +**Note**: + + - A mix of non-null and nullable variables can be provided. + + - `Date!` can be passed into scalar `Any` as well! It's stored as string. + + - `$cast` is a nested array. `[Any]` can represent an array of arbitrary types, but it won't enforce the input shape. + +#### Query + +Since `metadata` field has scalar `Any` type, it would return the full JSON in the response. + +**Note**: You can't define selection set to scalar based on [GraphQL spec](https://spec.graphql.org/October2021/#sec-Field-Selections). + +```graphql +query GetAllMovies { + movies { + name + metadata + } +} +``` + +""" +scalar Any @specifiedBy(url: "https://www.json.org/json-en.html") + +""" +The `Void` scalar type represents the absence of any value. It is typically used +in operations where no value is expected in return. +""" +scalar Void + +""" +The `True` scalar type only accepts the boolean value `true`. + +An optional field/argument typed as `True` may either be set +to `true` or omitted (not provided at all). The values `false` or `null` are not +accepted. +""" +scalar True + @fdc_forbiddenAsFieldType + @fdc_forbiddenAsVariableType + @fdc_example(value: true, description: "The only allowed value.") + +""" +A Common Expression Language (CEL) expression that returns a boolean at runtime. + +This expression can reference the `auth` variable, which is null when Firebase +Auth is not used. When Firebase Auth is used, the following fields are available: + + - `auth.uid`: The current user ID. + - `auth.token`: A map containing all token fields (e.g., 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**: Currently, only a limited set of expressions are supported. +""" +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**: Currently, only a limited set of expressions are supported. +""" +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 currently supported for each +type. +""" +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. + +In this example, we defined one table with a field named `myField`. + +```graphql +type TableName @table { + myField: String +} +``` +Data Connect adds an implicit `id` primary key column. So the above schema is equivalent to: + +```graphql +type TableName @table(key: "id") { + id: String @default(expr: "uuidV4()") + myField: String +} +``` + +Data Connect generates the following SQL table and CRUD operations to use it. + +```sql +CREATE TABLE "public"."table_name" ( + "id" uuid NOT NULL DEFAULT uuid_generate_v4(), + "my_field" text NULL, + PRIMARY KEY ("id") +) +``` + + * You can lookup a row: `query ($id: UUID!) { tableName(id: $id) { myField } } ` + * You can find rows using: `query tableNames(limit: 20) { myField }` + * You can insert a row: `mutation { tableName_insert(data: {myField: "foo"}) }` + * You can update a row: `mutation ($id: UUID!) { tableName_update(id: $id, data: {myField: "bar"}) }` + * You can delete a row: `mutation ($id: UUID!) { tableName_delete(id: $id) }` + +##### Customizations + +- `@table(singular)` and `@table(plural)` can customize the singular and plural name. +- `@table(name)` can customize the Postgres table name. +- `@table(key)` can customize the primary key field name and type. + +For example, the `User` table often has a `uid` as its primary key. + +```graphql +type User @table(key: "uid") { + uid: String! + name: String +} +``` + + * You can securely lookup a row: `query { user(key: {uid_expr: "auth.uid"}) { name } } ` + * You can securely insert a row: `mutation { user_insert(data: {uid_expr: "auth.uid" name: "Fred"}) }` + * You can securely update a row: `mutation { user_update(key: {uid_expr: "auth.uid"}, data: {name: "New Name"}) }` + * You can securely delete a row: `mutation { user_delete(key: {uid_expr: "auth.uid"}) }` + +`@table` type can be configured further with: + + - Custom SQL data types for columns. See `@col`. + - Add SQL indexes. See `@index`. + - Add SQL unique constraints. See `@unique`. + - Add foreign key constraints to define relations. See `@ref`. + +""" +directive @table( + """ + Configures the SQL database table name. Defaults to snake_case like `table_name`. + """ + name: String + """ + Configures the singular name. Defaults to the camelCase like `tableName`. + """ + singular: String + """ + Configures the plural name. Defaults to infer based on English plural pattern like `tableNames`. + """ + plural: String + """ + Defines the primary key of the table. Defaults to a single field named `id`. + If not present already, Data Connect adds an implicit field `id: UUID! @default(expr: "uuidV4()")`. + """ + key: [String!] +) on OBJECT + +""" +Defines a relational database Raw SQLview. + +Data Connect generates GraphQL queries with WHERE and ORDER BY clauses. +However, not all SQL features has native GraphQL equivalent. + +You can write **an arbitrary SQL SELECT statement**. Data Connect +would map Graphql fields on `@view` type to columns in your SELECT statement. + +* Scalar GQL fields (camelCase) should match a SQL column (snake_case) + in the SQL SELECT statement. +* Reference GQL field can point to another `@table` type. Similar to foreign key + defined with `@ref` on a `@table` type, a `@view` type establishes a relation + when `@ref(fields)` match `@ref(references)` on the target table. + +In this example, you can use `@view(sql)` to define an aggregation view on existing +table. + +```graphql +type User @table { + name: String + score: Int +} +type UserAggregation @view(sql: ''' + SELECT + COUNT(*) as count, + SUM(score) as sum, + AVG(score) as average, + PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY score) AS median, + (SELECT id FROM "user" LIMIT 1) as example_id + FROM "user" +''') { + count: Int + sum: Int + average: Float + median: Float + example: User + exampleId: UUID +} +``` + +###### Example: Query Raw SQL View + +```graphql +query { + userAggregations { + count sum average median + exampleId example { id } + } +} +``` + +##### One-to-One View + +An one-to-one companion `@view` can be handy if you want to argument a `@table` +with additional implied content. + +```graphql +type Restaurant @table { + name: String! +} +type Review @table { + restaurant: Restaurant! + rating: Int! +} +type RestaurantStats @view(sql: ''' + SELECT + restaurant_id, + COUNT(*) AS review_count, + AVG(rating) AS average_rating + FROM review + GROUP BY restaurant_id +''') { + restaurant: Restaurant @unique + reviewCount: Int + averageRating: Float +} +``` + +In this example, `@unique` convey the assumption that each `Restaurant` should +have only one `RestaurantStats` object. + +###### Example: Query One-to-One View + +```graphql +query ListRestaurants { + restaurants { + name + stats: restaurantStats_on_restaurant { + reviewCount + averageRating + } + } +} +``` + +###### Example: Filter based on One-to-One View + +```graphql +query BestRestaurants($minAvgRating: Float, $minReviewCount: Int) { + restaurants(where: { + restaurantStats_on_restaurant: { + averageRating: {ge: $minAvgRating} + reviewCount: {ge: $minReviewCount} + } + }) { name } +} +``` + +##### Customizations + +- One of `@view(sql)` or `@view(name)` should be defined. + `@view(name)` can refer to a persisted SQL view in the Postgres schema. +- `@view(singular)` and `@view(plural)` can customize the singular and plural name. + +`@view` type can be configured further: + + - `@unique` lets you define one-to-one relation. + - `@col` lets you customize SQL column mapping. For example, `@col(name: "column_in_select")`. + +##### Limitations + +Raw SQL view doesn't have a primary key, so it doesn't support lookup. Other +`@table` or `@view` cannot have `@ref` to a view either. + +View cannot be mutated. You can perform CRUD operations on the underlying +table to alter its content. + +**Important: Data Connect doesn't parse and validate SQL** + +- If the SQL view is invalid or undefined, related requests may fail. +- If the SQL view return incompatible types. Firebase Data Connect may surface + errors. +- If a field doesn't have a corresponding column in the SQL SELECT statement, + it will always be `null`. +- There is no way to ensure VIEW to TABLE `@ref` constraint. +- All fields must be nullable in case they aren't found in the SELECT statement + or in the referenced table. + +**Important: You should always test `@view`!** + +""" +directive @view( + """ + The SQL view name. If neither `name` nor `sql` are provided, defaults to the + snake_case of the singular type name. + `name` and `sql` cannot be specified at the same time. + """ + name: String @fdc_oneOf + """ + SQL `SELECT` statement used as the basis for this type. + SQL SELECT columns should use snake_case. GraphQL fields should use camelCase. + `name` and `sql` cannot be specified at the same time. + """ + sql: String @fdc_oneOf + """ + Configures the singular name. Defaults to the camelCase like `viewName`. + """ + singular: String + """ + Configures the plural name. Defaults to infer based on English plural pattern like `viewNames`. + """ + plural: String +) on OBJECT + +""" +Customizes a field that represents a SQL database table column. + +Data Connect maps scalar Fields on `@table` type to a SQL column of +corresponding data type. + +- scalar `UUID` maps to [`uuid`](https://www.postgresql.org/docs/current/datatype-uuid.html). +- scalar `String` maps to [`text`](https://www.postgresql.org/docs/current/datatype-character.html). +- scalar `Int` maps to [`int`](https://www.postgresql.org/docs/current/datatype-numeric.html). +- scalar `Int64` maps to [`bigint`](https://www.postgresql.org/docs/current/datatype-numeric.html). +- scalar `Float` maps to [`double precision`](https://www.postgresql.org/docs/current/datatype-numeric.html). +- scalar `Boolean` maps to [`boolean`](https://www.postgresql.org/docs/current/datatype-boolean.html). +- scalar `Date` maps to [`date`](https://www.postgresql.org/docs/current/datatype-datetime.html). +- scalar `Timestamp` maps to [`timestamptz`](https://www.postgresql.org/docs/current/datatype-datetime.html). +- scalar `Any` maps to [`jsonb`](https://www.postgresql.org/docs/current/datatype-json.html). +- scalar `Vector` maps to [`pgvector`](https://github.com/pgvector/pgvector). + +Array scalar fields are mapped to [Postgres arrays](https://www.postgresql.org/docs/current/arrays.html). + +###### Example: Serial Primary Key + +For example, you can define auto-increment primary key. + +```graphql +type Post @table { + id: Int! @col(name: "post_id", dataType: "serial") +} +``` + +Data Connect converts it to the following SQL table schema. + +```sql +CREATE TABLE "public"."post" ( + "post_id" serial NOT NULL, + PRIMARY KEY ("id") +) +``` + +###### Example: Vector + +```graphql +type Post @table { + content: String! @col(name: "post_content") + contentEmbedding: Vector! @col(size:768) +} +``` + +""" +directive @col( + """ + The SQL database column name. Defaults to snake_case of the field name. + """ + name: String + """ + Configures the custom SQL data type. + + Each GraphQL type can map to multiple SQL data types. + Refer to [Postgres supported data types](https://www.postgresql.org/docs/current/datatype.html). + + Incompatible SQL data type will lead to undefined behavior. + """ + dataType: String + """ + Required on `Vector` columns. It specifies the length of the Vector. + `textembedding-gecko@003` model generates `Vector` of `@col(size:768)`. + """ + size: Int +) on FIELD_DEFINITION + + +""" +Defines a foreign key reference to another table. + +For example, we can define a many-to-one relation. + +```graphql +type ManyTable @table { + refField: OneTable! +} +type OneTable @table { + someField: String! +} +``` +Data Connect adds implicit foreign key column and relation query field. So the +above schema is equivalent to the following schema. + +```graphql +type ManyTable @table { + id: UUID! @default(expr: "uuidV4()") + refField: OneTable! @ref(fields: "refFieldId", references: "id") + refFieldId: UUID! +} +type OneTable @table { + id: UUID! @default(expr: "uuidV4()") + someField: UUID! + # Generated Fields: + # manyTables_on_refField: [ManyTable!]! +} +``` +Data Connect generates the necessary foreign key constraint. + +```graphql +CREATE TABLE "public"."many_table" ( + "id" uuid NOT NULL DEFAULT uuid_generate_v4(), + "ref_field_id" uuid NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "many_table_ref_field_id_fkey" FOREIGN KEY ("ref_field_id") REFERENCES "public"."one_table" ("id") ON DELETE CASCADE +) +``` + +###### Example: Traverse the Reference Field + +```graphql +query ($id: UUID!) { + manyTable(id: $id) { + refField { id } + } +} +``` + +###### Example: Reverse Traverse the Reference field + +```graphql +query ($id: UUID!) { + oneTable(id: $id) { + manyTables_on_refField { id } + } +} +``` + +##### Optional Many-to-One Relation + +An optional foreign key reference will be set to null if the referenced row is deleted. + +In this example, if a `User` is deleted, the `assignee` and `reporter` +references will be set to null. + +```graphql +type Bug @table { + title: String! + assignee: User + reproter: User +} + +type User @table { name: String! } +``` + +##### Required Many-to-One Relation + +A required foreign key reference will cascade delete if the referenced row is +deleted. + +In this example, if a `Post` is deleted, associated comments will also be +deleted. + +```graphql +type Comment @table { + post: Post! + content: String! +} + +type Post @table { title: String! } +``` + +##### Many To Many Relation + +You can define a many-to-many relation with a join table. + +```graphql +type Membership @table(key: ["group", "user"]) { + group: Group! + user: User! + role: String! @default(value: "member") +} + +type Group @table { name: String! } +type User @table { name: String! } +``` + +When Data Connect sees a table with two reference field as its primary key, it +knows this is a join table, so expands the many-to-many query field. + +```graphql +type Group @table { + name: String! + # Generated Fields: + # users_via_Membership: [User!]! + # memberships_on_group: [Membership!]! +} +type User @table { + name: String! + # Generated Fields: + # groups_via_Membership: [Group!]! + # memberships_on_user: [Membership!]! +} +``` + +###### Example: Traverse the Many-To-Many Relation + +```graphql +query ($id: UUID!) { + group(id: $id) { + users: users_via_Membership { + name + } + } +} +``` + +###### Example: Traverse to the Join Table + +```graphql +query ($id: UUID!) { + group(id: $id) { + memberships: memberships_on_group { + user { name } + role + } + } +} +``` + +##### One To One Relation + +You can even define a one-to-one relation with the help of `@unique` or `@table(key)`. + +```graphql +type User @table { + name: String +} +type Account @table { + user: User! @unique +} +# Alternatively, use primary key constraint. +# type Account @table(key: "user") { +# user: User! +# } +``` + +###### Example: Transerse the Reference Field + +```graphql +query ($id: UUID!) { + account(id: $id) { + user { id } + } +} +``` + +###### Example: Reverse Traverse the Reference field + +```graphql +query ($id: UUID!) { + user(id: $id) { + account_on_user { id } + } +} +``` + +##### Customizations + +- `@ref(constraintName)` can customize the SQL foreign key constraint name (`table_name_ref_field_fkey` above). +- `@ref(fields)` can customize the foreign key field names. +- `@ref(references)` can customize the constraint to reference other columns. + By default, `@ref(references)` is the primary key of the `@ref` table. + Other fields with `@unique` may also be referred in the foreign key constraint. + +""" +directive @ref( + "The SQL database foreign key constraint name. Defaults to snake_case `{table_name}_{field_name}_fkey`." + constraintName: String + """ + Foreign key fields. Defaults to `{tableName}{PrimaryIdName}`. + """ + fields: [String!] + "The fields that the foreign key references in the other table. Defaults to its primary key." + references: [String!] +) on FIELD_DEFINITION + +"Defines the orderBy direction in a query." +enum OrderDirection { +"Results are ordered in ascending order." + ASC +"Results are ordered in descending order." + DESC +} + +""" +Specifies the default value for a column field. + +For example: + +```graphql +type User @table(key: "uid") { + uid: String! @default(expr: "auth.uid") + number: Int! @col(dataType: "serial") + createdAt: Date! @default(expr: "request.time") + role: String! @default(value: "Member") + credit: Int! @default(value: 100) +} +``` + +The supported arguments vary based on the field type. +""" +directive @default( + "A constant value validated against the field's GraphQL type during compilation." + value: Any @fdc_oneOf(required: true) + "A CEL expression whose return value must match the field's 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. + See [PostgreSQL defaults](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-DEFAULT) + for more details. + """ + sql: Any_SQL @fdc_oneOf(required: true) +) on FIELD_DEFINITION + +""" +Defines a database index to optimize query performance. + +```graphql +type User @table @index(fields: ["name", "phoneNumber"], order: [ASC, DESC]) { + name: String @index + phoneNumber: Int64 @index + tags: [String] @index # GIN Index +} +``` + +##### Single Field Index + +You can put `@index` on a `@col` field to create a SQL index. + +`@index(order)` matters little for single field indexes, as they can be scanned +in both directions. + +##### Composite Index + +You can put `@index(fields: [...])` on `@table` type to define composite indexes. + +`@index(order: [...])` can customize the index order to satisfy particular +filter and order requirement. + +""" +directive @index( + """ + Configure the SQL database index id. + + If not overridden, Data Connect generates the index name: + - `{table_name}_{first_field}_{second_field}_aa_idx` + - `{table_name}_{field_name}_idx` + """ + name: String + """ + Only allowed and required when used on a `@table` type. + Specifies the fields to create the index on. + """ + fields: [String!] + """ + Only allowed for `BTREE` `@index` on `@table` type. + Specifies the order for each indexed column. Defaults to all `ASC`. + """ + order: [IndexFieldOrder!] + """ + Customize the index type. + + For most index, it defaults to `BTREE`. + For array fields, only allowed `IndexType` is `GIN`. + For `Vector` fields, defaults to `HNSW`, may configure to `IVFFLAT`. + """ + type: IndexType + """ + Only allowed when used on vector field. + Defines the vector similarity method. Defaults to `INNER_PRODUCT`. + """ + vector_method: VectorSimilarityMethod +) repeatable on FIELD_DEFINITION | OBJECT + +"Specifies the sorting order for database indexes." +enum IndexFieldOrder { + "Sorts the field in ascending order (from lowest to highest)." + ASC + "Sorts the field in descending order (from highest to lowest)." + DESC +} + +"Defines the type of index to be used in the database." +enum IndexType { + "A general-purpose index type commonly used for sorting and searching." + BTREE + "Generalized Inverted Index, optimized for indexing composite values such as arrays." + GIN + "Hierarchical Navigable Small World graph, used for nearest-neighbor searches on vector fields." + HNSW + "Inverted File Index, optimized for approximate nearest-neighbor searches in vector databases." + IVFFLAT +} + +""" +Defines unique constraints on `@table`. + +For example, + +```graphql +type User @table { + phoneNumber: Int64 @unique +} +type UserProfile @table { + user: User! @unique + address: String @unique +} +``` + +- `@unique` on a `@col` field adds a single-column unique constraint. +- `@unique` on a `@table` type adds a composite unique constraint. +- `@unique` on a `@ref` defines a one-to-one relation. It adds unique constraint + on `@ref(fields)`. + +`@unique` ensures those fields can uniquely identify a row, so other `@table` +type may define `@ref(references)` to refer to fields that has a unique constraint. + +""" +directive @unique( + """ + Configures the SQL database unique constraint name. + + If not overridden, Data Connect generates the unique constraint name: + - `table_name_first_field_second_field_uidx` + - `table_name_only_field_name_uidx` + """ + indexName: String + """ + Only allowed and required when used on OBJECT, + this specifies the fields to create a unique constraint on. + """ + fields: [String!] +) repeatable on FIELD_DEFINITION | OBJECT + +""" +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. + +In the PostgreSQL table, it's stored as [`date`](https://www.postgresql.org/docs/current/datatype-datetime.html). +""" +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. + +In the PostgreSQL table, it's stored as [`timestamptz`](https://www.postgresql.org/docs/current/datatype-datetime.html). +""" +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. +""" +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. +""" +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 { + "Match if the field `IS NULL`." + isNull: Boolean + "Match if the field is exactly equal to the provided value." + eq: Date @fdc_oneOf(group: "eq") + "Match if the field equals the provided CEL expression." + eq_expr: Date_Expr @fdc_oneOf(group: "eq") + "Match if the field equals the provided relative date." + eq_date: Date_Relative @fdc_oneOf(group: "eq") + "Match if the field is not equal to the provided value." + ne: Date @fdc_oneOf(group: "ne") + "Match if the field is not equal to the provided CEL expression." + ne_expr: Date_Expr @fdc_oneOf(group: "ne") + "Match if the field is not equal to the provided relative date." + ne_date: Date_Relative @fdc_oneOf(group: "ne") + "Match if the field value is among the provided list of values." + in: [Date!] + "Match if the field value is not among the provided list of values." + nin: [Date!] + "Match if the field value is greater than the provided value." + gt: Date @fdc_oneOf(group: "gt") + "Match if the field value is greater than the provided CEL expression." + gt_expr: Date_Expr @fdc_oneOf(group: "gt") + "Match if the field value is greater than the provided relative date." + gt_date: Date_Relative @fdc_oneOf(group: "gt") + "Match if the field value is greater than or equal to the provided value." + ge: Date @fdc_oneOf(group: "ge") + "Match if the field value is greater than or equal to the provided CEL expression." + ge_expr: Date_Expr @fdc_oneOf(group: "ge") + "Match if the field value is greater than or equal to the provided relative date." + ge_date: Date_Relative @fdc_oneOf(group: "ge") + "Match if the field value is less than the provided value." + lt: Date @fdc_oneOf(group: "lt") + "Match if the field value is less than the provided CEL expression." + lt_expr: Date_Expr @fdc_oneOf(group: "lt") + "Match if the field value is less than the provided relative date." + lt_date: Date_Relative @fdc_oneOf(group: "lt") + "Match if the field value is less than or equal to the provided value." + le: Date @fdc_oneOf(group: "le") + "Match if the field value is less than or equal to the provided CEL expression." + le_expr: Date_Expr @fdc_oneOf(group: "le") + "Match if the field value is less than or equal to the provided relative date." + le_date: Date_Relative @fdc_oneOf(group: "le") +} + +"Conditions on a`Date` list." +input Date_ListFilter { + "Match if the list contains the provided date." + includes: Date @fdc_oneOf(group: "includes") + "Match if the list contains the provided date CEL expression." + includes_expr: Date_Expr @fdc_oneOf(group: "includes") + "Match if the list contains the provided relative date." + includes_date: Date_Relative @fdc_oneOf(group: "includes") + "Match if the list does not contain the provided date." + excludes: Date @fdc_oneOf(group: "excludes") + "Match if the list does not contain the provided date CEL expression." + excludes_expr: Date_Expr @fdc_oneOf(group: "excludes") + "Match if the list does not contain the provided relative date." + excludes_date: Date_Relative @fdc_oneOf(group: "excludes") + "Match if the list contains all the provided dates." + includesAll: [Date!] + "Match if the list contains none of the provided dates." + excludesAll: [Date!] +} + +"Conditions on a `Timestamp` value." +input Timestamp_Filter { + "Match if the field `IS NULL`." + isNull: Boolean + "Match if the field is exactly equal to the provided value." + eq: Timestamp @fdc_oneOf(group: "eq") + "Match if the field equals the provided CEL expression." + eq_expr: Timestamp_Expr @fdc_oneOf(group: "eq") + "Match if the field equals the provided relative time." + eq_time: Timestamp_Relative @fdc_oneOf(group: "eq") + "Match if the field is not equal to the provided value." + ne: Timestamp @fdc_oneOf(group: "ne") + "Match if the field is not equal to the provided CEL expression." + ne_expr: Timestamp_Expr @fdc_oneOf(group: "ne") + "Match if the field is not equal to the provided relative time." + ne_time: Timestamp_Relative @fdc_oneOf(group: "ne") + "Match if the field value is among the provided list of values." + in: [Timestamp!] + "Match if the field value is not among the provided list of values." + nin: [Timestamp!] + "Match if the field value is greater than the provided value." + gt: Timestamp @fdc_oneOf(group: "gt") + "Match if the field value is greater than the provided CEL expression." + gt_expr: Timestamp_Expr @fdc_oneOf(group: "gt") + "Match if the field value is greater than the provided relative time." + gt_time: Timestamp_Relative @fdc_oneOf(group: "gt") + "Match if the field value is greater than or equal to the provided value." + ge: Timestamp @fdc_oneOf(group: "ge") + "Match if the field value is greater than or equal to the provided CEL expression." + ge_expr: Timestamp_Expr @fdc_oneOf(group: "ge") + "Match if the field value is greater than or equal to the provided relative time." + ge_time: Timestamp_Relative @fdc_oneOf(group: "ge") + "Match if the field value is less than the provided value." + lt: Timestamp @fdc_oneOf(group: "lt") + "Match if the field value is less than the provided CEL expression." + lt_expr: Timestamp_Expr @fdc_oneOf(group: "lt") + "Match if the field value is less than the provided relative time." + lt_time: Timestamp_Relative @fdc_oneOf(group: "lt") + "Match if the field value is less than or equal to the provided value." + le: Timestamp @fdc_oneOf(group: "le") + "Match if the field value is less than or equal to the provided CEL expression." + le_expr: Timestamp_Expr @fdc_oneOf(group: "le") + "Match if the field value is less than or equal to the provided relative time." + le_time: Timestamp_Relative @fdc_oneOf(group: "le") +} + +"Conditions on a `Timestamp` list." +input Timestamp_ListFilter { + "Match if the list contains the provided timestamp." + includes: Timestamp @fdc_oneOf(group: "includes") + "Match if the list contains the provided timestamp CEL expression." + includes_expr: Timestamp_Expr @fdc_oneOf(group: "includes") + "Match if the list contains the provided relative timestamp." + includes_time: Timestamp_Relative @fdc_oneOf(group: "includes") + "Match if the list does not contain the provided timestamp." + excludes: Timestamp @fdc_oneOf(group: "excludes") + "Match if the list does not contain the provided timestamp CEL expression." + excludes_expr: Timestamp_Expr @fdc_oneOf(group: "excludes") + "Match if the list does not contain the provided relative timestamp." + excludes_time: Timestamp_Relative @fdc_oneOf(group: "excludes") + "Match if the list contains all the provided timestamps." + includesAll: [Timestamp!] + "Match if the list contains none of the provided timestamps." + excludesAll: [Timestamp!] +} + +"Update input of a `Date` value." +input Date_Update { + "Set the field to the provided date." + set: Date @fdc_oneOf(group: "set") + "Set the field to the provided date CEL expression." + set_expr: Date_Expr @fdc_oneOf(group: "set") + "Set the field to the provided relative date." + set_date: Date_Relative @fdc_oneOf(group: "set") +} + +"Update input of a `Date` list value." +input Date_ListUpdate { + "Replace the current list with the provided list of `Date` values." + set: [Date!] + "Append the provided `Date` values to the existing list." + append: [Date!] + "Prepend the provided `Date` values to the existing list." + prepend: [Date!] + "Remove the date value at the specified index." + delete: Int + "The index of the list to perform updates." + i: Int + "Update the date value at the specified index." + update: Date +} + +"Update input of a `Timestamp` value." +input Timestamp_Update { + "Set the field to the provided timestamp." + set: Timestamp @fdc_oneOf(group: "set") + "Set the field to the provided timestamp CEL expression." + set_expr: Timestamp_Expr @fdc_oneOf(group: "set") + "Set the field to the provided relative timestamp." + set_time: Timestamp_Relative @fdc_oneOf(group: "set") +} + +"Update input of an `Timestamp` list value." +input Timestamp_ListUpdate { + "Replace the current list with the provided list of `Timestamp` values." + set: [Timestamp!] + "Append the provided `Timestamp` values to the existing list." + append: [Timestamp!] + "Prepend the provided `Timestamp` values to the existing list." + prepend: [Timestamp!] + "Remove the timestamp value at the specified index." + delete: Int + "The index of the list to perform updates." + i: Int + "Update the timestamp value at the specified index." + update: Timestamp +} + + +"A runtime-calculated `Timestamp` value relative to `now` or `at`." +input Timestamp_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { + "Match for the current time." + now: True @fdc_oneOf(group: "from", required: true) + "A specific timestamp for matching." + at: Timestamp @fdc_oneOf(group: "from", required: true) + "Add the provided duration to the base timestamp." + add: Timestamp_Duration + "Subtract the provided duration from the base timestamp." + sub: Timestamp_Duration + "Truncate the timestamp to the provided interval." + truncateTo: Timestamp_Interval +} + +input Timestamp_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { + "The number of milliseconds for the duration." + milliseconds: Int! = 0 + "The number of seconds for the duration." + seconds: Int! = 0 + "The number of minutes for the duration." + minutes: Int! = 0 + "The number of hours for the duration." + hours: Int! = 0 + "The number of days for the duration." + days: Int! = 0 + "The number of weeks for the duration." + weeks: Int! = 0 + "The number of months for the duration." + months: Int! = 0 + "The number of years for the duration." + years: Int! = 0 +} + +enum Timestamp_Interval @fdc_forbiddenAsFieldType { + "Represents a time interval of one second." + SECOND + "Represents a time interval of one minute." + MINUTE + "Represents a time interval of one hour." + HOUR + "Represents a time interval of one day." + DAY + "Represents a time interval of one week." + WEEK + "Represents a time interval of one month." + MONTH + "Represents a time interval of one year." + YEAR +} + +"A runtime-calculated Date value relative to `today` or `on`." +input Date_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { + "Match for today’s date." + today: True @fdc_oneOf(group: "from", required: true) + "A specific date for matching." + on: Date @fdc_oneOf(group: "from", required: true) + "Add the provided duration to the base date." + add: Date_Duration + "Subtract the provided duration from the base date." + sub: Date_Duration + "Truncate the date to the provided interval." + truncateTo: Date_Interval +} + +input Date_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { + "The number of days for the duration." + days: Int! = 0 + "The number of weeks for the duration." + weeks: Int! = 0 + "The number of months for the duration." + months: Int! = 0 + "The number of years for the duration." + years: Int! = 0 +} + +enum Date_Interval @fdc_forbiddenAsFieldType { + "Represents a time interval of one week." + WEEK + "Represents a time interval of one month." + MONTH + "Represents a time interval of one year." + YEAR +} + +"Update input of a `String` value." +input String_Update { + "Set the field to a provided value." + set: String @fdc_oneOf(group: "set") + "Set the field to a provided server value expression." + set_expr: String_Expr @fdc_oneOf(group: "set") +} + +"Update input of a `String` list value." +input String_ListUpdate { + "Set the list with the provided values." + set: [String!] + "Append the provided values to the existing list." + append: [String!] + "Prepend the provided values to the existing list." + prepend: [String!] +} + +"Update input of a `UUID` value." +input UUID_Update { + "Set the field to a provided UUID." + set: UUID @fdc_oneOf(group: "set") + "Set the field to a provided UUID expression." + set_expr: UUID_Expr @fdc_oneOf(group: "set") +} + +"Update input of an `ID` list value." +input UUID_ListUpdate { + "Set the list with the provided list of UUIDs." + set: [UUID!] + "Append the provided UUIDs to the existing list." + append: [UUID!] + "Prepend the provided UUIDs to the existing list." + prepend: [UUID!] +} + +"Update input of an `Int` value." +input Int_Update { + "Set the field to a provided value." + set: Int + "Increment the field by a provided value." + inc: Int + "Decrement the field by a provided value." + dec: Int +} + +"Update input of an `Int` list value." +input Int_ListUpdate { + "Set the list with the provided values." + set: [Int!] + "Append the provided list of values to the existing list." + append: [Int!] + "Prepend the provided list of values to the existing list." + prepend: [Int!] +} + +"Update input of an `Int64` value." +input Int64_Update { + "Set the field to a provided value." + set: Int64 + "Increment the field by a provided value." + inc: Int64 + "Decrement the field by a provided value." + dec: Int64 +} + +"Update input of an `Int64` list value." +input Int64_ListUpdate { + "Replace the list with the provided values." + set: [Int64!] + "Append the provided list of values to the existing list." + append: [Int64!] + "Prepend the provided list of values to the existing list." + prepend: [Int64!] +} + +"Update input of a `Float` value." +input Float_Update { + "Set the field to a provided value." + set: Float + "Increment the field by a provided value." + inc: Float + "Decrement the field by a provided value." + dec: Float +} + +"Update input of a `Float` list value." +input Float_ListUpdate { + "Set the list with the provided values." + set: [Float!] + "Append the provided list of values to the existing list." + append: [Float!] + "Prepend the provided list of values to the existing list." + prepend: [Float!] +} + +"Update input of a `Boolean` value." +input Boolean_Update { + "Set the field to a provided value." + set: Boolean +} + +"Update input of a `Boolean` list value." +input Boolean_ListUpdate { + "Set the list with the provided values." + set: [Boolean!] + "Append the provided list of values to the existing list." + append: [Boolean!] + "Prepend the provided list of values to the existing list." + prepend: [Boolean!] +} + +"Update input of an `Any` value." +input Any_Update { + "Set the field to a provided value." + set: Any +} + +"Update input of an `Any` list value." +input Any_ListUpdate { + "Set the list with the provided values." + set: [Any!] + "Append the provided list of values to the existing list." + append: [Any!] + "Prepend the provided list of values to the existing list." + prepend: [Any!] +} + +type Query { + """ + _service provides customized introspection on Firebase Data Connect Sevice. + """ + _service: _Service! +} + +""" +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] + +In the PostgreSQL table, it's stored as [`pgvector`](https://github.com/pgvector/pgvector). + +See `Vector_Embed` for how to generate text embeddings in query and mutations. +""" +scalar Vector + +""" +Defines the similarity function to use when comparing vectors in queries. + +Defaults to `INNER_PRODUCT`. + +View [all vector functions](https://github.com/pgvector/pgvector?tab=readme-ov-file#vector-functions). +""" +enum VectorSimilarityMethod { + "Measures the Euclidean (L2) distance between two vectors." + L2 + "Measures the cosine similarity between two vectors." + COSINE + "Measures the inner product(dot product) between two vectors." + INNER_PRODUCT +} + +"Conditions on a Vector value." +input Vector_Filter { + "Match if the field is exactly equal to the provided vector." + eq: Vector + "Match if the field is not equal to the provided vector." + ne: Vector + "Match if the field value is among the provided list of vectors." + in: [Vector!] + "Match if the field value is not among the provided list of vectors." + nin: [Vector!] + "Match if the field is `NULL`." + isNull: Boolean +} + +input Vector_ListFilter { + "Match if the list includes the supplied vector." + includes: Vector + "Match if the list does not include the supplied vector." + excludes: Vector + "Match if the list contains all the provided vectors." + includesAll: [Vector!] + "Match if the list contains none of the provided vectors." + excludesAll: [Vector!] +} + +"Update input of a Vector value." +input Vector_Update { + "Set the field to the provided vector value." + set: Vector @fdc_oneOf(group: "set") + "Set the field to the vector embedding result from a text input." + set_embed: Vector_Embed @fdc_oneOf(group: "set") +} + + +"Update input of a Vector list value." +input Vector_ListUpdate { + "Replace the current list with the provided list of Vector values." + set: [Vector] + "Append the provided Vector values to the existing list." + append: [Vector] + "Prepend the provided Vector values to the existing list." + prepend: [Vector] + "Delete the vector at the specified index." + delete: Int + "The index of the vector to be updated." + i: Int + "Update the vector at the specified index." + update: Vector +} + +""" +Create a vector embedding of text using the given model on Vertex AI. + +Cloud SQL for Postgresql natively integrates with [Vertex AI Text embeddings API](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text-embeddings-api) +to effectively generate text embeddings. + +If you uses [`Vector`](scalar.md#Vector) in your schema, Firebase Data Connect automatically installs +[`pgvector`](https://github.com/pgvector/pgvector) and [`google_ml_integration`](https://cloud.google.com/sql/docs/postgres/integrate-cloud-sql-with-vertex-ai) +Postgres extensions in your Cloud SQL database. + +Given a Post table with a `Vector` embedding field. + +```graphql +type Post @table { + content: String! + contentEmbedding: Vector @col(size:768) +} +``` + +NOTE: All natively supported `Vector_Embed_Model` generates vector of length `768`. + +###### Example: Insert embedding + +```graphql +mutation CreatePost($content: String!) { + post_insert(data: { + content: $content, + contentEmbedding_embed: {model: "textembedding-gecko@003", text: $content}, + }) +} +``` + +###### Example: Vector similarity Search + +```graphql +query SearchPost($query: String!) { + posts_contentEmbedding_similarity(compare_embed: {model: "textembedding-gecko@003", text: $query}) { + id + content + } +} +``` +""" +input Vector_Embed @fdc_forbiddenAsVariableType { + """ + The model to use for vector embedding. + Recommend the latest stable model: `textembedding-gecko@003`. + """ + model: Vector_Embed_Model! + "The text to generate the vector embedding from." + text: String! +} + +""" +The Vertex AI model version that is required in input `Vector_Embed`. + +It is recommended to use the latest stable model version: `textembedding-gecko@003`. + +View all supported [Vertex AI Text embeddings APIs](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text-embeddings-api). +""" +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") + @fdc_example(value: "textembedding-gecko@001", description: "An older version of the textembedding-gecko model") + @fdc_example(value: "text-embedding-004", description: "Another text embedding model") + +""" +Redact a part of the response from the client. + +Redacted fields are still evaluated for side effects (including data changes and +`@check`) and the results are still available to later steps in CEL expressions +(via `response.fieldName`). +""" +directive @redact on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +""" +Ensure this field is present and is not null or `[]`, or abort the request / transaction. + +A CEL expression, `expr` is used to test the field value. It defaults to +rejecting null and `[]` but a custom expression can be provided instead. + +If the field occurs multiple times (i.e. directly or indirectly nested under a +list), `expr` will be executed once for each occurrence and `@check` succeeds if +all values succeed. `@check` fails when the field is not present at all (i.e. +all ancestor paths contain `null` or `[]`), unless `optional` is true. + +If a `@check` fails in a mutation, the top-level field containing it will be +replaced with a partial error, whose message can be customzied via the `message` +argument. Each subsequent top-level fields will return an aborted error (i.e. +not executed). To rollback previous steps, see `@transaction`. +""" +directive @check( + """ + The CEL expression to test the field value (or values if nested under a list). + + Within the CEL expression, a special value `this` evaluates to the field that + this directive is attached to. If this field occurs multiple times because + any ancestor is a list, each occurrence is tested with `this` bound to each + value. When the field itself is a list or object, `this` follows the same + structure (including all decendants selected in case of objects). + + For any given path, if an ancestor is `null` or `[]`, the field will not be + reached and the CEL evaluation will be skipped for that path. In other words, + evaluation only takes place when `this` is `null` or non-null, but never + undefined. (See also the `optional` argument.) + """ + expr: Boolean_Expr! = "!(this in [null, []])" + """ + The error message to return to the client if the check fails. + + Defaults to "permission denied" if not specified. + """ + message: String! = "permission denied" + """ + Whether the check should pass or fail (default) when the field is not present. + + A field will not be reached at a given path if its parent or any ancestor is + `[]` or `null`. When this happens to all paths, the field will not be present + anywhere in the response tree. In other words, `expr` is evaluated 0 times. + By default, @check will automatically fail in this case. Set this argument to + `true` to make it pass even if no tests are run (a.k.a. "vacuously true"). + """ + optional: Boolean = false +) repeatable on QUERY | MUTATION | FIELD | FRAGMENT_DEFINITION | FRAGMENT_SPREAD | INLINE_FRAGMENT + +type Mutation { + """ + Run a query during the mutation and add fields into the response. + + Example: foo: query { users { id } } will add a field foo: {users: [{id: "..."}, …]} into the response JSON. + + Note: Data fetched this way can be handy for permission checks. See @check. + """ + query: Query +} + diff --git a/dataconnect/connector/connector.yaml b/dataconnect/dataconnect/connector/connector.yaml similarity index 100% rename from dataconnect/connector/connector.yaml rename to dataconnect/dataconnect/connector/connector.yaml diff --git a/dataconnect/connector/mutations.gql b/dataconnect/dataconnect/connector/mutations.gql similarity index 100% rename from dataconnect/connector/mutations.gql rename to dataconnect/dataconnect/connector/mutations.gql diff --git a/dataconnect/connector/queries.gql b/dataconnect/dataconnect/connector/queries.gql similarity index 100% rename from dataconnect/connector/queries.gql rename to dataconnect/dataconnect/connector/queries.gql diff --git a/dataconnect/dataconnect.yaml b/dataconnect/dataconnect/dataconnect.yaml similarity index 77% rename from dataconnect/dataconnect.yaml rename to dataconnect/dataconnect/dataconnect.yaml index 675381e4..300d80b1 100644 --- a/dataconnect/dataconnect.yaml +++ b/dataconnect/dataconnect/dataconnect.yaml @@ -5,8 +5,8 @@ schema: source: "./schema" datasource: postgresql: - database: "fdcdb2" + database: "fdcdb" cloudSql: - instanceId: "fdc-sql" + instanceId: "dataconnect-fdc" # schemaValidation: "COMPATIBLE" connectorDirs: ["./connector"] diff --git a/dataconnect/dataconnect/lib/movies_connector/add_favorited_movie.dart b/dataconnect/dataconnect/lib/movies_connector/add_favorited_movie.dart new file mode 100644 index 00000000..9f2a90b9 --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/add_favorited_movie.dart @@ -0,0 +1,192 @@ +part of movies_connector; + +class AddFavoritedMovieVariablesBuilder { + String movieId; + + + FirebaseDataConnect _dataConnect; + + AddFavoritedMovieVariablesBuilder(this._dataConnect, {required String this.movieId,}); + Deserializer dataDeserializer = (dynamic json) => AddFavoritedMovieData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (AddFavoritedMovieVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + MutationRef ref() { + AddFavoritedMovieVariables vars=AddFavoritedMovieVariables(movieId: movieId,); + + return _dataConnect.mutation("AddFavoritedMovie", dataDeserializer, varsSerializer, vars); + } +} + + + class AddFavoritedMovieFavoriteMovieUpsert { + + String userId; + + + String movieId; + + + + + + + AddFavoritedMovieFavoriteMovieUpsert.fromJson(dynamic json): + userId = + + nativeFromJson(json['userId']) + + + + , + + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['userId'] = + + nativeToJson(userId) + +; + + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + AddFavoritedMovieFavoriteMovieUpsert({ + + required this.userId, + + required this.movieId, + + }); +} + + + + class AddFavoritedMovieData { + + AddFavoritedMovieFavoriteMovieUpsert favorite_movie_upsert; + + + + + + + AddFavoritedMovieData.fromJson(dynamic json): + favorite_movie_upsert = + + AddFavoritedMovieFavoriteMovieUpsert.fromJson(json['favorite_movie_upsert']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['favorite_movie_upsert'] = + + favorite_movie_upsert.toJson() + +; + + + return json; + } + + AddFavoritedMovieData({ + + required this.favorite_movie_upsert, + + }); +} + + + + class AddFavoritedMovieVariables { + + String movieId; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + AddFavoritedMovieVariables.fromJson(Map json): + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + AddFavoritedMovieVariables({ + + required this.movieId, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/add_review.dart b/dataconnect/dataconnect/lib/movies_connector/add_review.dart new file mode 100644 index 00000000..1205433f --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/add_review.dart @@ -0,0 +1,240 @@ +part of movies_connector; + +class AddReviewVariablesBuilder { + String movieId; +int rating; +String reviewText; + + + FirebaseDataConnect _dataConnect; + + AddReviewVariablesBuilder(this._dataConnect, {required String this.movieId,required int this.rating,required String this.reviewText,}); + Deserializer dataDeserializer = (dynamic json) => AddReviewData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (AddReviewVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + MutationRef ref() { + AddReviewVariables vars=AddReviewVariables(movieId: movieId,rating: rating,reviewText: reviewText,); + + return _dataConnect.mutation("AddReview", dataDeserializer, varsSerializer, vars); + } +} + + + class AddReviewReviewInsert { + + String userId; + + + String movieId; + + + + + + + AddReviewReviewInsert.fromJson(dynamic json): + userId = + + nativeFromJson(json['userId']) + + + + , + + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['userId'] = + + nativeToJson(userId) + +; + + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + AddReviewReviewInsert({ + + required this.userId, + + required this.movieId, + + }); +} + + + + class AddReviewData { + + AddReviewReviewInsert review_insert; + + + + + + + AddReviewData.fromJson(dynamic json): + review_insert = + + AddReviewReviewInsert.fromJson(json['review_insert']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['review_insert'] = + + review_insert.toJson() + +; + + + return json; + } + + AddReviewData({ + + required this.review_insert, + + }); +} + + + + class AddReviewVariables { + + String movieId; + + + int rating; + + + String reviewText; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + AddReviewVariables.fromJson(Map json): + movieId = + + nativeFromJson(json['movieId']) + + + + , + + rating = + + nativeFromJson(json['rating']) + + + + , + + reviewText = + + nativeFromJson(json['reviewText']) + + + + + { + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + + json['rating'] = + + nativeToJson(rating) + +; + + + + json['reviewText'] = + + nativeToJson(reviewText) + +; + + + return json; + } + + AddReviewVariables({ + + required this.movieId, + + required this.rating, + + required this.reviewText, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/delete_favorited_movie.dart b/dataconnect/dataconnect/lib/movies_connector/delete_favorited_movie.dart new file mode 100644 index 00000000..2071ee5d --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/delete_favorited_movie.dart @@ -0,0 +1,194 @@ +part of movies_connector; + +class DeleteFavoritedMovieVariablesBuilder { + String movieId; + + + FirebaseDataConnect _dataConnect; + + DeleteFavoritedMovieVariablesBuilder(this._dataConnect, {required String this.movieId,}); + Deserializer dataDeserializer = (dynamic json) => DeleteFavoritedMovieData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (DeleteFavoritedMovieVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + MutationRef ref() { + DeleteFavoritedMovieVariables vars=DeleteFavoritedMovieVariables(movieId: movieId,); + + return _dataConnect.mutation("DeleteFavoritedMovie", dataDeserializer, varsSerializer, vars); + } +} + + + class DeleteFavoritedMovieFavoriteMovieDelete { + + String userId; + + + String movieId; + + + + + + + DeleteFavoritedMovieFavoriteMovieDelete.fromJson(dynamic json): + userId = + + nativeFromJson(json['userId']) + + + + , + + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['userId'] = + + nativeToJson(userId) + +; + + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + DeleteFavoritedMovieFavoriteMovieDelete({ + + required this.userId, + + required this.movieId, + + }); +} + + + + class DeleteFavoritedMovieData { + + DeleteFavoritedMovieFavoriteMovieDelete? favorite_movie_delete; + + + + + + + DeleteFavoritedMovieData.fromJson(dynamic json): + favorite_movie_delete = json['favorite_movie_delete'] == null ? null : + + DeleteFavoritedMovieFavoriteMovieDelete.fromJson(json['favorite_movie_delete']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (favorite_movie_delete != null) { + json['favorite_movie_delete'] = + + favorite_movie_delete!.toJson() + +; + } + + + return json; + } + + DeleteFavoritedMovieData({ + + this.favorite_movie_delete, + + }); +} + + + + class DeleteFavoritedMovieVariables { + + String movieId; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + DeleteFavoritedMovieVariables.fromJson(Map json): + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + DeleteFavoritedMovieVariables({ + + required this.movieId, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/delete_review.dart b/dataconnect/dataconnect/lib/movies_connector/delete_review.dart new file mode 100644 index 00000000..49fe10cd --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/delete_review.dart @@ -0,0 +1,194 @@ +part of movies_connector; + +class DeleteReviewVariablesBuilder { + String movieId; + + + FirebaseDataConnect _dataConnect; + + DeleteReviewVariablesBuilder(this._dataConnect, {required String this.movieId,}); + Deserializer dataDeserializer = (dynamic json) => DeleteReviewData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (DeleteReviewVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + MutationRef ref() { + DeleteReviewVariables vars=DeleteReviewVariables(movieId: movieId,); + + return _dataConnect.mutation("DeleteReview", dataDeserializer, varsSerializer, vars); + } +} + + + class DeleteReviewReviewDelete { + + String userId; + + + String movieId; + + + + + + + DeleteReviewReviewDelete.fromJson(dynamic json): + userId = + + nativeFromJson(json['userId']) + + + + , + + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['userId'] = + + nativeToJson(userId) + +; + + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + DeleteReviewReviewDelete({ + + required this.userId, + + required this.movieId, + + }); +} + + + + class DeleteReviewData { + + DeleteReviewReviewDelete? review_delete; + + + + + + + DeleteReviewData.fromJson(dynamic json): + review_delete = json['review_delete'] == null ? null : + + DeleteReviewReviewDelete.fromJson(json['review_delete']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (review_delete != null) { + json['review_delete'] = + + review_delete!.toJson() + +; + } + + + return json; + } + + DeleteReviewData({ + + this.review_delete, + + }); +} + + + + class DeleteReviewVariables { + + String movieId; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + DeleteReviewVariables.fromJson(Map json): + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + DeleteReviewVariables({ + + required this.movieId, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/get_actor_by_id.dart b/dataconnect/dataconnect/lib/movies_connector/get_actor_by_id.dart new file mode 100644 index 00000000..5400fa07 --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/get_actor_by_id.dart @@ -0,0 +1,573 @@ +part of movies_connector; + +class GetActorByIdVariablesBuilder { + String id; + + + FirebaseDataConnect _dataConnect; + + GetActorByIdVariablesBuilder(this._dataConnect, {required String this.id,}); + Deserializer dataDeserializer = (dynamic json) => GetActorByIdData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (GetActorByIdVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + QueryRef ref() { + GetActorByIdVariables vars=GetActorByIdVariables(id: id,); + + return _dataConnect.query("GetActorById", dataDeserializer, varsSerializer, vars); + } +} + + + class GetActorByIdActor { + + String id; + + + String name; + + + String imageUrl; + + + List mainActors; + + + List supportingActors; + + + + + + + GetActorByIdActor.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + name = + + nativeFromJson(json['name']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + , + + mainActors = + + + (json['mainActors'] as List) + .map((e) => GetActorByIdActorMainActors.fromJson(e)) + .toList() + + + + + , + + supportingActors = + + + (json['supportingActors'] as List) + .map((e) => GetActorByIdActorSupportingActors.fromJson(e)) + .toList() + + + + + + { + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['name'] = + + nativeToJson(name) + +; + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + + json['mainActors'] = + + + mainActors.map((e) => e.toJson()).toList() + + +; + + + + json['supportingActors'] = + + + supportingActors.map((e) => e.toJson()).toList() + + +; + + + return json; + } + + GetActorByIdActor({ + + required this.id, + + required this.name, + + required this.imageUrl, + + required this.mainActors, + + required this.supportingActors, + + }); +} + + + + class GetActorByIdActorMainActors { + + String id; + + + String title; + + + String? genre; + + + List? tags; + + + String imageUrl; + + + + + + + GetActorByIdActorMainActors.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + , + + genre = json['genre'] == null ? null : + + nativeFromJson(json['genre']) + + + + , + + tags = json['tags'] == null ? null : + + + (json['tags'] as List) + .map((e) => nativeFromJson(e)) + .toList() + + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + + { + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + + if (genre != null) { + json['genre'] = + + nativeToJson(genre) + +; + } + + + + if (tags != null) { + json['tags'] = + + + tags?.map((e) => nativeToJson(e)).toList() + + +; + } + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + return json; + } + + GetActorByIdActorMainActors({ + + required this.id, + + required this.title, + + this.genre, + + this.tags, + + required this.imageUrl, + + }); +} + + + + class GetActorByIdActorSupportingActors { + + String id; + + + String title; + + + String? genre; + + + List? tags; + + + String imageUrl; + + + + + + + GetActorByIdActorSupportingActors.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + , + + genre = json['genre'] == null ? null : + + nativeFromJson(json['genre']) + + + + , + + tags = json['tags'] == null ? null : + + + (json['tags'] as List) + .map((e) => nativeFromJson(e)) + .toList() + + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + + { + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + + if (genre != null) { + json['genre'] = + + nativeToJson(genre) + +; + } + + + + if (tags != null) { + json['tags'] = + + + tags?.map((e) => nativeToJson(e)).toList() + + +; + } + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + return json; + } + + GetActorByIdActorSupportingActors({ + + required this.id, + + required this.title, + + this.genre, + + this.tags, + + required this.imageUrl, + + }); +} + + + + class GetActorByIdData { + + GetActorByIdActor? actor; + + + + + + + GetActorByIdData.fromJson(dynamic json): + actor = json['actor'] == null ? null : + + GetActorByIdActor.fromJson(json['actor']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (actor != null) { + json['actor'] = + + actor!.toJson() + +; + } + + + return json; + } + + GetActorByIdData({ + + this.actor, + + }); +} + + + + class GetActorByIdVariables { + + String id; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + GetActorByIdVariables.fromJson(Map json): + id = + + nativeFromJson(json['id']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + return json; + } + + GetActorByIdVariables({ + + required this.id, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/get_current_user.dart b/dataconnect/dataconnect/lib/movies_connector/get_current_user.dart new file mode 100644 index 00000000..38a7e191 --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/get_current_user.dart @@ -0,0 +1,763 @@ +part of movies_connector; + +class GetCurrentUserVariablesBuilder { + + + FirebaseDataConnect _dataConnect; + + GetCurrentUserVariablesBuilder(this._dataConnect, ); + Deserializer dataDeserializer = (dynamic json) => GetCurrentUserData.fromJson(jsonDecode(json)); + + Future> execute() { + return this.ref().execute(); + } + QueryRef ref() { + + return _dataConnect.query("GetCurrentUser", dataDeserializer, emptySerializer, null); + } +} + + + class GetCurrentUserUser { + + String id; + + + String username; + + + List reviews; + + + List favoriteMovies; + + + + + + + GetCurrentUserUser.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + username = + + nativeFromJson(json['username']) + + + + , + + reviews = + + + (json['reviews'] as List) + .map((e) => GetCurrentUserUserReviews.fromJson(e)) + .toList() + + + + + , + + favoriteMovies = + + + (json['favoriteMovies'] as List) + .map((e) => GetCurrentUserUserFavoriteMovies.fromJson(e)) + .toList() + + + + + + { + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['username'] = + + nativeToJson(username) + +; + + + + json['reviews'] = + + + reviews.map((e) => e.toJson()).toList() + + +; + + + + json['favoriteMovies'] = + + + favoriteMovies.map((e) => e.toJson()).toList() + + +; + + + return json; + } + + GetCurrentUserUser({ + + required this.id, + + required this.username, + + required this.reviews, + + required this.favoriteMovies, + + }); +} + + + + class GetCurrentUserUserReviews { + + String id; + + + int? rating; + + + DateTime reviewDate; + + + String? reviewText; + + + GetCurrentUserUserReviewsMovie movie; + + + + + + + GetCurrentUserUserReviews.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + rating = json['rating'] == null ? null : + + nativeFromJson(json['rating']) + + + + , + + reviewDate = + + nativeFromJson(json['reviewDate']) + + + + , + + reviewText = json['reviewText'] == null ? null : + + nativeFromJson(json['reviewText']) + + + + , + + movie = + + GetCurrentUserUserReviewsMovie.fromJson(json['movie']) + + + + + { + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + if (rating != null) { + json['rating'] = + + nativeToJson(rating) + +; + } + + + + json['reviewDate'] = + + nativeToJson(reviewDate) + +; + + + + if (reviewText != null) { + json['reviewText'] = + + nativeToJson(reviewText) + +; + } + + + + json['movie'] = + + movie.toJson() + +; + + + return json; + } + + GetCurrentUserUserReviews({ + + required this.id, + + this.rating, + + required this.reviewDate, + + this.reviewText, + + required this.movie, + + }); +} + + + + class GetCurrentUserUserReviewsMovie { + + String id; + + + String title; + + + + + + + GetCurrentUserUserReviewsMovie.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + + { + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + return json; + } + + GetCurrentUserUserReviewsMovie({ + + required this.id, + + required this.title, + + }); +} + + + + class GetCurrentUserUserFavoriteMovies { + + GetCurrentUserUserFavoriteMoviesMovie movie; + + + + + + + GetCurrentUserUserFavoriteMovies.fromJson(dynamic json): + movie = + + GetCurrentUserUserFavoriteMoviesMovie.fromJson(json['movie']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movie'] = + + movie.toJson() + +; + + + return json; + } + + GetCurrentUserUserFavoriteMovies({ + + required this.movie, + + }); +} + + + + class GetCurrentUserUserFavoriteMoviesMovie { + + String id; + + + String title; + + + String? genre; + + + String imageUrl; + + + int? releaseYear; + + + double? rating; + + + String? description; + + + List? tags; + + + List metadata; + + + + + + + GetCurrentUserUserFavoriteMoviesMovie.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + , + + genre = json['genre'] == null ? null : + + nativeFromJson(json['genre']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + , + + releaseYear = json['releaseYear'] == null ? null : + + nativeFromJson(json['releaseYear']) + + + + , + + rating = json['rating'] == null ? null : + + nativeFromJson(json['rating']) + + + + , + + description = json['description'] == null ? null : + + nativeFromJson(json['description']) + + + + , + + tags = json['tags'] == null ? null : + + + (json['tags'] as List) + .map((e) => nativeFromJson(e)) + .toList() + + + + + , + + metadata = + + + (json['metadata'] as List) + .map((e) => GetCurrentUserUserFavoriteMoviesMovieMetadata.fromJson(e)) + .toList() + + + + + + { + + + + + + + + + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + + if (genre != null) { + json['genre'] = + + nativeToJson(genre) + +; + } + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + + if (releaseYear != null) { + json['releaseYear'] = + + nativeToJson(releaseYear) + +; + } + + + + if (rating != null) { + json['rating'] = + + nativeToJson(rating) + +; + } + + + + if (description != null) { + json['description'] = + + nativeToJson(description) + +; + } + + + + if (tags != null) { + json['tags'] = + + + tags?.map((e) => nativeToJson(e)).toList() + + +; + } + + + + json['metadata'] = + + + metadata.map((e) => e.toJson()).toList() + + +; + + + return json; + } + + GetCurrentUserUserFavoriteMoviesMovie({ + + required this.id, + + required this.title, + + this.genre, + + required this.imageUrl, + + this.releaseYear, + + this.rating, + + this.description, + + this.tags, + + required this.metadata, + + }); +} + + + + class GetCurrentUserUserFavoriteMoviesMovieMetadata { + + String? director; + + + + + + + GetCurrentUserUserFavoriteMoviesMovieMetadata.fromJson(dynamic json): + director = json['director'] == null ? null : + + nativeFromJson(json['director']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (director != null) { + json['director'] = + + nativeToJson(director) + +; + } + + + return json; + } + + GetCurrentUserUserFavoriteMoviesMovieMetadata({ + + this.director, + + }); +} + + + + class GetCurrentUserData { + + GetCurrentUserUser? user; + + + + + + + GetCurrentUserData.fromJson(dynamic json): + user = json['user'] == null ? null : + + GetCurrentUserUser.fromJson(json['user']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (user != null) { + json['user'] = + + user!.toJson() + +; + } + + + return json; + } + + GetCurrentUserData({ + + this.user, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/get_if_favorited_movie.dart b/dataconnect/dataconnect/lib/movies_connector/get_if_favorited_movie.dart new file mode 100644 index 00000000..901fb84e --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/get_if_favorited_movie.dart @@ -0,0 +1,171 @@ +part of movies_connector; + +class GetIfFavoritedMovieVariablesBuilder { + String movieId; + + + FirebaseDataConnect _dataConnect; + + GetIfFavoritedMovieVariablesBuilder(this._dataConnect, {required String this.movieId,}); + Deserializer dataDeserializer = (dynamic json) => GetIfFavoritedMovieData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (GetIfFavoritedMovieVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + QueryRef ref() { + GetIfFavoritedMovieVariables vars=GetIfFavoritedMovieVariables(movieId: movieId,); + + return _dataConnect.query("GetIfFavoritedMovie", dataDeserializer, varsSerializer, vars); + } +} + + + class GetIfFavoritedMovieFavoriteMovie { + + String movieId; + + + + + + + GetIfFavoritedMovieFavoriteMovie.fromJson(dynamic json): + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + GetIfFavoritedMovieFavoriteMovie({ + + required this.movieId, + + }); +} + + + + class GetIfFavoritedMovieData { + + GetIfFavoritedMovieFavoriteMovie? favorite_movie; + + + + + + + GetIfFavoritedMovieData.fromJson(dynamic json): + favorite_movie = json['favorite_movie'] == null ? null : + + GetIfFavoritedMovieFavoriteMovie.fromJson(json['favorite_movie']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (favorite_movie != null) { + json['favorite_movie'] = + + favorite_movie!.toJson() + +; + } + + + return json; + } + + GetIfFavoritedMovieData({ + + this.favorite_movie, + + }); +} + + + + class GetIfFavoritedMovieVariables { + + String movieId; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + GetIfFavoritedMovieVariables.fromJson(Map json): + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + GetIfFavoritedMovieVariables({ + + required this.movieId, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/get_movie_by_id.dart b/dataconnect/dataconnect/lib/movies_connector/get_movie_by_id.dart new file mode 100644 index 00000000..56cc681c --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/get_movie_by_id.dart @@ -0,0 +1,912 @@ +part of movies_connector; + +class GetMovieByIdVariablesBuilder { + String id; + + + FirebaseDataConnect _dataConnect; + + GetMovieByIdVariablesBuilder(this._dataConnect, {required String this.id,}); + Deserializer dataDeserializer = (dynamic json) => GetMovieByIdData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (GetMovieByIdVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + QueryRef ref() { + GetMovieByIdVariables vars=GetMovieByIdVariables(id: id,); + + return _dataConnect.query("GetMovieById", dataDeserializer, varsSerializer, vars); + } +} + + + class GetMovieByIdMovie { + + String id; + + + String title; + + + String imageUrl; + + + int? releaseYear; + + + String? genre; + + + double? rating; + + + String? description; + + + List? tags; + + + List metadata; + + + List mainActors; + + + List supportingActors; + + + List reviews; + + + + + + + GetMovieByIdMovie.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + , + + releaseYear = json['releaseYear'] == null ? null : + + nativeFromJson(json['releaseYear']) + + + + , + + genre = json['genre'] == null ? null : + + nativeFromJson(json['genre']) + + + + , + + rating = json['rating'] == null ? null : + + nativeFromJson(json['rating']) + + + + , + + description = json['description'] == null ? null : + + nativeFromJson(json['description']) + + + + , + + tags = json['tags'] == null ? null : + + + (json['tags'] as List) + .map((e) => nativeFromJson(e)) + .toList() + + + + + , + + metadata = + + + (json['metadata'] as List) + .map((e) => GetMovieByIdMovieMetadata.fromJson(e)) + .toList() + + + + + , + + mainActors = + + + (json['mainActors'] as List) + .map((e) => GetMovieByIdMovieMainActors.fromJson(e)) + .toList() + + + + + , + + supportingActors = + + + (json['supportingActors'] as List) + .map((e) => GetMovieByIdMovieSupportingActors.fromJson(e)) + .toList() + + + + + , + + reviews = + + + (json['reviews'] as List) + .map((e) => GetMovieByIdMovieReviews.fromJson(e)) + .toList() + + + + + + { + + + + + + + + + + + + + + + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + + if (releaseYear != null) { + json['releaseYear'] = + + nativeToJson(releaseYear) + +; + } + + + + if (genre != null) { + json['genre'] = + + nativeToJson(genre) + +; + } + + + + if (rating != null) { + json['rating'] = + + nativeToJson(rating) + +; + } + + + + if (description != null) { + json['description'] = + + nativeToJson(description) + +; + } + + + + if (tags != null) { + json['tags'] = + + + tags?.map((e) => nativeToJson(e)).toList() + + +; + } + + + + json['metadata'] = + + + metadata.map((e) => e.toJson()).toList() + + +; + + + + json['mainActors'] = + + + mainActors.map((e) => e.toJson()).toList() + + +; + + + + json['supportingActors'] = + + + supportingActors.map((e) => e.toJson()).toList() + + +; + + + + json['reviews'] = + + + reviews.map((e) => e.toJson()).toList() + + +; + + + return json; + } + + GetMovieByIdMovie({ + + required this.id, + + required this.title, + + required this.imageUrl, + + this.releaseYear, + + this.genre, + + this.rating, + + this.description, + + this.tags, + + required this.metadata, + + required this.mainActors, + + required this.supportingActors, + + required this.reviews, + + }); +} + + + + class GetMovieByIdMovieMetadata { + + String? director; + + + + + + + GetMovieByIdMovieMetadata.fromJson(dynamic json): + director = json['director'] == null ? null : + + nativeFromJson(json['director']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (director != null) { + json['director'] = + + nativeToJson(director) + +; + } + + + return json; + } + + GetMovieByIdMovieMetadata({ + + this.director, + + }); +} + + + + class GetMovieByIdMovieMainActors { + + String id; + + + String name; + + + String imageUrl; + + + + + + + GetMovieByIdMovieMainActors.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + name = + + nativeFromJson(json['name']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + + { + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['name'] = + + nativeToJson(name) + +; + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + return json; + } + + GetMovieByIdMovieMainActors({ + + required this.id, + + required this.name, + + required this.imageUrl, + + }); +} + + + + class GetMovieByIdMovieSupportingActors { + + String id; + + + String name; + + + String imageUrl; + + + + + + + GetMovieByIdMovieSupportingActors.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + name = + + nativeFromJson(json['name']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + + { + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['name'] = + + nativeToJson(name) + +; + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + return json; + } + + GetMovieByIdMovieSupportingActors({ + + required this.id, + + required this.name, + + required this.imageUrl, + + }); +} + + + + class GetMovieByIdMovieReviews { + + String id; + + + String? reviewText; + + + DateTime reviewDate; + + + int? rating; + + + GetMovieByIdMovieReviewsUser user; + + + + + + + GetMovieByIdMovieReviews.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + reviewText = json['reviewText'] == null ? null : + + nativeFromJson(json['reviewText']) + + + + , + + reviewDate = + + nativeFromJson(json['reviewDate']) + + + + , + + rating = json['rating'] == null ? null : + + nativeFromJson(json['rating']) + + + + , + + user = + + GetMovieByIdMovieReviewsUser.fromJson(json['user']) + + + + + { + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + if (reviewText != null) { + json['reviewText'] = + + nativeToJson(reviewText) + +; + } + + + + json['reviewDate'] = + + nativeToJson(reviewDate) + +; + + + + if (rating != null) { + json['rating'] = + + nativeToJson(rating) + +; + } + + + + json['user'] = + + user.toJson() + +; + + + return json; + } + + GetMovieByIdMovieReviews({ + + required this.id, + + this.reviewText, + + required this.reviewDate, + + this.rating, + + required this.user, + + }); +} + + + + class GetMovieByIdMovieReviewsUser { + + String id; + + + String username; + + + + + + + GetMovieByIdMovieReviewsUser.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + username = + + nativeFromJson(json['username']) + + + + + { + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['username'] = + + nativeToJson(username) + +; + + + return json; + } + + GetMovieByIdMovieReviewsUser({ + + required this.id, + + required this.username, + + }); +} + + + + class GetMovieByIdData { + + GetMovieByIdMovie? movie; + + + + + + + GetMovieByIdData.fromJson(dynamic json): + movie = json['movie'] == null ? null : + + GetMovieByIdMovie.fromJson(json['movie']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (movie != null) { + json['movie'] = + + movie!.toJson() + +; + } + + + return json; + } + + GetMovieByIdData({ + + this.movie, + + }); +} + + + + class GetMovieByIdVariables { + + String id; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + GetMovieByIdVariables.fromJson(Map json): + id = + + nativeFromJson(json['id']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + return json; + } + + GetMovieByIdVariables({ + + required this.id, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/list_movies.dart b/dataconnect/dataconnect/lib/movies_connector/list_movies.dart new file mode 100644 index 00000000..57399267 --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/list_movies.dart @@ -0,0 +1,403 @@ +part of movies_connector; + +class ListMoviesVariablesBuilder { + Optional _orderByRating = Optional.optional(orderDirectionDeserializer, enumSerializer); +Optional _orderByReleaseYear = Optional.optional(orderDirectionDeserializer, enumSerializer); +Optional _limit = Optional.optional(nativeFromJson, nativeToJson); + + + FirebaseDataConnect _dataConnect; + ListMoviesVariablesBuilder orderByRating(OrderDirection? t) { +this._orderByRating.value = t; +return this; +} +ListMoviesVariablesBuilder orderByReleaseYear(OrderDirection? t) { +this._orderByReleaseYear.value = t; +return this; +} +ListMoviesVariablesBuilder limit(int? t) { +this._limit.value = t; +return this; +} + + ListMoviesVariablesBuilder(this._dataConnect, ); + Deserializer dataDeserializer = (dynamic json) => ListMoviesData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (ListMoviesVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + QueryRef ref() { + ListMoviesVariables vars=ListMoviesVariables(orderByRating: _orderByRating,orderByReleaseYear: _orderByReleaseYear,limit: _limit,); + + return _dataConnect.query("ListMovies", dataDeserializer, varsSerializer, vars); + } +} + + + class ListMoviesMovies { + + String id; + + + String title; + + + String imageUrl; + + + int? releaseYear; + + + String? genre; + + + double? rating; + + + List? tags; + + + String? description; + + + + + + + ListMoviesMovies.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + , + + releaseYear = json['releaseYear'] == null ? null : + + nativeFromJson(json['releaseYear']) + + + + , + + genre = json['genre'] == null ? null : + + nativeFromJson(json['genre']) + + + + , + + rating = json['rating'] == null ? null : + + nativeFromJson(json['rating']) + + + + , + + tags = json['tags'] == null ? null : + + + (json['tags'] as List) + .map((e) => nativeFromJson(e)) + .toList() + + + + + , + + description = json['description'] == null ? null : + + nativeFromJson(json['description']) + + + + + { + + + + + + + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + + if (releaseYear != null) { + json['releaseYear'] = + + nativeToJson(releaseYear) + +; + } + + + + if (genre != null) { + json['genre'] = + + nativeToJson(genre) + +; + } + + + + if (rating != null) { + json['rating'] = + + nativeToJson(rating) + +; + } + + + + if (tags != null) { + json['tags'] = + + + tags?.map((e) => nativeToJson(e)).toList() + + +; + } + + + + if (description != null) { + json['description'] = + + nativeToJson(description) + +; + } + + + return json; + } + + ListMoviesMovies({ + + required this.id, + + required this.title, + + required this.imageUrl, + + this.releaseYear, + + this.genre, + + this.rating, + + this.tags, + + this.description, + + }); +} + + + + class ListMoviesData { + + List movies; + + + + + + + ListMoviesData.fromJson(dynamic json): + movies = + + + (json['movies'] as List) + .map((e) => ListMoviesMovies.fromJson(e)) + .toList() + + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movies'] = + + + movies.map((e) => e.toJson()).toList() + + +; + + + return json; + } + + ListMoviesData({ + + required this.movies, + + }); +} + + + + class ListMoviesVariables { + + late OptionalorderByRating; + + + late OptionalorderByReleaseYear; + + + late Optionallimit; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + ListMoviesVariables.fromJson(Map json) { + + + orderByRating = Optional.optional(orderDirectionDeserializer, enumSerializer); + orderByRating.value = json['orderByRating'] == null ? null : + + OrderDirection.values.byName(json['orderByRating']) + +; + + + + orderByReleaseYear = Optional.optional(orderDirectionDeserializer, enumSerializer); + orderByReleaseYear.value = json['orderByReleaseYear'] == null ? null : + + OrderDirection.values.byName(json['orderByReleaseYear']) + +; + + + + limit = Optional.optional(nativeFromJson, nativeToJson); + limit.value = json['limit'] == null ? null : + + nativeFromJson(json['limit']) + +; + + + } + + + Map toJson() { + Map json = {}; + + + if(orderByRating.state == OptionalState.set) { + json['orderByRating'] = orderByRating.toJson(); + } + + + + if(orderByReleaseYear.state == OptionalState.set) { + json['orderByReleaseYear'] = orderByReleaseYear.toJson(); + } + + + + if(limit.state == OptionalState.set) { + json['limit'] = limit.toJson(); + } + + + return json; + } + + ListMoviesVariables({ + + required this.orderByRating, + + required this.orderByReleaseYear, + + required this.limit, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/movies.dart b/dataconnect/dataconnect/lib/movies_connector/movies.dart new file mode 100644 index 00000000..b7fbdaa8 --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/movies.dart @@ -0,0 +1,129 @@ +library movies_connector; +import 'package:firebase_data_connect/firebase_data_connect.dart'; +import 'dart:convert'; + +part 'upsert_user.dart'; + +part 'add_favorited_movie.dart'; + +part 'delete_favorited_movie.dart'; + +part 'add_review.dart'; + +part 'update_review.dart'; + +part 'delete_review.dart'; + +part 'list_movies.dart'; + +part 'get_movie_by_id.dart'; + +part 'get_actor_by_id.dart'; + +part 'get_current_user.dart'; + +part 'get_if_favorited_movie.dart'; + +part 'search_all.dart'; + + + + enum OrderDirection { + + ASC, + + DESC, + + } + OrderDirection orderDirectionDeserializer(dynamic data) { + return OrderDirection.values.byName(data); + } + + + +String enumSerializer(Enum e) { + return e.name; +} + + + +class MoviesConnector { + + + UpsertUserVariablesBuilder upsertUser ({required String username,}) { + return UpsertUserVariablesBuilder(dataConnect, username: username,); + } + + + AddFavoritedMovieVariablesBuilder addFavoritedMovie ({required String movieId,}) { + return AddFavoritedMovieVariablesBuilder(dataConnect, movieId: movieId,); + } + + + DeleteFavoritedMovieVariablesBuilder deleteFavoritedMovie ({required String movieId,}) { + return DeleteFavoritedMovieVariablesBuilder(dataConnect, movieId: movieId,); + } + + + AddReviewVariablesBuilder addReview ({required String movieId,required int rating,required String reviewText,}) { + return AddReviewVariablesBuilder(dataConnect, movieId: movieId,rating: rating,reviewText: reviewText,); + } + + + UpdateReviewVariablesBuilder updateReview ({required String movieId,required int rating,required String reviewText,}) { + return UpdateReviewVariablesBuilder(dataConnect, movieId: movieId,rating: rating,reviewText: reviewText,); + } + + + DeleteReviewVariablesBuilder deleteReview ({required String movieId,}) { + return DeleteReviewVariablesBuilder(dataConnect, movieId: movieId,); + } + + + ListMoviesVariablesBuilder listMovies () { + return ListMoviesVariablesBuilder(dataConnect, ); + } + + + GetMovieByIdVariablesBuilder getMovieById ({required String id,}) { + return GetMovieByIdVariablesBuilder(dataConnect, id: id,); + } + + + GetActorByIdVariablesBuilder getActorById ({required String id,}) { + return GetActorByIdVariablesBuilder(dataConnect, id: id,); + } + + + GetCurrentUserVariablesBuilder getCurrentUser () { + return GetCurrentUserVariablesBuilder(dataConnect, ); + } + + + GetIfFavoritedMovieVariablesBuilder getIfFavoritedMovie ({required String movieId,}) { + return GetIfFavoritedMovieVariablesBuilder(dataConnect, movieId: movieId,); + } + + + SearchAllVariablesBuilder searchAll ({required int minYear,required int maxYear,required double minRating,required double maxRating,required String genre,}) { + return SearchAllVariablesBuilder(dataConnect, minYear: minYear,maxYear: maxYear,minRating: minRating,maxRating: maxRating,genre: genre,); + } + + + static ConnectorConfig connectorConfig = ConnectorConfig( + 'us-central1', + 'movies', + 'dataconnect', + ); + + MoviesConnector({required this.dataConnect}); + static MoviesConnector get instance { + return MoviesConnector( + dataConnect: FirebaseDataConnect.instanceFor( + connectorConfig: connectorConfig, + sdkType: CallerSDKType.generated)); + } + + FirebaseDataConnect dataConnect; +} + diff --git a/dataconnect/dataconnect/lib/movies_connector/search_all.dart b/dataconnect/dataconnect/lib/movies_connector/search_all.dart new file mode 100644 index 00000000..27803d0a --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/search_all.dart @@ -0,0 +1,1021 @@ +part of movies_connector; + +class SearchAllVariablesBuilder { + Optional _input = Optional.optional(nativeFromJson, nativeToJson); +int minYear; +int maxYear; +double minRating; +double maxRating; +String genre; + + + FirebaseDataConnect _dataConnect; + SearchAllVariablesBuilder input(String? t) { +this._input.value = t; +return this; +} + + SearchAllVariablesBuilder(this._dataConnect, {required int this.minYear,required int this.maxYear,required double this.minRating,required double this.maxRating,required String this.genre,}); + Deserializer dataDeserializer = (dynamic json) => SearchAllData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (SearchAllVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + QueryRef ref() { + SearchAllVariables vars=SearchAllVariables(input: _input,minYear: minYear,maxYear: maxYear,minRating: minRating,maxRating: maxRating,genre: genre,); + + return _dataConnect.query("SearchAll", dataDeserializer, varsSerializer, vars); + } +} + + + class SearchAllMoviesMatchingTitle { + + String id; + + + String title; + + + String? genre; + + + double? rating; + + + String imageUrl; + + + + + + + SearchAllMoviesMatchingTitle.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + , + + genre = json['genre'] == null ? null : + + nativeFromJson(json['genre']) + + + + , + + rating = json['rating'] == null ? null : + + nativeFromJson(json['rating']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + + { + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + + if (genre != null) { + json['genre'] = + + nativeToJson(genre) + +; + } + + + + if (rating != null) { + json['rating'] = + + nativeToJson(rating) + +; + } + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + return json; + } + + SearchAllMoviesMatchingTitle({ + + required this.id, + + required this.title, + + this.genre, + + this.rating, + + required this.imageUrl, + + }); +} + + + + class SearchAllMoviesMatchingDescription { + + String id; + + + String title; + + + String? genre; + + + double? rating; + + + String imageUrl; + + + + + + + SearchAllMoviesMatchingDescription.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + , + + genre = json['genre'] == null ? null : + + nativeFromJson(json['genre']) + + + + , + + rating = json['rating'] == null ? null : + + nativeFromJson(json['rating']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + + { + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + + if (genre != null) { + json['genre'] = + + nativeToJson(genre) + +; + } + + + + if (rating != null) { + json['rating'] = + + nativeToJson(rating) + +; + } + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + return json; + } + + SearchAllMoviesMatchingDescription({ + + required this.id, + + required this.title, + + this.genre, + + this.rating, + + required this.imageUrl, + + }); +} + + + + class SearchAllActorsMatchingName { + + String id; + + + String name; + + + String imageUrl; + + + + + + + SearchAllActorsMatchingName.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + name = + + nativeFromJson(json['name']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + + { + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['name'] = + + nativeToJson(name) + +; + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + return json; + } + + SearchAllActorsMatchingName({ + + required this.id, + + required this.name, + + required this.imageUrl, + + }); +} + + + + class SearchAllReviewsMatchingText { + + String id; + + + int? rating; + + + String? reviewText; + + + DateTime reviewDate; + + + SearchAllReviewsMatchingTextMovie movie; + + + SearchAllReviewsMatchingTextUser user; + + + + + + + SearchAllReviewsMatchingText.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + rating = json['rating'] == null ? null : + + nativeFromJson(json['rating']) + + + + , + + reviewText = json['reviewText'] == null ? null : + + nativeFromJson(json['reviewText']) + + + + , + + reviewDate = + + nativeFromJson(json['reviewDate']) + + + + , + + movie = + + SearchAllReviewsMatchingTextMovie.fromJson(json['movie']) + + + + , + + user = + + SearchAllReviewsMatchingTextUser.fromJson(json['user']) + + + + + { + + + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + if (rating != null) { + json['rating'] = + + nativeToJson(rating) + +; + } + + + + if (reviewText != null) { + json['reviewText'] = + + nativeToJson(reviewText) + +; + } + + + + json['reviewDate'] = + + nativeToJson(reviewDate) + +; + + + + json['movie'] = + + movie.toJson() + +; + + + + json['user'] = + + user.toJson() + +; + + + return json; + } + + SearchAllReviewsMatchingText({ + + required this.id, + + this.rating, + + this.reviewText, + + required this.reviewDate, + + required this.movie, + + required this.user, + + }); +} + + + + class SearchAllReviewsMatchingTextMovie { + + String id; + + + String title; + + + + + + + SearchAllReviewsMatchingTextMovie.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + + { + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + return json; + } + + SearchAllReviewsMatchingTextMovie({ + + required this.id, + + required this.title, + + }); +} + + + + class SearchAllReviewsMatchingTextUser { + + String id; + + + String username; + + + + + + + SearchAllReviewsMatchingTextUser.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + username = + + nativeFromJson(json['username']) + + + + + { + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['username'] = + + nativeToJson(username) + +; + + + return json; + } + + SearchAllReviewsMatchingTextUser({ + + required this.id, + + required this.username, + + }); +} + + + + class SearchAllData { + + List moviesMatchingTitle; + + + List moviesMatchingDescription; + + + List actorsMatchingName; + + + List reviewsMatchingText; + + + + + + + SearchAllData.fromJson(dynamic json): + moviesMatchingTitle = + + + (json['moviesMatchingTitle'] as List) + .map((e) => SearchAllMoviesMatchingTitle.fromJson(e)) + .toList() + + + + + , + + moviesMatchingDescription = + + + (json['moviesMatchingDescription'] as List) + .map((e) => SearchAllMoviesMatchingDescription.fromJson(e)) + .toList() + + + + + , + + actorsMatchingName = + + + (json['actorsMatchingName'] as List) + .map((e) => SearchAllActorsMatchingName.fromJson(e)) + .toList() + + + + + , + + reviewsMatchingText = + + + (json['reviewsMatchingText'] as List) + .map((e) => SearchAllReviewsMatchingText.fromJson(e)) + .toList() + + + + + + { + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['moviesMatchingTitle'] = + + + moviesMatchingTitle.map((e) => e.toJson()).toList() + + +; + + + + json['moviesMatchingDescription'] = + + + moviesMatchingDescription.map((e) => e.toJson()).toList() + + +; + + + + json['actorsMatchingName'] = + + + actorsMatchingName.map((e) => e.toJson()).toList() + + +; + + + + json['reviewsMatchingText'] = + + + reviewsMatchingText.map((e) => e.toJson()).toList() + + +; + + + return json; + } + + SearchAllData({ + + required this.moviesMatchingTitle, + + required this.moviesMatchingDescription, + + required this.actorsMatchingName, + + required this.reviewsMatchingText, + + }); +} + + + + class SearchAllVariables { + + late Optionalinput; + + + int minYear; + + + int maxYear; + + + double minRating; + + + double maxRating; + + + String genre; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + SearchAllVariables.fromJson(Map json): + minYear = + + nativeFromJson(json['minYear']) + + + + , + + maxYear = + + nativeFromJson(json['maxYear']) + + + + , + + minRating = + + nativeFromJson(json['minRating']) + + + + , + + maxRating = + + nativeFromJson(json['maxRating']) + + + + , + + genre = + + nativeFromJson(json['genre']) + + + + + { + + + input = Optional.optional(nativeFromJson, nativeToJson); + input.value = json['input'] == null ? null : + + nativeFromJson(json['input']) + +; + + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + if(input.state == OptionalState.set) { + json['input'] = input.toJson(); + } + + + + json['minYear'] = + + nativeToJson(minYear) + +; + + + + json['maxYear'] = + + nativeToJson(maxYear) + +; + + + + json['minRating'] = + + nativeToJson(minRating) + +; + + + + json['maxRating'] = + + nativeToJson(maxRating) + +; + + + + json['genre'] = + + nativeToJson(genre) + +; + + + return json; + } + + SearchAllVariables({ + + required this.input, + + required this.minYear, + + required this.maxYear, + + required this.minRating, + + required this.maxRating, + + required this.genre, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/update_review.dart b/dataconnect/dataconnect/lib/movies_connector/update_review.dart new file mode 100644 index 00000000..bbd614a2 --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/update_review.dart @@ -0,0 +1,242 @@ +part of movies_connector; + +class UpdateReviewVariablesBuilder { + String movieId; +int rating; +String reviewText; + + + FirebaseDataConnect _dataConnect; + + UpdateReviewVariablesBuilder(this._dataConnect, {required String this.movieId,required int this.rating,required String this.reviewText,}); + Deserializer dataDeserializer = (dynamic json) => UpdateReviewData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (UpdateReviewVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + MutationRef ref() { + UpdateReviewVariables vars=UpdateReviewVariables(movieId: movieId,rating: rating,reviewText: reviewText,); + + return _dataConnect.mutation("UpdateReview", dataDeserializer, varsSerializer, vars); + } +} + + + class UpdateReviewReviewUpdate { + + String userId; + + + String movieId; + + + + + + + UpdateReviewReviewUpdate.fromJson(dynamic json): + userId = + + nativeFromJson(json['userId']) + + + + , + + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['userId'] = + + nativeToJson(userId) + +; + + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + UpdateReviewReviewUpdate({ + + required this.userId, + + required this.movieId, + + }); +} + + + + class UpdateReviewData { + + UpdateReviewReviewUpdate? review_update; + + + + + + + UpdateReviewData.fromJson(dynamic json): + review_update = json['review_update'] == null ? null : + + UpdateReviewReviewUpdate.fromJson(json['review_update']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (review_update != null) { + json['review_update'] = + + review_update!.toJson() + +; + } + + + return json; + } + + UpdateReviewData({ + + this.review_update, + + }); +} + + + + class UpdateReviewVariables { + + String movieId; + + + int rating; + + + String reviewText; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + UpdateReviewVariables.fromJson(Map json): + movieId = + + nativeFromJson(json['movieId']) + + + + , + + rating = + + nativeFromJson(json['rating']) + + + + , + + reviewText = + + nativeFromJson(json['reviewText']) + + + + + { + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + + json['rating'] = + + nativeToJson(rating) + +; + + + + json['reviewText'] = + + nativeToJson(reviewText) + +; + + + return json; + } + + UpdateReviewVariables({ + + required this.movieId, + + required this.rating, + + required this.reviewText, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/upsert_user.dart b/dataconnect/dataconnect/lib/movies_connector/upsert_user.dart new file mode 100644 index 00000000..16d90738 --- /dev/null +++ b/dataconnect/dataconnect/lib/movies_connector/upsert_user.dart @@ -0,0 +1,169 @@ +part of movies_connector; + +class UpsertUserVariablesBuilder { + String username; + + + FirebaseDataConnect _dataConnect; + + UpsertUserVariablesBuilder(this._dataConnect, {required String this.username,}); + Deserializer dataDeserializer = (dynamic json) => UpsertUserData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (UpsertUserVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + MutationRef ref() { + UpsertUserVariables vars=UpsertUserVariables(username: username,); + + return _dataConnect.mutation("UpsertUser", dataDeserializer, varsSerializer, vars); + } +} + + + class UpsertUserUserUpsert { + + String id; + + + + + + + UpsertUserUserUpsert.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + return json; + } + + UpsertUserUserUpsert({ + + required this.id, + + }); +} + + + + class UpsertUserData { + + UpsertUserUserUpsert user_upsert; + + + + + + + UpsertUserData.fromJson(dynamic json): + user_upsert = + + UpsertUserUserUpsert.fromJson(json['user_upsert']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['user_upsert'] = + + user_upsert.toJson() + +; + + + return json; + } + + UpsertUserData({ + + required this.user_upsert, + + }); +} + + + + class UpsertUserVariables { + + String username; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + UpsertUserVariables.fromJson(Map json): + username = + + nativeFromJson(json['username']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['username'] = + + nativeToJson(username) + +; + + + return json; + } + + UpsertUserVariables({ + + required this.username, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/moviedata_insert.gql b/dataconnect/dataconnect/moviedata_insert.gql new file mode 100644 index 00000000..2f205012 --- /dev/null +++ b/dataconnect/dataconnect/moviedata_insert.gql @@ -0,0 +1,687 @@ +mutation { + movie_insertMany( + data: [ + { + id: "550e8400-e29b-41d4-a716-446655440000" + title: "Quantum Paradox" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fquantum_paradox.jpeg?alt=media&token=4142e2a1-bf43-43b5-b7cf-6616be3fd4e3" + releaseYear: 2025 + genre: "sci-fi" + rating: 7.9 + description: "A group of scientists accidentally open a portal to a parallel universe, causing a rift in time. As the team races to close the portal, they encounter alternate versions of themselves, leading to shocking revelations." + tags: ["thriller", "adventure"] + } + { + id: "550e8400-e29b-41d4-a716-446655440001" + title: "The Lone Outlaw" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Flone_outlaw.jpeg?alt=media&token=15525ffc-208f-4b59-b506-ae8348e06e85" + releaseYear: 2023 + genre: "western" + rating: 8.2 + description: "In the lawless Wild West, a mysterious gunslinger with a hidden past takes on a corrupt sheriff and his band of outlaws to bring justice to a small town." + tags: ["action", "drama"] + } + { + id: "550e8400-e29b-41d4-a716-446655440002" + title: "Celestial Harmony" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fcelestial_harmony.jpeg?alt=media&token=3edf1cf9-c2f5-4c75-9819-36ff6a734c9a" + releaseYear: 2024 + genre: "romance" + rating: 7.5 + description: "Two astronauts, stationed on a remote space station, fall in love amidst the isolation of deep space. But when a mysterious signal disrupts their communication, they must find a way to reconnect and survive." + tags: ["romance", "sci-fi"] + } + { + id: "550e8400-e29b-41d4-a716-446655440003" + title: "Noir Mystique" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fnoir_mystique.jpeg?alt=media&token=3299adba-cb98-4302-8b23-aeb679a4f913" + releaseYear: 2022 + genre: "mystery" + rating: 8.0 + description: "A private detective gets caught up in a web of lies, deception, and betrayal while investigating the disappearance of a famous actress in 1940s Hollywood." + tags: ["crime", "thriller"] + } + { + id: "550e8400-e29b-41d4-a716-446655440004" + title: "The Forgotten Island" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fforgotten_island.jpeg?alt=media&token=bc2b16e1-caed-4649-952c-73b6113f205c" + releaseYear: 2025 + genre: "adventure" + rating: 7.6 + description: "An explorer leads an expedition to a remote island rumored to be home to mythical creatures. As the team ventures deeper into the island, they uncover secrets that change the course of history." + tags: ["adventure", "fantasy"] + } + { + id: "550e8400-e29b-41d4-a716-446655440005" + title: "Digital Nightmare" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fdigital_nightmare.jpeg?alt=media&token=335ec842-1ca4-4b09-abd1-e96d9f5c0c2f" + releaseYear: 2024 + genre: "horror" + rating: 6.9 + description: "A tech-savvy teenager discovers a cursed app that brings nightmares to life. As the horrors of the digital world cross into reality, she must find a way to break the curse before it's too late." + tags: ["horror", "thriller"] + } + { + id: "550e8400-e29b-41d4-a716-446655440006" + title: "Eclipse of Destiny" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Feclipse_destiny.jpeg?alt=media&token=346649b3-cb5c-4d7e-b0d4-6f02e3df5959" + releaseYear: 2026 + genre: "fantasy" + rating: 8.1 + description: "In a kingdom on the brink of war, a prophecy speaks of an eclipse that will grant power to the rightful ruler. As factions vie for control, a young warrior must decide where his true loyalty lies." + tags: ["fantasy", "adventure"] + } + { + id: "550e8400-e29b-41d4-a716-446655440007" + title: "Heart of Steel" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fheart_steel.jpeg?alt=media&token=17883d71-329b-415a-86f8-dd4d9e941d7f" + releaseYear: 2023 + genre: "sci-fi" + rating: 7.7 + description: "A brilliant scientist creates a robot with a human heart. As the robot struggles to understand emotions, it becomes entangled in a plot that could change the fate of humanity." + tags: ["sci-fi", "drama"] + } + { + id: "550e8400-e29b-41d4-a716-446655440008" + title: "Rise of the Crimson Empire" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Frise_crimson_empire.jpeg?alt=media&token=6faa73ad-7504-4146-8f3a-50b90f607f33" + releaseYear: 2025 + genre: "action" + rating: 8.4 + description: "A legendary warrior rises to challenge the tyrannical rule of a powerful empire. As rebellion brews, the warrior must unite different factions to lead an uprising." + tags: ["action", "adventure"] + } + { + id: "550e8400-e29b-41d4-a716-446655440009" + title: "Silent Waves" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fsilent_waves.jpeg?alt=media&token=bd626bf1-ec60-4e57-aa07-87ba14e35bb7" + releaseYear: 2024 + genre: "drama" + rating: 8.2 + description: "A talented pianist, who loses his hearing in a tragic accident, must rediscover his passion for music with the help of a young music teacher who believes in him." + tags: ["drama", "music"] + } + { + id: "550e8400-e29b-41d4-a716-446655440010" + title: "Echoes of the Past" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fecho_of_past.jpeg?alt=media&token=d866aa27-8534-4d72-8988-9da4a1b9e452" + releaseYear: 2023 + genre: "historical" + rating: 7.8 + description: "A historian stumbles upon an ancient artifact that reveals hidden truths about an empire long forgotten. As she deciphers the clues, a shadowy organization tries to stop her from unearthing the past." + tags: ["drama", "mystery"] + } + { + id: "550e8400-e29b-41d4-a716-446655440011" + title: "Beyond the Horizon" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fbeyond_horizon.jpeg?alt=media&token=31493973-0692-4e6e-8b88-afb1aaea17ee" + releaseYear: 2026 + genre: "sci-fi" + rating: 8.5 + description: "In the future, Earth's best pilots are sent on a mission to explore a mysterious planet beyond the solar system. What they find changes humanity's understanding of the universe forever." + tags: ["sci-fi", "adventure"] + } + { + id: "550e8400-e29b-41d4-a716-446655440012" + title: "Shadows and Lies" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fshadows_lies.jpeg?alt=media&token=01afb80d-caee-47f8-a00e-aea8b9e459a2" + releaseYear: 2022 + genre: "crime" + rating: 7.9 + description: "A young detective with a dark past investigates a series of mysterious murders in a city plagued by corruption. As she digs deeper, she realizes nothing is as it seems." + tags: ["crime", "thriller"] + } + { + id: "550e8400-e29b-41d4-a716-446655440013" + title: "The Last Symphony" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Flast_symphony.jpeg?alt=media&token=f9bf80cd-3d8e-4e24-8503-7feb11f4e397" + releaseYear: 2024 + genre: "drama" + rating: 8.0 + description: "An aging composer struggling with memory loss attempts to complete his final symphony. With the help of a young prodigy, he embarks on an emotional journey through his memories and legacy." + tags: ["drama", "music"] + } + { + id: "550e8400-e29b-41d4-a716-446655440014" + title: "Moonlit Crusade" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fmoonlit_crusade.jpeg?alt=media&token=b13241f5-d7d0-4370-b651-07847ad99dc2" + releaseYear: 2025 + genre: "fantasy" + rating: 8.3 + description: "A knight is chosen by an ancient order to embark on a quest under the light of the full moon. Facing mythical beasts and treacherous landscapes, he seeks a relic that could save his kingdom." + tags: ["fantasy", "adventure"] + } + { + id: "550e8400-e29b-41d4-a716-446655440015" + title: "Abyss of the Deep" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fabyss_deep.jpeg?alt=media&token=2417321d-2451-4ec0-9ed6-6297042170e6" + releaseYear: 2023 + genre: "horror" + rating: 7.2 + description: "When a group of marine biologists descends into the unexplored depths of the ocean, they encounter a terrifying and ancient force. Now, they must survive as the abyss comes alive." + tags: ["horror", "thriller"] + } + { + id: "550e8400-e29b-41d4-a716-446655440016" + title: "Phoenix Rising" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fpheonix_rising.jpeg?alt=media&token=7298b1fd-833c-471c-a55d-e8fc798b4ab2" + releaseYear: 2025 + genre: "action" + rating: 8.6 + description: "A special forces operative, presumed dead, returns to avenge his fallen comrades. With nothing to lose, he faces a powerful enemy in a relentless pursuit for justice." + tags: ["action", "thriller"] + } + { + id: "550e8400-e29b-41d4-a716-446655440017" + title: "The Infinite Knot" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Finfinite_knot.jpeg?alt=media&token=93d54d93-d933-4663-a6fe-26b707ef823e" + releaseYear: 2026 + genre: "romance" + rating: 7.4 + description: "Two souls destined to meet across multiple lifetimes struggle to find each other in a chaotic world. With each incarnation, they get closer, but time itself becomes their greatest obstacle." + tags: ["romance", "fantasy"] + } + { + id: "550e8400-e29b-41d4-a716-446655440018" + title: "Parallel Justice" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fparalel_justice.jpeg?alt=media&token=4544b5e2-7a1d-46ca-a97f-eb6a490d4288" + releaseYear: 2024 + genre: "crime" + rating: 8.1 + description: "A lawyer who can see the outcomes of different timelines must choose between justice and personal gain. When a high-stakes case arises, he faces a moral dilemma that could alter his life forever." + tags: ["crime", "thriller"] + } + { + id: "550e8400-e29b-41d4-a716-446655440019" + title: "Veil of Illusion" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fveil_illusion.jpeg?alt=media&token=7bf09a3c-c531-478a-9d02-5d99fca9393b" + releaseYear: 2022 + genre: "mystery" + rating: 7.8 + description: "A magician-turned-detective uses his skills in illusion to solve crimes. When a series of murders leaves the city in fear, he must reveal the truth hidden behind a veil of deceit." + tags: ["mystery", "crime"] + } + ] + ) + actor_insertMany( + data: [ + { + id: "123e4567-e89b-12d3-a456-426614174020" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Foliver_blackwood.jpeg?alt=media&token=79cdbc29-c2c6-4dc3-b87f-f6dc4f1a8208" + name: "Oliver Blackwood" + } + { + id: "123e4567-e89b-12d3-a456-426614174021" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Femma_westfield.jpeg?alt=media&token=2991c3c9-cfa8-4067-8b26-c5239b6894c4" + name: "Emma Westfield" + } + { + id: "123e4567-e89b-12d3-a456-426614174022" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fjack_stone.jpeg?alt=media&token=74a564aa-d840-4bdd-a8a6-c6b17bbde608" + name: "Jack Stone" + } + { + id: "123e4567-e89b-12d3-a456-426614174023" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fclara_woods.jpeg?alt=media&token=b4ff2a15-ef6d-4f20-86c9-07d67015fb29" + name: "Clara Woods" + } + { + id: "123e4567-e89b-12d3-a456-426614174024" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fnoah_frost.jpeg?alt=media&token=0d08179a-7778-405e-9501-feac43b77a99" + name: "Noah Frost" + } + { + id: "123e4567-e89b-12d3-a456-426614174025" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fisabelle_hart.jpeg?alt=media&token=d4fdf896-0f5b-4c32-91a4-7a541a95e77d" + name: "Isabella Hart" + } + { + id: "123e4567-e89b-12d3-a456-426614174026" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fliam_hale.jpeg?alt=media&token=08e8eeee-b8ef-4e7b-8f97-a1e0b59321cc" + name: "Liam Hale" + } + { + id: "123e4567-e89b-12d3-a456-426614174027" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fsophia_knight.jpeg?alt=media&token=7a79ef21-93e0-46f9-934c-6bbef7b5d430" + name: "Sophia Knight" + } + { + id: "123e4567-e89b-12d3-a456-426614174028" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Falex_clay.jpeg?alt=media&token=2a798cdb-f44f-48d5-91bc-9d26a758944e" + name: "Alexander Clay" + } + { + id: "123e4567-e89b-12d3-a456-426614174029" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Famelia_stone.jpeg?alt=media&token=34f21ba9-9e28-4708-9e55-f123634ab506" + name: "Amelia Stone" + } + { + id: "123e4567-e89b-12d3-a456-426614174030" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fethan_blake.jpeg?alt=media&token=41352170-a5cd-4088-b8fd-1c4ee0d52cad" + name: "Ethan Blake" + } + { + id: "123e4567-e89b-12d3-a456-426614174031" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fmia_gray.jpeg?alt=media&token=1ba1831a-3ada-485a-b5c9-2d018bf1862b" + name: "Mia Gray" + } + { + id: "123e4567-e89b-12d3-a456-426614174032" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Flucas_reed.jpeg?alt=media&token=c74f44f3-ae98-4208-8e67-18c2db65a5c1" + name: "Lucas Reed" + } + { + id: "123e4567-e89b-12d3-a456-426614174033" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fevelyn_harper.jpeg?alt=media&token=b138b308-9589-4dfe-8c50-a6d70f06dfb1" + name: "Evelyn Harper" + } + { + id: "123e4567-e89b-12d3-a456-426614174034" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Foscar_smith.jpeg?alt=media&token=d493da85-644d-4d45-a09d-ecb5416645e4" + name: "Oscar Smith" + } + { + id: "123e4567-e89b-12d3-a456-426614174035" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fava_winter.jpeg?alt=media&token=757e4b11-0372-401e-8fa0-61797e90312a" + name: "Ava Winter" + } + { + id: "123e4567-e89b-12d3-a456-426614174036" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fleo_hunt.jpeg?alt=media&token=2cb14738-b39b-47b1-87f9-b45f38245179" + name: "Leo Hunt" + } + { + id: "123e4567-e89b-12d3-a456-426614174037" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Flucy_walsh.jpeg?alt=media&token=016a216c-f329-4c10-bbe8-b31425f73c69" + name: "Lucy Walsh" + } + { + id: "123e4567-e89b-12d3-a456-426614174038" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fmason_ford.jpeg?alt=media&token=55388be9-fdc8-483f-8352-c29755ed3574" + name: "Mason Ford" + } + { + id: "123e4567-e89b-12d3-a456-426614174039" + imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Flily_moore.jpeg?alt=media&token=19538aa6-1baf-4033-8fd7-d2a62aa79f51" + name: "Lily Moore" + } + ] + ) + movieMetadata_insertMany( + data: [ + { + movieId: "550e8400-e29b-41d4-a716-446655440000" + director: "Henry Caldwell" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440001" + director: "Juliana Mason, Clark Avery" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440002" + director: "Diana Rivers" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440003" + director: "Liam Thatcher" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440004" + director: "Evelyn Hart" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440005" + director: "Grayson Brooks" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440006" + director: "Isabella Quinn" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440007" + director: "Vincent Hale" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440008" + director: "Amelia Sutton" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440009" + director: "Lucas Stone" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440010" + director: "Sophia Langford" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440011" + director: "Noah Bennett" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440012" + director: "Chloe Armstrong" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440013" + director: "Sebastian Crane" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440014" + director: "Isla Fitzgerald" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440015" + director: "Oliver Hayes" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440016" + director: "Mila Donovan" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440017" + director: "Carter Monroe, Elise Turner" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440018" + director: "Adrian Blake" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440019" + director: "Hazel Carter" + } + ] + ) +movieActor_insertMany( + data: [ + { + movieId: "550e8400-e29b-41d4-a716-446655440000" + actorId: "123e4567-e89b-12d3-a456-426614174020" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440000" + actorId: "123e4567-e89b-12d3-a456-426614174021" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440001" + actorId: "123e4567-e89b-12d3-a456-426614174021" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440001" + actorId: "123e4567-e89b-12d3-a456-426614174022" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440002" + actorId: "123e4567-e89b-12d3-a456-426614174022" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440002" + actorId: "123e4567-e89b-12d3-a456-426614174023" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440003" + actorId: "123e4567-e89b-12d3-a456-426614174023" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440003" + actorId: "123e4567-e89b-12d3-a456-426614174024" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440004" + actorId: "123e4567-e89b-12d3-a456-426614174024" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440004" + actorId: "123e4567-e89b-12d3-a456-426614174025" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440005" + actorId: "123e4567-e89b-12d3-a456-426614174025" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440005" + actorId: "123e4567-e89b-12d3-a456-426614174026" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440006" + actorId: "123e4567-e89b-12d3-a456-426614174026" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440006" + actorId: "123e4567-e89b-12d3-a456-426614174027" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440007" + actorId: "123e4567-e89b-12d3-a456-426614174027" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440007" + actorId: "123e4567-e89b-12d3-a456-426614174028" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440008" + actorId: "123e4567-e89b-12d3-a456-426614174028" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440008" + actorId: "123e4567-e89b-12d3-a456-426614174029" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440009" + actorId: "123e4567-e89b-12d3-a456-426614174029" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440009" + actorId: "123e4567-e89b-12d3-a456-426614174030" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440010" + actorId: "123e4567-e89b-12d3-a456-426614174030" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440010" + actorId: "123e4567-e89b-12d3-a456-426614174031" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440011" + actorId: "123e4567-e89b-12d3-a456-426614174031" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440011" + actorId: "123e4567-e89b-12d3-a456-426614174032" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440012" + actorId: "123e4567-e89b-12d3-a456-426614174032" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440012" + actorId: "123e4567-e89b-12d3-a456-426614174033" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440013" + actorId: "123e4567-e89b-12d3-a456-426614174033" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440013" + actorId: "123e4567-e89b-12d3-a456-426614174034" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440014" + actorId: "123e4567-e89b-12d3-a456-426614174034" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440014" + actorId: "123e4567-e89b-12d3-a456-426614174035" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440015" + actorId: "123e4567-e89b-12d3-a456-426614174035" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440015" + actorId: "123e4567-e89b-12d3-a456-426614174036" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440016" + actorId: "123e4567-e89b-12d3-a456-426614174036" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440016" + actorId: "123e4567-e89b-12d3-a456-426614174037" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440017" + actorId: "123e4567-e89b-12d3-a456-426614174037" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440017" + actorId: "123e4567-e89b-12d3-a456-426614174038" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440018" + actorId: "123e4567-e89b-12d3-a456-426614174038" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440018" + actorId: "123e4567-e89b-12d3-a456-426614174039" + role: "supporting" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440019" + actorId: "123e4567-e89b-12d3-a456-426614174039" + role: "main" + } + { + movieId: "550e8400-e29b-41d4-a716-446655440019" + actorId: "123e4567-e89b-12d3-a456-426614174020" + role: "supporting" + } + ] +) + user_insertMany( + data: [ + { id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", username: "sherlock_h" } + { id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", username: "hercule_p" } + { id: "TBedjwCX0Jf955Uuoxk6k74sY0l1", username: "jane_d" } + ] + ) + + review_insertMany( + 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 } + } + { + 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 } + } + { + 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 } + } + { + 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 } + } + { + 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 } + } + { + 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 } + } + ] + ) + + favorite_movie_insertMany( + data: [ + { + userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2" + movieId: "550e8400-e29b-41d4-a716-446655440000" + } + { + userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2" + movieId: "550e8400-e29b-41d4-a716-446655440001" + } + { + userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1" + movieId: "550e8400-e29b-41d4-a716-446655440002" + } + { + userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2" + movieId: "550e8400-e29b-41d4-a716-446655440003" + } + { + userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2" + movieId: "550e8400-e29b-41d4-a716-446655440004" + } + { + userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1" + movieId: "550e8400-e29b-41d4-a716-446655440005" + } + ] + ) +} diff --git a/dataconnect/schema/schema.gql b/dataconnect/dataconnect/schema/schema.gql similarity index 100% rename from dataconnect/schema/schema.gql rename to dataconnect/dataconnect/schema/schema.gql diff --git a/dataconnect/firebase.json b/dataconnect/firebase.json index 69d7060b..bfcaefe6 100644 --- a/dataconnect/firebase.json +++ b/dataconnect/firebase.json @@ -1 +1,44 @@ -{"flutter":{"platforms":{"android":{"default":{"projectId":"vertex-ai-devrel","appId":"1:474248463284:android:23f58dd553f5331f97e8e1","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"vertex-ai-devrel","appId":"1:474248463284:ios:1bee535bf196651197e8e1","uploadDebugSymbols":false,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"vertex-ai-devrel","configurations":{"android":"1:474248463284:android:23f58dd553f5331f97e8e1","ios":"1:474248463284:ios:1bee535bf196651197e8e1","web":"1:474248463284:web:c6676b8628d2086297e8e1"}}}}}} \ No newline at end of file +{ + "flutter": { + "platforms": { + "android": { + "default": { + "projectId": "quickstart-flutter-cc624", + "appId": "1:731568610039:android:2fda8b27330be9447251f2", + "fileOutput": "android/app/google-services.json" + } + }, + "ios": { + "default": { + "projectId": "quickstart-flutter-cc624", + "appId": "1:731568610039:ios:e78b43f1d75a77d87251f2", + "uploadDebugSymbols": false, + "fileOutput": "ios/Runner/GoogleService-Info.plist" + } + }, + "dart": { + "lib/firebase_options.dart": { + "projectId": "quickstart-flutter-cc624", + "configurations": { + "android": "1:731568610039:android:2fda8b27330be9447251f2", + "ios": "1:731568610039:ios:e78b43f1d75a77d87251f2", + "macos": "1:731568610039:ios:e78b43f1d75a77d87251f2", + "web": "1:731568610039:web:2896847d0f5655fb7251f2", + "windows": "1:731568610039:web:3c1e404f955f0b467251f2" + } + } + }, + "macos": { + "default": { + "projectId": "quickstart-flutter-cc624", + "appId": "1:731568610039:ios:e78b43f1d75a77d87251f2", + "uploadDebugSymbols": false, + "fileOutput": "macos/Runner/GoogleService-Info.plist" + } + } + } + }, + "dataconnect": { + "source": "dataconnect" + } +} diff --git a/dataconnect/ios/Flutter/Debug.xcconfig b/dataconnect/ios/Flutter/Debug.xcconfig index 592ceee8..ec97fc6f 100644 --- a/dataconnect/ios/Flutter/Debug.xcconfig +++ b/dataconnect/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/dataconnect/ios/Flutter/Release.xcconfig b/dataconnect/ios/Flutter/Release.xcconfig index 592ceee8..c4855bfe 100644 --- a/dataconnect/ios/Flutter/Release.xcconfig +++ b/dataconnect/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/dataconnect/lib/firebase_options.dart b/dataconnect/lib/firebase_options.dart index c543db4b..e26e9441 100644 --- a/dataconnect/lib/firebase_options.dart +++ b/dataconnect/lib/firebase_options.dart @@ -25,15 +25,9 @@ class DefaultFirebaseOptions { case TargetPlatform.iOS: return ios; case TargetPlatform.macOS: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for macos - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); + return macos; case TargetPlatform.windows: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for windows - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); + return windows; case TargetPlatform.linux: throw UnsupportedError( 'DefaultFirebaseOptions have not been configured for linux - ' @@ -47,28 +41,47 @@ class DefaultFirebaseOptions { } static const FirebaseOptions web = FirebaseOptions( - apiKey: 'AIzaSyAQ0QFQQ_e4TQv6mzRe6QjE5H4pvlsuRSI', - appId: '1:474248463284:web:c6676b8628d2086297e8e1', - messagingSenderId: '474248463284', - projectId: 'vertex-ai-devrel', - authDomain: 'vertex-ai-devrel.firebaseapp.com', - storageBucket: 'vertex-ai-devrel.appspot.com', + apiKey: 'AIzaSyDP_NulZ2xnDHFRAbBX45RPqkpzXfGjKJI', + appId: '1:731568610039:web:2896847d0f5655fb7251f2', + messagingSenderId: '731568610039', + projectId: 'quickstart-flutter-cc624', + authDomain: 'quickstart-flutter-cc624.firebaseapp.com', + storageBucket: 'quickstart-flutter-cc624.firebasestorage.app', ); static const FirebaseOptions android = FirebaseOptions( - apiKey: 'AIzaSyBxNnSTRdHJ1bo0paLyjulOV6CbzSecaCQ', - appId: '1:474248463284:android:23f58dd553f5331f97e8e1', - messagingSenderId: '474248463284', - projectId: 'vertex-ai-devrel', - storageBucket: 'vertex-ai-devrel.appspot.com', + apiKey: 'AIzaSyA45BWLEXFb2SRqtMu6LoCL2f53k-6_0GM', + appId: '1:731568610039:android:2fda8b27330be9447251f2', + messagingSenderId: '731568610039', + projectId: 'quickstart-flutter-cc624', + storageBucket: 'quickstart-flutter-cc624.firebasestorage.app', ); static const FirebaseOptions ios = FirebaseOptions( - apiKey: 'AIzaSyDpBD_g5f6lX72JnnPfke9MeWqr8SMEysg', - appId: '1:474248463284:ios:1bee535bf196651197e8e1', - messagingSenderId: '474248463284', - projectId: 'vertex-ai-devrel', - storageBucket: 'vertex-ai-devrel.appspot.com', + apiKey: 'AIzaSyCqVWdSdrCPRZ6Ld_6j1hjpWfPIUg-7_5I', + appId: '1:731568610039:ios:e78b43f1d75a77d87251f2', + messagingSenderId: '731568610039', + projectId: 'quickstart-flutter-cc624', + storageBucket: 'quickstart-flutter-cc624.firebasestorage.app', iosBundleId: 'com.example.dataconnect', ); -} + + static const FirebaseOptions macos = FirebaseOptions( + apiKey: 'AIzaSyCqVWdSdrCPRZ6Ld_6j1hjpWfPIUg-7_5I', + appId: '1:731568610039:ios:e78b43f1d75a77d87251f2', + messagingSenderId: '731568610039', + projectId: 'quickstart-flutter-cc624', + storageBucket: 'quickstart-flutter-cc624.firebasestorage.app', + iosBundleId: 'com.example.dataconnect', + ); + + static const FirebaseOptions windows = FirebaseOptions( + apiKey: 'AIzaSyDP_NulZ2xnDHFRAbBX45RPqkpzXfGjKJI', + appId: '1:731568610039:web:3c1e404f955f0b467251f2', + messagingSenderId: '731568610039', + projectId: 'quickstart-flutter-cc624', + authDomain: 'quickstart-flutter-cc624.firebaseapp.com', + storageBucket: 'quickstart-flutter-cc624.firebasestorage.app', + ); + +} \ No newline at end of file diff --git a/dataconnect/lib/main.dart b/dataconnect/lib/main.dart index d3c247d4..4709ac92 100644 --- a/dataconnect/lib/main.dart +++ b/dataconnect/lib/main.dart @@ -3,9 +3,29 @@ import 'dart:async'; import 'package:firebase_data_connect/firebase_data_connect.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; +import 'package:go_router/go_router.dart'; import 'firebase_options.dart'; +import 'movie_detail.dart'; import 'movies_connector/movies.dart'; +final _router = GoRouter( + routes: [ + GoRoute( + path: '/', + builder: (context, state) => MyHomePage(), + ), + GoRoute( + path: '/movies/:movieId', + builder: (context, state) => + MovieDetail(id: state.pathParameters['movieId']!), + ) + ], + redirect: (context, state) { + print(state.path); + return null; + }, +); + void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( @@ -20,34 +40,15 @@ class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Firebase Data Connect', - theme: ThemeData( - // This is the theme of your application. - // - // TRY THIS: Try running your application with "flutter run". You'll see - // the application has a purple toolbar. Then, without quitting the app, - // try changing the seedColor in the colorScheme below to Colors.green - // and then invoke "hot reload" (save your changes or press the "hot - // reload" button in a Flutter-supported IDE, or press "r" if you used - // the command line to start the app). - // - // Notice that the counter didn't reset back to zero; the application - // state is not lost during the reload. To reset the state, use hot - // restart instead. - // - // This works for code too, not just values: Most code changes can be - // tested with just a hot reload. - colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), - useMaterial3: true, - ), - home: const MyHomePage(title: 'Data Connect Flutter'), + return MaterialApp.router( + theme: ThemeData.dark(), + routerConfig: _router, ); } } class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); + const MyHomePage({super.key}); // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect @@ -58,8 +59,6 @@ class MyHomePage extends StatefulWidget { // used by the build method of the State. Fields in a Widget subclass are // always marked "final". - final String title; - @override State createState() => _MyHomePageState(); } @@ -74,8 +73,8 @@ class _MyHomePageState extends State { /// TODO: Uncomment the following lines to update the movies state when data /// comes back from the server. - // MoviesConnector.instance.dataConnect - // .useDataConnectEmulator('localhost', 9399); + MoviesConnector.instance.dataConnect + .useDataConnectEmulator('localhost', 9399); MoviesConnector.instance .listMovies() .orderByRating(OrderDirection.DESC) @@ -107,17 +106,15 @@ class _MyHomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: const Text('Firebase Data Connect Flutter'), - ), - body: SingleChildScrollView( + body: SafeArea( + child: SingleChildScrollView( child: Column( children: [ _buildMovieList('Top 10 Movies', _topMovies), _buildMovieList('Latest Movies', _latestMovies), ], ), - ), + )), ); } @@ -129,7 +126,7 @@ class _MyHomePageState extends State { padding: const EdgeInsets.all(8.0), child: Text( title, - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), ), SizedBox( @@ -146,34 +143,41 @@ class _MyHomePageState extends State { ); } + void _visitDetail(String id) { + context.push("/movies/$id"); + } + Widget _buildMovieItem(ListMoviesMovies movie) { - return Flexible( - child: Container( + return Container( width: 150, // Adjust the width as needed padding: const EdgeInsets.all(4.0), child: Card( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: 9 / 16, // 9:16 aspect ratio for the image - child: Image.network( - movie.imageUrl, - fit: BoxFit.cover, - ), - ), - const SizedBox(height: 8), - Padding( - padding: EdgeInsets.all(8.0), - child: Text( - movie.title, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ), - ], - ), + child: InkWell( + onTap: () { + _visitDetail(movie.id); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: 9 / 16, // 9:16 aspect ratio for the image + child: Image.network( + movie.imageUrl, + fit: BoxFit.cover, + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + movie.title, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + ], + )), ), - )); + ); } } diff --git a/dataconnect/lib/movie_detail.dart b/dataconnect/lib/movie_detail.dart new file mode 100644 index 00000000..8adf7822 --- /dev/null +++ b/dataconnect/lib/movie_detail.dart @@ -0,0 +1,241 @@ +import 'package:dataconnect/movies_connector/movies.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class MovieDetail extends StatefulWidget { + const MovieDetail({super.key, required this.id}); + + final String id; + + @override + State createState() => _MovieDetailState(id: this.id); +} + +class _MovieDetailState extends State { + _MovieDetailState({required this.id}); + String id; + double _ratingValue = 0; + bool loading = true; + GetMovieByIdData? data; + @override + void initState() { + super.initState(); + MoviesConnector.instance.getMovieById(id: id).execute().then((value) { + setState(() { + loading = false; + data = value.data; + }); + }); + } + + List _buildMainDescription() { + var movie = data!.movie!; + return [ + Align( + alignment: Alignment.centerLeft, + child: Container( + child: Text( + movie.title, + style: const TextStyle(fontSize: 30), + ), + )), + Row( + children: [ + Text(movie.releaseYear.toString()), + const SizedBox(width: 10), + Row( + children: [const Icon(Icons.star), Text(movie.rating.toString())], + ) + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: AspectRatio( + aspectRatio: 9 / 16, // 9:16 aspect ratio for the image + child: Image.network( + movie.imageUrl, + fit: BoxFit.cover, + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), + child: Column(children: [ + Row( + children: movie.tags!.map((tag) { + return TextButton(onPressed: () {}, child: Text(tag)); + }).toList(), + ), + Text(movie.description!) + ]), + )) + ]), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // TODO(mtewani): Check if the movie has been watched by the user + OutlinedButton.icon( + onPressed: () { + // TODO(mtewani): Check if user is logged in. + }, + icon: const Icon(Icons.check_circle), + label: const Text('Watched'), + ), + OutlinedButton.icon( + onPressed: () { + // TODO(mtewani): Check if user is logged in. + }, + icon: const Icon(Icons.favorite), + label: const Text('Add To Favorites'), + ) + ], + ) + ]; + } + + Widget _buildMainActorsList() { + return Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Main Actors", + style: TextStyle(fontSize: 30), + ), + ListView.builder( + scrollDirection: Axis.vertical, + shrinkWrap: true, + itemBuilder: (context, index) { + GetMovieByIdMovieMainActors actor = data!.movie!.mainActors[index]; + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CircleAvatar( + radius: 30, + child: ClipOval(child: Image.network(actor.imageUrl))), + Text(actor + .name) // TODO(mtewani): Clip if there's not enough width + ]); + }, + itemCount: data!.movie!.mainActors.length, + ) + ], + )); + } + + Widget _buildSupportingActorsList() { + return Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Supporting Actors", + style: TextStyle(fontSize: 30), + ), + ListView.builder( + scrollDirection: Axis.vertical, + shrinkWrap: true, + itemBuilder: (context, index) { + GetMovieByIdMovieSupportingActors actor = + data!.movie!.supportingActors[index]; + return Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CircleAvatar( + radius: 30, + child: ClipOval(child: Image.network(actor.imageUrl))), + Text(actor + .name) // TODO(mtewani): Clip if there's not enough width + ]); + }, + itemCount: data!.movie!.mainActors.length, + ) + ], + )); + } + + List _buildRatings() { + return [ + Text("Rating: $_ratingValue"), + Slider( + value: _ratingValue, + max: 5, + divisions: 10, + label: _ratingValue.toString(), + onChanged: (double value) { + setState(() { + _ratingValue = value; + }); + }, + ), + TextField( + decoration: InputDecoration( + hintText: "Write your review", + border: OutlineInputBorder(), + ), + ), + OutlinedButton.icon( + onPressed: () { + // TODO(mtewani): Check if user is logged in. + }, + label: const Text('Submit Review'), + ), + ...data!.movie!.reviews.map((review) { + return Card( + child: Padding( + padding: EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(review.user.username), + Row( + children: [ + Text(DateFormat.yMMMd().format(review.reviewDate)), + SizedBox( + width: 10, + ), + Text("Rating ${review.rating}") + ], + ), + Text(review.reviewText!) + ], + )), + ); + }) + ]; +/**/ + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: data == null + ? const Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [CircularProgressIndicator()], + ) + : Padding( + padding: const EdgeInsets.all(30), + child: SingleChildScrollView( + child: Column( + children: [ + ..._buildMainDescription(), + _buildMainActorsList(), + _buildSupportingActorsList(), + ..._buildRatings() + ], + )))), + ); + } +} diff --git a/dataconnect/macos/Flutter/Flutter-Debug.xcconfig b/dataconnect/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b6..4b81f9b2 100644 --- a/dataconnect/macos/Flutter/Flutter-Debug.xcconfig +++ b/dataconnect/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/dataconnect/macos/Flutter/Flutter-Release.xcconfig b/dataconnect/macos/Flutter/Flutter-Release.xcconfig index c2efd0b6..5caa9d15 100644 --- a/dataconnect/macos/Flutter/Flutter-Release.xcconfig +++ b/dataconnect/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/dataconnect/macos/Runner.xcodeproj/project.pbxproj b/dataconnect/macos/Runner.xcodeproj/project.pbxproj index 3be415f2..e6892799 100644 --- a/dataconnect/macos/Runner.xcodeproj/project.pbxproj +++ b/dataconnect/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + E81C99BCE641EAAC42D0435C /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = F9721B425DB992F996064CCA /* GoogleService-Info.plist */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -64,7 +65,7 @@ 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* dataconnect.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "dataconnect.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* dataconnect.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = dataconnect.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -78,6 +79,7 @@ 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + F9721B425DB992F996064CCA /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -125,6 +127,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + F9721B425DB992F996064CCA /* GoogleService-Info.plist */, ); sourceTree = ""; }; @@ -285,6 +288,7 @@ files = ( 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + E81C99BCE641EAAC42D0435C /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/dataconnect/pubspec.lock b/dataconnect/pubspec.lock index 11ea9962..b7747825 100644 --- a/dataconnect/pubspec.lock +++ b/dataconnect/pubspec.lock @@ -200,6 +200,14 @@ packages: description: flutter source: sdk version: "0.0.0" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: "844a216ee2aa29dd484fdc815f2d1bc1ca7d02182121b494e14c2ce79bb01bb7" + url: "https://pub.dev" + source: hosted + version: "14.5.0" google_identity_services_web: dependency: transitive description: @@ -249,7 +257,7 @@ packages: source: hosted version: "4.0.2" intl: - dependency: transitive + dependency: "direct main" description: name: intl sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf @@ -288,6 +296,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" matcher: dependency: transitive description: diff --git a/dataconnect/pubspec.yaml b/dataconnect/pubspec.yaml index 751c8fb3..5ff5570c 100644 --- a/dataconnect/pubspec.yaml +++ b/dataconnect/pubspec.yaml @@ -37,6 +37,8 @@ dependencies: cupertino_icons: ^1.0.8 firebase_data_connect: ^0.1.2+1 firebase_core: ^3.6.0 + go_router: ^14.5.0 + intl: ^0.19.0 dev_dependencies: flutter_test: From 2ec2e2f9f2ae851c73794d2a56a5c9d82a167cb9 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 13 Nov 2024 17:05:37 -0800 Subject: [PATCH 02/17] Added detail and signin pages --- .../android/app/src/main/AndroidManifest.xml | 1 + .../.dataconnect/schema/main/input.gql | 56 +++ .../.dataconnect/schema/main/query.gql | 24 + .../dataconnect/connector/connector.yaml | 2 +- dataconnect/dataconnect/connector/queries.gql | 26 ++ .../lib/movies_connector/movies.dart | 7 + dataconnect/dataconnect/schema/schema.gql | 7 + dataconnect/firebase.json | 8 + dataconnect/lib/actor_detail.dart | 93 ++++ dataconnect/lib/destination.dart | 22 + dataconnect/lib/genre_list_movies.dart | 133 ++++++ dataconnect/lib/genre_page.dart | 63 +++ dataconnect/lib/login.dart | 100 ++++ dataconnect/lib/main.dart | 32 +- dataconnect/lib/movie_detail.dart | 141 +++--- .../lib/movies_connector/list_genres.dart | 126 ++++++ .../list_movies_by_genre.dart | 427 ++++++++++++++++++ dataconnect/lib/movies_connector/movies.dart | 14 + dataconnect/lib/navigation_shell.dart | 34 ++ dataconnect/lib/profile.dart | 57 +++ dataconnect/lib/router.dart | 78 ++++ dataconnect/lib/sign_up.dart | 123 +++++ dataconnect/lib/util/auth.dart | 12 + dataconnect/pubspec.lock | 22 +- dataconnect/pubspec.yaml | 1 + 25 files changed, 1510 insertions(+), 99 deletions(-) create mode 100644 dataconnect/lib/actor_detail.dart create mode 100644 dataconnect/lib/destination.dart create mode 100644 dataconnect/lib/genre_list_movies.dart create mode 100644 dataconnect/lib/genre_page.dart create mode 100644 dataconnect/lib/login.dart create mode 100644 dataconnect/lib/movies_connector/list_genres.dart create mode 100644 dataconnect/lib/movies_connector/list_movies_by_genre.dart create mode 100644 dataconnect/lib/navigation_shell.dart create mode 100644 dataconnect/lib/profile.dart create mode 100644 dataconnect/lib/router.dart create mode 100644 dataconnect/lib/sign_up.dart create mode 100644 dataconnect/lib/util/auth.dart diff --git a/dataconnect/android/app/src/main/AndroidManifest.xml b/dataconnect/android/app/src/main/AndroidManifest.xml index 8ab02cb0..136e48a8 100644 --- a/dataconnect/android/app/src/main/AndroidManifest.xml +++ b/dataconnect/android/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ createState() => _ActorDetailState(); +} + +class _ActorDetailState extends State { + bool loading = true; + GetActorByIdActor? actor; + @override + void initState() { + super.initState(); + MoviesConnector.instance + .getActorById(id: widget.actorId) + .execute() + .then((value) { + setState(() { + loading = false; + actor = value.data.actor; + }); + }); + } + + _buildActorInfo() { + return [ + Align( + alignment: Alignment.centerLeft, + child: Container( + child: Text( + actor!.name, + style: const TextStyle(fontSize: 30), + ), + )), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: AspectRatio( + aspectRatio: 9 / 16, // 9:16 aspect ratio for the image + child: Image.network( + actor!.imageUrl, + fit: BoxFit.cover, + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), + // child: Column(children: [Text(actor!.info!)]), + )) + ]), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // TODO(mtewani): Check if the movie has been watched by the user + OutlinedButton.icon( + onPressed: () { + // TODO(mtewani): Check if user is logged in. + }, + icon: const Icon(Icons.favorite), + label: const Text('Add To Favorites'), + ) + ], + ) + ]; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: actor == null + ? const Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [CircularProgressIndicator()], + ) + : Padding( + padding: const EdgeInsets.all(30), + child: SingleChildScrollView( + child: Column( + children: [..._buildActorInfo()], + )))), + ); + } +} diff --git a/dataconnect/lib/destination.dart b/dataconnect/lib/destination.dart new file mode 100644 index 00000000..f3d04d4e --- /dev/null +++ b/dataconnect/lib/destination.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; + +class Destination { + const Destination({required this.label, required this.icon}); + final String label; + final IconData icon; +} + +class Route { + Route({required this.path, required this.label, required this.iconData}); + final String path; + final String label; + final IconData iconData; +} + +var homePath = Route(path: '/home', label: 'Home', iconData: Icons.home); +var genrePath = Route(path: '/genres', label: 'Genres', iconData: Icons.list); +var searchPath = + Route(path: '/search', label: 'Search', iconData: Icons.search); +var profilePath = + Route(path: '/profile', label: 'Profile', iconData: Icons.person); +var paths = [homePath, genrePath, searchPath, profilePath]; diff --git a/dataconnect/lib/genre_list_movies.dart b/dataconnect/lib/genre_list_movies.dart new file mode 100644 index 00000000..db43fb05 --- /dev/null +++ b/dataconnect/lib/genre_list_movies.dart @@ -0,0 +1,133 @@ +import 'package:dataconnect/movies_connector/movies.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class GenreListMovies extends StatefulWidget { + const GenreListMovies({super.key, required this.genre}); + final String genre; + + @override + State createState() => _GenreListMoviesState(); +} + +class _GenreListMoviesState extends State { + bool loading = true; + List _mostPopular = []; + List _mostRecent = []; + + void _visitDetail(String id) { + context.push("/movies/$id"); + } + + Widget _buildMovieList(String title, List movies) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + title, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + ), + SizedBox( + height: 300, // Adjust the height as needed + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: movies.length, + itemBuilder: (context, index) { + return _buildMovieItem(movies[index]); + }, + ), + ), + ], + ); + } + + Widget _buildMovieItem(ListMoviesByGenreMovies movie) { + return Container( + width: 150, // Adjust the width as needed + padding: const EdgeInsets.all(4.0), + child: Card( + child: InkWell( + onTap: () { + _visitDetail(movie.id); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: 9 / 16, // 9:16 aspect ratio for the image + child: Image.network( + movie.imageUrl, + fit: BoxFit.cover, + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + movie.title, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + ], + )), + ), + ); + } + + @override + void initState() { + super.initState(); + String genre = widget.genre; + MoviesConnector.instance + .listMoviesByGenre(genre: genre) + .orderByRating(OrderDirection.DESC) + .limit(10) + .execute() + .then((res) { + setState(() { + _mostPopular = res.data.movies; + }); + }); + + MoviesConnector.instance + .listMoviesByGenre(genre: genre) + .orderByReleaseYear(OrderDirection.DESC) + .execute() + .then((res) { + setState(() { + _mostRecent = res.data.movies; + }); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: _mostPopular.isEmpty && _mostRecent.isEmpty + ? const Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [CircularProgressIndicator()], + ) + : SingleChildScrollView( + padding: const EdgeInsets.all(30), + child: Column( + children: [ + Text( + "${widget.genre} Movies", + style: const TextStyle( + fontSize: 20, fontWeight: FontWeight.bold), + ), + _buildMovieList("Most Popular", _mostPopular), + _buildMovieList("Most Recent", _mostRecent) + ], + ), + )), + ); + } +} diff --git a/dataconnect/lib/genre_page.dart b/dataconnect/lib/genre_page.dart new file mode 100644 index 00000000..7838e404 --- /dev/null +++ b/dataconnect/lib/genre_page.dart @@ -0,0 +1,63 @@ +import 'package:dataconnect/movies_connector/movies.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class GenrePage extends StatefulWidget { + const GenrePage({super.key}); + + @override + State createState() => _GenrePageState(); +} + +class _GenrePageState extends State { + List genres = []; + bool loading = true; + @override + void initState() { + super.initState(); + MoviesConnector.instance.listGenres().execute().then((genres) { + setState(() { + loading = false; + this.genres = + genres.data.genres.map((genreData) => genreData.genre!).toList(); + }); + }); + } + + Widget _buildGenreList() { + return ListView.builder( + itemBuilder: (context, index) { + String genre = genres[index]; + return ListTile( + title: TextButton( + child: Text(genre, style: TextStyle(fontSize: 30)), + onPressed: () { + context.push('/genres/${genre}'); + }, + ), + ); + }, + itemCount: genres.length, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: loading + ? const Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [CircularProgressIndicator()], + ) + : Padding( + padding: const EdgeInsets.all(30), child: _buildGenreList() + // ..._buildMainDescription(), + // _buildMainActorsList(), + // _buildSupportingActorsList(), + // ..._buildRatings() + )), + ); + } +} diff --git a/dataconnect/lib/login.dart b/dataconnect/lib/login.dart new file mode 100644 index 00000000..3817a85a --- /dev/null +++ b/dataconnect/lib/login.dart @@ -0,0 +1,100 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class Login extends StatefulWidget { + const Login({super.key}); + + @override + State createState() => _LoginState(); +} + +class _LoginState extends State { + final _formKey = GlobalKey(); + String _username = ''; + String _password = ''; + Widget _buildForm() { + return Form( + key: _formKey, + child: Column( + children: [ + TextFormField( + decoration: const InputDecoration( + hintText: "Username", border: OutlineInputBorder()), + onChanged: (value) { + setState(() { + _username = value; + }); + }, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + return null; + }, + ), + const SizedBox(height: 30), + TextFormField( + decoration: const InputDecoration( + hintText: "Password", border: OutlineInputBorder()), + onChanged: (value) { + setState(() { + _password = value; + }); + }, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter a password'; + } + + return null; + }, + ), + ElevatedButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + logIn(); + } + }, + child: const Text('Sign In')), + Text('Don\'t have an account?'), + ElevatedButton( + onPressed: () { + context.go('/signup'); + }, + child: const Text('Sign Up')), + ], + )); + } + + logIn() async { + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar(content: Text('Signing In'))); + try { + await FirebaseAuth.instance + .signInWithEmailAndPassword(email: _username, password: _password); + if (mounted) { + context.go('/home'); + } + } catch (_) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('There was an error when creating a user.'))); + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Padding( + padding: EdgeInsets.all(30), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [_buildForm()], + ))), + ); + } +} diff --git a/dataconnect/lib/main.dart b/dataconnect/lib/main.dart index 4709ac92..eb3e599a 100644 --- a/dataconnect/lib/main.dart +++ b/dataconnect/lib/main.dart @@ -1,36 +1,19 @@ -import 'dart:async'; - -import 'package:firebase_data_connect/firebase_data_connect.dart'; +import 'package:dataconnect/router.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:go_router/go_router.dart'; import 'firebase_options.dart'; -import 'movie_detail.dart'; import 'movies_connector/movies.dart'; -final _router = GoRouter( - routes: [ - GoRoute( - path: '/', - builder: (context, state) => MyHomePage(), - ), - GoRoute( - path: '/movies/:movieId', - builder: (context, state) => - MovieDetail(id: state.pathParameters['movieId']!), - ) - ], - redirect: (context, state) { - print(state.path); - return null; - }, -); - void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); + MoviesConnector.instance.dataConnect + .useDataConnectEmulator('localhost', 9399); + FirebaseAuth.instance.useAuthEmulator('localhost', 9400); runApp(const MyApp()); } @@ -42,7 +25,7 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp.router( theme: ThemeData.dark(), - routerConfig: _router, + routerConfig: router, ); } } @@ -73,8 +56,7 @@ class _MyHomePageState extends State { /// TODO: Uncomment the following lines to update the movies state when data /// comes back from the server. - MoviesConnector.instance.dataConnect - .useDataConnectEmulator('localhost', 9399); + MoviesConnector.instance .listMovies() .orderByRating(OrderDirection.DESC) diff --git a/dataconnect/lib/movie_detail.dart b/dataconnect/lib/movie_detail.dart index 8adf7822..90810f29 100644 --- a/dataconnect/lib/movie_detail.dart +++ b/dataconnect/lib/movie_detail.dart @@ -1,5 +1,6 @@ import 'package:dataconnect/movies_connector/movies.dart'; import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; class MovieDetail extends StatefulWidget { @@ -8,19 +9,20 @@ class MovieDetail extends StatefulWidget { final String id; @override - State createState() => _MovieDetailState(id: this.id); + State createState() => _MovieDetailState(); } class _MovieDetailState extends State { - _MovieDetailState({required this.id}); - String id; double _ratingValue = 0; bool loading = true; GetMovieByIdData? data; @override void initState() { super.initState(); - MoviesConnector.instance.getMovieById(id: id).execute().then((value) { + MoviesConnector.instance + .getMovieById(id: widget.id) + .execute() + .then((value) { setState(() { loading = false; data = value.data; @@ -97,69 +99,84 @@ class _MovieDetailState extends State { ]; } + void _visitActorDetail(String id) { + context.push("/actors/$id"); + } + Widget _buildMainActorsList() { return Container( + height: 125, child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Main Actors", - style: TextStyle(fontSize: 30), - ), - ListView.builder( - scrollDirection: Axis.vertical, - shrinkWrap: true, - itemBuilder: (context, index) { - GetMovieByIdMovieMainActors actor = data!.movie!.mainActors[index]; - return Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - CircleAvatar( - radius: 30, - child: ClipOval(child: Image.network(actor.imageUrl))), - Text(actor - .name) // TODO(mtewani): Clip if there's not enough width - ]); - }, - itemCount: data!.movie!.mainActors.length, - ) - ], - )); + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Main Actors", + style: TextStyle(fontSize: 30), + ), + Expanded( + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + GetMovieByIdMovieMainActors actor = + data!.movie!.mainActors[index]; + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CircleAvatar( + radius: 30, + child: + ClipOval(child: Image.network(actor.imageUrl))), + Text(actor + .name) // TODO(mtewani): Clip if there's not enough width + ]); + }, + itemCount: data!.movie!.mainActors.length, + )) + ], + )); } Widget _buildSupportingActorsList() { return Container( + height: 125, child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Supporting Actors", - style: TextStyle(fontSize: 30), - ), - ListView.builder( - scrollDirection: Axis.vertical, - shrinkWrap: true, - itemBuilder: (context, index) { - GetMovieByIdMovieSupportingActors actor = - data!.movie!.supportingActors[index]; - return Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - CircleAvatar( - radius: 30, - child: ClipOval(child: Image.network(actor.imageUrl))), - Text(actor - .name) // TODO(mtewani): Clip if there's not enough width - ]); - }, - itemCount: data!.movie!.mainActors.length, - ) - ], - )); + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Supporting Actors", + style: TextStyle(fontSize: 30), + ), + Expanded( + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + GetMovieByIdMovieSupportingActors actor = + data!.movie!.supportingActors[index]; + return InkWell( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CircleAvatar( + radius: 30, + child: ClipOval( + child: Image.network(actor.imageUrl))), + Text(actor + .name) // TODO(mtewani): Clip if there's not enough width + ]), + onTap: () { + _visitActorDetail(actor.id); + }, + ); + }, + itemCount: data!.movie!.mainActors.length, + ), + ) + ], + )); } List _buildRatings() { @@ -176,7 +193,7 @@ class _MovieDetailState extends State { }); }, ), - TextField( + const TextField( decoration: InputDecoration( hintText: "Write your review", border: OutlineInputBorder(), @@ -191,7 +208,7 @@ class _MovieDetailState extends State { ...data!.movie!.reviews.map((review) { return Card( child: Padding( - padding: EdgeInsets.all(20.0), + padding: const EdgeInsets.all(20.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -200,7 +217,7 @@ class _MovieDetailState extends State { Row( children: [ Text(DateFormat.yMMMd().format(review.reviewDate)), - SizedBox( + const SizedBox( width: 10, ), Text("Rating ${review.rating}") diff --git a/dataconnect/lib/movies_connector/list_genres.dart b/dataconnect/lib/movies_connector/list_genres.dart new file mode 100644 index 00000000..dd834671 --- /dev/null +++ b/dataconnect/lib/movies_connector/list_genres.dart @@ -0,0 +1,126 @@ +part of movies_connector; + +class ListGenresVariablesBuilder { + + + FirebaseDataConnect _dataConnect; + + ListGenresVariablesBuilder(this._dataConnect, ); + Deserializer dataDeserializer = (dynamic json) => ListGenresData.fromJson(jsonDecode(json)); + + Future> execute() { + return this.ref().execute(); + } + QueryRef ref() { + + return _dataConnect.query("ListGenres", dataDeserializer, emptySerializer, null); + } +} + + + class ListGenresGenres { + + String? genre; + + + + + + + ListGenresGenres.fromJson(dynamic json): + genre = json['genre'] == null ? null : + + nativeFromJson(json['genre']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (genre != null) { + json['genre'] = + + nativeToJson(genre) + +; + } + + + return json; + } + + ListGenresGenres({ + + this.genre, + + }); +} + + + + class ListGenresData { + + List genres; + + + + + + + ListGenresData.fromJson(dynamic json): + genres = + + + (json['genres'] as List) + .map((e) => ListGenresGenres.fromJson(e)) + .toList() + + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['genres'] = + + + genres.map((e) => e.toJson()).toList() + + +; + + + return json; + } + + ListGenresData({ + + required this.genres, + + }); +} + + + + + + + diff --git a/dataconnect/lib/movies_connector/list_movies_by_genre.dart b/dataconnect/lib/movies_connector/list_movies_by_genre.dart new file mode 100644 index 00000000..a0bfb78d --- /dev/null +++ b/dataconnect/lib/movies_connector/list_movies_by_genre.dart @@ -0,0 +1,427 @@ +part of movies_connector; + +class ListMoviesByGenreVariablesBuilder { + String genre; +Optional _orderByRating = Optional.optional(orderDirectionDeserializer, enumSerializer); +Optional _orderByReleaseYear = Optional.optional(orderDirectionDeserializer, enumSerializer); +Optional _limit = Optional.optional(nativeFromJson, nativeToJson); + + + FirebaseDataConnect _dataConnect; + ListMoviesByGenreVariablesBuilder orderByRating(OrderDirection? t) { +this._orderByRating.value = t; +return this; +} +ListMoviesByGenreVariablesBuilder orderByReleaseYear(OrderDirection? t) { +this._orderByReleaseYear.value = t; +return this; +} +ListMoviesByGenreVariablesBuilder limit(int? t) { +this._limit.value = t; +return this; +} + + ListMoviesByGenreVariablesBuilder(this._dataConnect, {required String this.genre,}); + Deserializer dataDeserializer = (dynamic json) => ListMoviesByGenreData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (ListMoviesByGenreVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + QueryRef ref() { + ListMoviesByGenreVariables vars=ListMoviesByGenreVariables(genre: genre,orderByRating: _orderByRating,orderByReleaseYear: _orderByReleaseYear,limit: _limit,); + + return _dataConnect.query("ListMoviesByGenre", dataDeserializer, varsSerializer, vars); + } +} + + + class ListMoviesByGenreMovies { + + String id; + + + String title; + + + String imageUrl; + + + int? releaseYear; + + + String? genre; + + + double? rating; + + + List? tags; + + + String? description; + + + + + + + ListMoviesByGenreMovies.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + , + + releaseYear = json['releaseYear'] == null ? null : + + nativeFromJson(json['releaseYear']) + + + + , + + genre = json['genre'] == null ? null : + + nativeFromJson(json['genre']) + + + + , + + rating = json['rating'] == null ? null : + + nativeFromJson(json['rating']) + + + + , + + tags = json['tags'] == null ? null : + + + (json['tags'] as List) + .map((e) => nativeFromJson(e)) + .toList() + + + + + , + + description = json['description'] == null ? null : + + nativeFromJson(json['description']) + + + + + { + + + + + + + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + + if (releaseYear != null) { + json['releaseYear'] = + + nativeToJson(releaseYear) + +; + } + + + + if (genre != null) { + json['genre'] = + + nativeToJson(genre) + +; + } + + + + if (rating != null) { + json['rating'] = + + nativeToJson(rating) + +; + } + + + + if (tags != null) { + json['tags'] = + + + tags?.map((e) => nativeToJson(e)).toList() + + +; + } + + + + if (description != null) { + json['description'] = + + nativeToJson(description) + +; + } + + + return json; + } + + ListMoviesByGenreMovies({ + + required this.id, + + required this.title, + + required this.imageUrl, + + this.releaseYear, + + this.genre, + + this.rating, + + this.tags, + + this.description, + + }); +} + + + + class ListMoviesByGenreData { + + List movies; + + + + + + + ListMoviesByGenreData.fromJson(dynamic json): + movies = + + + (json['movies'] as List) + .map((e) => ListMoviesByGenreMovies.fromJson(e)) + .toList() + + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movies'] = + + + movies.map((e) => e.toJson()).toList() + + +; + + + return json; + } + + ListMoviesByGenreData({ + + required this.movies, + + }); +} + + + + class ListMoviesByGenreVariables { + + String genre; + + + late OptionalorderByRating; + + + late OptionalorderByReleaseYear; + + + late Optionallimit; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + ListMoviesByGenreVariables.fromJson(Map json): + genre = + + nativeFromJson(json['genre']) + + + + + { + + + + + orderByRating = Optional.optional(orderDirectionDeserializer, enumSerializer); + orderByRating.value = json['orderByRating'] == null ? null : + + OrderDirection.values.byName(json['orderByRating']) + +; + + + + orderByReleaseYear = Optional.optional(orderDirectionDeserializer, enumSerializer); + orderByReleaseYear.value = json['orderByReleaseYear'] == null ? null : + + OrderDirection.values.byName(json['orderByReleaseYear']) + +; + + + + limit = Optional.optional(nativeFromJson, nativeToJson); + limit.value = json['limit'] == null ? null : + + nativeFromJson(json['limit']) + +; + + + } + + + Map toJson() { + Map json = {}; + + + json['genre'] = + + nativeToJson(genre) + +; + + + + if(orderByRating.state == OptionalState.set) { + json['orderByRating'] = orderByRating.toJson(); + } + + + + if(orderByReleaseYear.state == OptionalState.set) { + json['orderByReleaseYear'] = orderByReleaseYear.toJson(); + } + + + + if(limit.state == OptionalState.set) { + json['limit'] = limit.toJson(); + } + + + return json; + } + + ListMoviesByGenreVariables({ + + required this.genre, + + required this.orderByRating, + + required this.orderByReleaseYear, + + required this.limit, + + }); +} + + + + + + + diff --git a/dataconnect/lib/movies_connector/movies.dart b/dataconnect/lib/movies_connector/movies.dart index b7fbdaa8..cf9114d7 100644 --- a/dataconnect/lib/movies_connector/movies.dart +++ b/dataconnect/lib/movies_connector/movies.dart @@ -16,6 +16,10 @@ part 'delete_review.dart'; part 'list_movies.dart'; +part 'list_movies_by_genre.dart'; + +part 'list_genres.dart'; + part 'get_movie_by_id.dart'; part 'get_actor_by_id.dart'; @@ -85,6 +89,16 @@ class MoviesConnector { } + ListMoviesByGenreVariablesBuilder listMoviesByGenre ({required String genre,}) { + return ListMoviesByGenreVariablesBuilder(dataConnect, genre: genre,); + } + + + ListGenresVariablesBuilder listGenres () { + return ListGenresVariablesBuilder(dataConnect, ); + } + + GetMovieByIdVariablesBuilder getMovieById ({required String id,}) { return GetMovieByIdVariablesBuilder(dataConnect, id: id,); } diff --git a/dataconnect/lib/navigation_shell.dart b/dataconnect/lib/navigation_shell.dart new file mode 100644 index 00000000..f73b02e8 --- /dev/null +++ b/dataconnect/lib/navigation_shell.dart @@ -0,0 +1,34 @@ +import 'package:dataconnect/destination.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class NavigationShell extends StatelessWidget { + const NavigationShell({required this.navigationShell, super.key}); + final StatefulNavigationShell navigationShell; + + void _goBranch(int index) { + navigationShell.goBranch( + index, + // A common pattern when using bottom navigation bars is to support + // navigating to the initial location when tapping the item that is + // already active. This example demonstrates how to support this behavior, + // using the initialLocation parameter of goBranch. + initialLocation: index == navigationShell.currentIndex, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: navigationShell, + bottomNavigationBar: NavigationBar( + selectedIndex: navigationShell.currentIndex, + onDestinationSelected: _goBranch, + destinations: paths + .map((destination) => NavigationDestination( + icon: Icon(destination.iconData), label: destination.label)) + .toList(), + ), + ); + } +} diff --git a/dataconnect/lib/profile.dart b/dataconnect/lib/profile.dart new file mode 100644 index 00000000..1a7768ff --- /dev/null +++ b/dataconnect/lib/profile.dart @@ -0,0 +1,57 @@ +import 'package:dataconnect/main.dart'; +import 'package:dataconnect/util/auth.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class Profile extends StatefulWidget { + const Profile({super.key}); + + @override + State createState() => _ProfileState(); +} + +class _ProfileState extends State { + User? _currentUser; + @override + void initState() { + super.initState(); + Auth.getCurrentUser().then((user) { + setState(() { + _currentUser = user; + }); + }); + } + + Widget _UserInfo() { + return Container( + child: Column( + children: [ + Text('Welcome back ${_currentUser!.displayName ?? ''}!'), + TextButton( + onPressed: () async { + FirebaseAuth.instance.signOut(); + context.go('/login'); + }, + child: Text('Sign out')) + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return _currentUser == null + ? const Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [CircularProgressIndicator()], + ) + : Container( + padding: EdgeInsets.all(30), + child: Column( + children: [_UserInfo()], + ), + ); + } +} diff --git a/dataconnect/lib/router.dart b/dataconnect/lib/router.dart new file mode 100644 index 00000000..f639a8b3 --- /dev/null +++ b/dataconnect/lib/router.dart @@ -0,0 +1,78 @@ +import 'package:dataconnect/destination.dart'; +import 'package:dataconnect/login.dart'; +import 'package:dataconnect/profile.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +import 'actor_detail.dart'; +import 'genre_list_movies.dart'; +import 'genre_page.dart'; +import 'main.dart'; +import 'movie_detail.dart'; +import 'navigation_shell.dart'; +import 'sign_up.dart'; +import 'util/auth.dart'; + +var router = GoRouter(initialLocation: homePath.path, routes: [ + StatefulShellRoute.indexedStack( + builder: (context, state, navigationShell) { + return NavigationShell(navigationShell: navigationShell); + }, + branches: [ + StatefulShellBranch(routes: [ + GoRoute( + path: homePath.path, + builder: (context, state) => const MyHomePage(), + ), + GoRoute( + path: '/movies/:movieId', + builder: (context, state) => + MovieDetail(id: state.pathParameters['movieId']!)) + ]), + StatefulShellBranch( + routes: [ + GoRoute( + path: genrePath.path, + builder: (context, state) => const GenrePage(), + ), + GoRoute( + path: "/genres/:genre", + builder: (context, state) => + GenreListMovies(genre: state.pathParameters['genre']!), + ), + GoRoute( + path: "/actors", + redirect: (context, state) => + '/actors/${state.pathParameters['actorId']}', + routes: [ + GoRoute( + path: ":actorId", + builder: (context, state) => ActorDetail( + actorId: state.pathParameters['actorId']!)) + ]) + ], + ), + StatefulShellBranch(routes: [ + GoRoute( + path: "/search", + builder: (context, state) => const Text('abc'), + ), + ]), + StatefulShellBranch(routes: [ + GoRoute( + path: "/profile", + redirect: (context, state) async { + return (await Auth.isLoggedIn()) ? null : '/login'; + }, + builder: (context, state) => const Profile()), + GoRoute( + path: "/login", + builder: (context, state) => const Login(), + ), + GoRoute( + path: "/signup", + builder: (context, state) => const SignUp(), + ) + ]) + ]) +]); diff --git a/dataconnect/lib/sign_up.dart b/dataconnect/lib/sign_up.dart new file mode 100644 index 00000000..676f1387 --- /dev/null +++ b/dataconnect/lib/sign_up.dart @@ -0,0 +1,123 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class SignUp extends StatefulWidget { + const SignUp({super.key}); + + @override + State createState() => _SignUpState(); +} + +class _SignUpState extends State { + final _formKey = GlobalKey(); + String _username = ''; + String _password = ''; + String _confirmPassword = ''; + Widget _buildForm() { + return Form( + key: _formKey, + child: Column( + children: [ + TextFormField( + decoration: const InputDecoration( + hintText: "Email", border: OutlineInputBorder()), + onChanged: (value) { + setState(() { + _username = value; + }); + }, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + return null; + }, + ), + const SizedBox(height: 30), + TextFormField( + obscureText: true, + enableSuggestions: false, + autocorrect: false, + decoration: const InputDecoration( + hintText: "Password", border: OutlineInputBorder()), + onChanged: (value) { + setState(() { + _password = value; + }); + }, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter a password'; + } + if (value != _confirmPassword) { + return 'Passwords do not match'; + } + return null; + }, + ), + const SizedBox(height: 30), + TextFormField( + obscureText: true, + enableSuggestions: false, + autocorrect: false, + decoration: const InputDecoration( + hintText: "Confirm Password", border: OutlineInputBorder()), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + if (value != _password) { + return 'Passwords do not match'; + } + return null; + }, + onChanged: (value) { + setState(() { + _confirmPassword = value; + }); + }, + ), + ElevatedButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + signUp(); + } + }, + child: Text('Submit')) + ], + )); + } + + signUp() async { + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar(content: Text('Signing Up'))); + try { + await FirebaseAuth.instance.createUserWithEmailAndPassword( + email: _username, password: _password); + if (mounted) { + context.go('/home'); + } + } catch (e) { + print(e); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('There was an error when creating a user.'))); + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Padding( + padding: EdgeInsets.all(30), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [_buildForm()], + ))), + ); + } +} diff --git a/dataconnect/lib/util/auth.dart b/dataconnect/lib/util/auth.dart new file mode 100644 index 00000000..b31c1409 --- /dev/null +++ b/dataconnect/lib/util/auth.dart @@ -0,0 +1,12 @@ +import 'package:firebase_auth/firebase_auth.dart'; + +class Auth { + static isLoggedIn() async { + User? user = await FirebaseAuth.instance.authStateChanges().first; + return user != null; + } + + static getCurrentUser() { + return FirebaseAuth.instance.authStateChanges().first; + } +} diff --git a/dataconnect/pubspec.lock b/dataconnect/pubspec.lock index b7747825..54938821 100644 --- a/dataconnect/pubspec.lock +++ b/dataconnect/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: "5534e701a2c505fed1f0799e652dd6ae23bd4d2c4cf797220e5ced5764a7c1c2" + sha256: "71c01c1998c40b3af1944ad0a5f374b4e6fef7f3d2df487f3970dbeadaeb25a1" url: "https://pub.dev" source: hosted - version: "1.3.44" + version: "1.3.46" archive: dependency: transitive description: @@ -114,37 +114,37 @@ packages: source: hosted version: "0.2.0" firebase_auth: - dependency: transitive + dependency: "direct main" description: name: firebase_auth - sha256: d453acec0d958ba0e25d41a9901b32cb77d1535766903dea7a61b2788c304596 + sha256: "49c356bac95ed234805e3bb928a86d5b21a4d3745d77be53ecf2d61409ddb802" url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "5.3.3" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface - sha256: "78966c2ef774f5bf2a8381a307222867e9ece3509110500f7a138c115926aa65" + sha256: "9bc336ce673ea90a9dbdb04f0e9a3e52a32321898dc869cdefe6cc0f0db369ed" url: "https://pub.dev" source: hosted - version: "7.4.7" + version: "7.4.9" firebase_auth_web: dependency: transitive description: name: firebase_auth_web - sha256: "77ad3b252badedd3f08dfa21a4c7fe244be96c6da3a4067f253b13ea5d32424c" + sha256: "56dcce4293e2a2c648c33ab72c09e888bd0e64cbb1681a32575ec9dc9c2f67f3" url: "https://pub.dev" source: hosted - version: "5.13.2" + version: "5.13.4" firebase_core: dependency: "direct main" description: name: firebase_core - sha256: "51dfe2fbf3a984787a2e7b8592f2f05c986bfedd6fdacea3f9e0a7beb334de96" + sha256: "2438a75ad803e818ad3bd5df49137ee619c46b6fc7101f4dbc23da07305ce553" url: "https://pub.dev" source: hosted - version: "3.6.0" + version: "3.8.0" firebase_core_platform_interface: dependency: transitive description: diff --git a/dataconnect/pubspec.yaml b/dataconnect/pubspec.yaml index 5ff5570c..04c8f250 100644 --- a/dataconnect/pubspec.yaml +++ b/dataconnect/pubspec.yaml @@ -39,6 +39,7 @@ dependencies: firebase_core: ^3.6.0 go_router: ^14.5.0 intl: ^0.19.0 + firebase_auth: ^5.3.3 dev_dependencies: flutter_test: From f555797f315c2bfad44861e3c0c3ba49d18f8c1b Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 14 Nov 2024 15:19:20 -0800 Subject: [PATCH 03/17] Added signin/signup pages --- .../main/res/xml/network_security_config.xml | 6 + .../.dataconnect/schema/main/implicit.gql | 20 + .../.dataconnect/schema/main/input.gql | 320 ++++++ .../.dataconnect/schema/main/mutation.gql | 204 ++++ .../.dataconnect/schema/main/query.gql | 76 ++ .../.dataconnect/schema/main/relation.gql | 192 ++++ .../dataconnect/connector/mutations.gql | 14 +- dataconnect/dataconnect/connector/queries.gql | 50 +- .../movies_connector/add_favorited_movie.dart | 192 ---- .../lib/movies_connector/add_review.dart | 240 ---- .../delete_favorited_movie.dart | 194 ---- .../lib/movies_connector/get_actor_by_id.dart | 573 --------- .../movies_connector/get_current_user.dart | 763 ------------ .../get_if_favorited_movie.dart | 171 --- .../lib/movies_connector/get_movie_by_id.dart | 912 --------------- .../lib/movies_connector/list_movies.dart | 403 ------- .../lib/movies_connector/movies.dart | 136 --- .../lib/movies_connector/search_all.dart | 1021 ----------------- .../lib/movies_connector/update_review.dart | 242 ---- .../lib/movies_connector/upsert_user.dart | 169 --- dataconnect/dataconnect/moviedata_insert.gql | 6 +- dataconnect/dataconnect/schema/schema.gql | 13 + dataconnect/lib/extensions.dart | 49 + dataconnect/lib/login.dart | 3 + dataconnect/lib/movie_detail.dart | 107 +- .../lib/movies_connector/add_review.dart | 18 +- .../delete_favorited_actor.dart | 194 ++++ .../delete_watched_movie.dart} | 48 +- .../movies_connector/get_current_user.dart | 570 +++++++++ .../get_if_favorited_movie.dart | 171 --- .../get_movie_info_for_user.dart | 243 ++++ .../list_movies_by_partial_title.dart | 271 +++++ dataconnect/lib/movies_connector/movies.dart | 31 +- .../lib/movies_connector/upsert_user.dart | 28 +- dataconnect/lib/profile.dart | 42 +- dataconnect/lib/router.dart | 6 +- dataconnect/lib/search.dart | 270 +++++ dataconnect/lib/sign_up.dart | 24 +- dataconnect/lib/util/auth.dart | 13 +- dataconnect/lib/widgets/list_actors.dart | 64 ++ dataconnect/lib/widgets/list_movies.dart | 91 ++ dataconnect/lib/widgets/login_guard.dart | 38 + 42 files changed, 2912 insertions(+), 5286 deletions(-) create mode 100644 dataconnect/android/app/src/main/res/xml/network_security_config.xml delete mode 100644 dataconnect/dataconnect/lib/movies_connector/add_favorited_movie.dart delete mode 100644 dataconnect/dataconnect/lib/movies_connector/add_review.dart delete mode 100644 dataconnect/dataconnect/lib/movies_connector/delete_favorited_movie.dart delete mode 100644 dataconnect/dataconnect/lib/movies_connector/get_actor_by_id.dart delete mode 100644 dataconnect/dataconnect/lib/movies_connector/get_current_user.dart delete mode 100644 dataconnect/dataconnect/lib/movies_connector/get_if_favorited_movie.dart delete mode 100644 dataconnect/dataconnect/lib/movies_connector/get_movie_by_id.dart delete mode 100644 dataconnect/dataconnect/lib/movies_connector/list_movies.dart delete mode 100644 dataconnect/dataconnect/lib/movies_connector/movies.dart delete mode 100644 dataconnect/dataconnect/lib/movies_connector/search_all.dart delete mode 100644 dataconnect/dataconnect/lib/movies_connector/update_review.dart delete mode 100644 dataconnect/dataconnect/lib/movies_connector/upsert_user.dart create mode 100644 dataconnect/lib/extensions.dart create mode 100644 dataconnect/lib/movies_connector/delete_favorited_actor.dart rename dataconnect/{dataconnect/lib/movies_connector/delete_review.dart => lib/movies_connector/delete_watched_movie.dart} (50%) delete mode 100644 dataconnect/lib/movies_connector/get_if_favorited_movie.dart create mode 100644 dataconnect/lib/movies_connector/get_movie_info_for_user.dart create mode 100644 dataconnect/lib/movies_connector/list_movies_by_partial_title.dart create mode 100644 dataconnect/lib/search.dart create mode 100644 dataconnect/lib/widgets/list_actors.dart create mode 100644 dataconnect/lib/widgets/list_movies.dart create mode 100644 dataconnect/lib/widgets/login_guard.dart diff --git a/dataconnect/android/app/src/main/res/xml/network_security_config.xml b/dataconnect/android/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 00000000..17abf3ac --- /dev/null +++ b/dataconnect/android/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,6 @@ + + + + 10.0.2.2 + + \ No newline at end of file diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql b/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql index c7944ef7..a63e2f15 100644 --- a/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql +++ b/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql @@ -1,3 +1,13 @@ +extend type FavoriteActor { + """ + ✨ Implicit foreign key field based on `FavoriteActor`.`user`. It must match the value of `User`.`id`. See `@ref` for how to customize it. + """ + userId: String! @fdc_generated(from: "FavoriteActor.user", purpose: IMPLICIT_REF_FIELD) + """ + ✨ Implicit foreign key field based on `FavoriteActor`.`actor`. It must match the value of `Actor`.`id`. See `@ref` for how to customize it. + """ + actorId: UUID! @fdc_generated(from: "FavoriteActor.actor", purpose: IMPLICIT_REF_FIELD) +} extend type FavoriteMovie { """ ✨ Implicit foreign key field based on `FavoriteMovie`.`user`. It must match the value of `User`.`id`. See `@ref` for how to customize it. @@ -38,3 +48,13 @@ extend type Review { """ userId: String! @fdc_generated(from: "Review.user", purpose: IMPLICIT_REF_FIELD) } +extend type WatchedMovie { + """ + ✨ Implicit foreign key field based on `WatchedMovie`.`user`. It must match the value of `User`.`id`. See `@ref` for how to customize it. + """ + userId: String! @fdc_generated(from: "WatchedMovie.user", purpose: IMPLICIT_REF_FIELD) + """ + ✨ Implicit foreign key field based on `WatchedMovie`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it. + """ + movieId: UUID! @fdc_generated(from: "WatchedMovie.movie", purpose: IMPLICIT_REF_FIELD) +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/input.gql b/dataconnect/dataconnect/.dataconnect/schema/main/input.gql index 68d92f7e..8fae7303 100644 --- a/dataconnect/dataconnect/.dataconnect/schema/main/input.gql +++ b/dataconnect/dataconnect/.dataconnect/schema/main/input.gql @@ -5,6 +5,12 @@ It has the same format as `Actor_Key`, but is only used as mutation return value """ scalar Actor_KeyOutput """ +✨ `FavoriteActor_KeyOutput` returns the primary key fields of table type `FavoriteActor`. + +It has the same format as `FavoriteActor_Key`, but is only used as mutation return value. +""" +scalar FavoriteActor_KeyOutput +""" ✨ `FavoriteMovie_KeyOutput` returns the primary key fields of table type `FavoriteMovie`. It has the same format as `FavoriteMovie_Key`, but is only used as mutation return value. @@ -41,6 +47,12 @@ It has the same format as `User_Key`, but is only used as mutation return value. """ scalar User_KeyOutput """ +✨ `WatchedMovie_KeyOutput` returns the primary key fields of table type `WatchedMovie`. + +It has the same format as `WatchedMovie_Key`, but is only used as mutation return value. +""" +scalar WatchedMovie_KeyOutput +""" ✨ Generated data input type for table 'Actor'. It includes all necessary fields for creating or upserting rows into table. """ input Actor_Data { @@ -98,6 +110,10 @@ input Actor_Filter { """ name: String_Filter """ + ✨ Generated from Field `Actor`.`favorite_actors_on_actor` of type `[FavoriteActor!]!` + """ + favorite_actors_on_actor: FavoriteActor_ListFilter + """ ✨ Generated from Field `Actor`.`movieActors_on_actor` of type `[MovieActor!]!` """ movieActors_on_actor: MovieActor_ListFilter @@ -105,6 +121,10 @@ input Actor_Filter { ✨ Generated from Field `Actor`.`movies_via_MovieActor` of type `[Movie!]!` """ movies_via_MovieActor: Movie_ListFilter + """ + ✨ Generated from Field `Actor`.`users_via_FavoriteActor` of type `[User!]!` + """ + users_via_FavoriteActor: User_ListFilter } """ ✨ Generated first-row input type for table 'Actor'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. @@ -163,6 +183,136 @@ input Actor_Order { name: OrderDirection } """ +✨ Generated data input type for table 'FavoriteActor'. It includes all necessary fields for creating or upserting rows into table. +""" +input FavoriteActor_Data { + """ + ✨ Generated from Field `FavoriteActor`.`userId` of type `String!` + """ + userId: String + """ + ✨ `_expr` server value variant of `userId` (✨ Generated from Field `FavoriteActor`.`userId` of type `String!`) + """ + userId_expr: String_Expr + """ + ✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!` + """ + actorId: UUID + """ + ✨ `_expr` server value variant of `actorId` (✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!`) + """ + actorId_expr: UUID_Expr + """ + ✨ Generated from Field `FavoriteActor`.`actor` of type `Actor!` + """ + actor: Actor_Key + """ + ✨ Generated from Field `FavoriteActor`.`user` of type `User!` + """ + user: User_Key +} +""" +✨ Generated filter input type for table 'FavoriteActor'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. +""" +input FavoriteActor_Filter { + """ + Apply multiple filter conditions using `AND` logic. + """ + _and: [FavoriteActor_Filter!] + """ + Negate the result of the provided filter condition. + """ + _not: FavoriteActor_Filter + """ + Apply multiple filter conditions using `OR` logic. + """ + _or: [FavoriteActor_Filter!] + """ + ✨ Generated from Field `FavoriteActor`.`userId` of type `String!` + """ + userId: String_Filter + """ + ✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!` + """ + actorId: UUID_Filter + """ + ✨ Generated from Field `FavoriteActor`.`actor` of type `Actor!` + """ + actor: Actor_Filter + """ + ✨ Generated from Field `FavoriteActor`.`user` of type `User!` + """ + user: User_Filter +} +""" +✨ Generated first-row input type for table 'FavoriteActor'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. +""" +input FavoriteActor_FirstRow { + """ + Order the result by the specified fields. + """ + orderBy: [FavoriteActor_Order!] + """ + Filters rows based on the specified conditions. + """ + where: FavoriteActor_Filter +} +""" +✨ Generated key input type for table 'FavoriteActor'. It represents the primary key fields used to uniquely identify a row in the table. +""" +input FavoriteActor_Key { + """ + ✨ Generated from Field `FavoriteActor`.`userId` of type `String!` + """ + userId: String + """ + ✨ `_expr` server value variant of `userId` (✨ Generated from Field `FavoriteActor`.`userId` of type `String!`) + """ + userId_expr: String_Expr + """ + ✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!` + """ + actorId: UUID + """ + ✨ `_expr` server value variant of `actorId` (✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!`) + """ + actorId_expr: UUID_Expr +} +""" +✨ Generated list filter input type for table 'FavoriteActor'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. +""" +input FavoriteActor_ListFilter { + """ + The desired number of objects that match the condition (defaults to at least one). + """ + count: Int_Filter = {gt:0} + """ + Condition of the related objects to filter for. + """ + exist: FavoriteActor_Filter +} +""" +✨ Generated order input type for table 'FavoriteActor'. This input defines the sorting order of rows in query results based on one or more fields. +""" +input FavoriteActor_Order { + """ + ✨ Generated from Field `FavoriteActor`.`userId` of type `String!` + """ + userId: OrderDirection + """ + ✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!` + """ + actorId: OrderDirection + """ + ✨ Generated from Field `FavoriteActor`.`actor` of type `Actor!` + """ + actor: Actor_Order + """ + ✨ Generated from Field `FavoriteActor`.`user` of type `User!` + """ + user: User_Order +} +""" ✨ Generated data input type for table 'FavoriteMovie'. It includes all necessary fields for creating or upserting rows into table. """ input FavoriteMovie_Data { @@ -470,6 +620,10 @@ input Movie_Filter { """ reviews_on_movie: Review_ListFilter """ + ✨ Generated from Field `Movie`.`watched_movies_on_movie` of type `[WatchedMovie!]!` + """ + watched_movies_on_movie: WatchedMovie_ListFilter + """ ✨ Generated from Field `Movie`.`actors_via_MovieActor` of type `[Actor!]!` """ actors_via_MovieActor: Actor_ListFilter @@ -481,6 +635,10 @@ input Movie_Filter { ✨ Generated from Field `Movie`.`users_via_Review` of type `[User!]!` """ users_via_Review: User_ListFilter + """ + ✨ Generated from Field `Movie`.`users_via_WatchedMovie` of type `[User!]!` + """ + users_via_WatchedMovie: User_ListFilter } """ ✨ Generated first-row input type for table 'Movie'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. @@ -1033,6 +1191,14 @@ input User_Data { """ id_expr: String_Expr """ + ✨ Generated from Field `User`.`name` of type `String!` + """ + name: String + """ + ✨ `_expr` server value variant of `name` (✨ Generated from Field `User`.`name` of type `String!`) + """ + name_expr: String_Expr + """ ✨ Generated from Field `User`.`username` of type `String!` """ username: String @@ -1062,10 +1228,18 @@ input User_Filter { """ id: String_Filter """ + ✨ Generated from Field `User`.`name` of type `String!` + """ + name: String_Filter + """ ✨ Generated from Field `User`.`username` of type `String!` """ username: String_Filter """ + ✨ Generated from Field `User`.`favorite_actors_on_user` of type `[FavoriteActor!]!` + """ + favorite_actors_on_user: FavoriteActor_ListFilter + """ ✨ Generated from Field `User`.`favorite_movies_on_user` of type `[FavoriteMovie!]!` """ favorite_movies_on_user: FavoriteMovie_ListFilter @@ -1074,6 +1248,14 @@ input User_Filter { """ reviews_on_user: Review_ListFilter """ + ✨ Generated from Field `User`.`watched_movies_on_user` of type `[WatchedMovie!]!` + """ + watched_movies_on_user: WatchedMovie_ListFilter + """ + ✨ Generated from Field `User`.`actors_via_FavoriteActor` of type `[Actor!]!` + """ + actors_via_FavoriteActor: Actor_ListFilter + """ ✨ Generated from Field `User`.`movies_via_FavoriteMovie` of type `[Movie!]!` """ movies_via_FavoriteMovie: Movie_ListFilter @@ -1081,6 +1263,10 @@ input User_Filter { ✨ Generated from Field `User`.`movies_via_Review` of type `[Movie!]!` """ movies_via_Review: Movie_ListFilter + """ + ✨ Generated from Field `User`.`movies_via_WatchedMovie` of type `[Movie!]!` + """ + movies_via_WatchedMovie: Movie_ListFilter } """ ✨ Generated first-row input type for table 'User'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. @@ -1130,7 +1316,141 @@ input User_Order { """ id: OrderDirection """ + ✨ Generated from Field `User`.`name` of type `String!` + """ + name: OrderDirection + """ ✨ Generated from Field `User`.`username` of type `String!` """ username: OrderDirection } +""" +✨ Generated data input type for table 'WatchedMovie'. It includes all necessary fields for creating or upserting rows into table. +""" +input WatchedMovie_Data { + """ + ✨ Generated from Field `WatchedMovie`.`userId` of type `String!` + """ + userId: String + """ + ✨ `_expr` server value variant of `userId` (✨ Generated from Field `WatchedMovie`.`userId` of type `String!`) + """ + userId_expr: String_Expr + """ + ✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!` + """ + movieId: UUID + """ + ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!`) + """ + movieId_expr: UUID_Expr + """ + ✨ Generated from Field `WatchedMovie`.`movie` of type `Movie!` + """ + movie: Movie_Key + """ + ✨ Generated from Field `WatchedMovie`.`user` of type `User!` + """ + user: User_Key +} +""" +✨ Generated filter input type for table 'WatchedMovie'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. +""" +input WatchedMovie_Filter { + """ + Apply multiple filter conditions using `AND` logic. + """ + _and: [WatchedMovie_Filter!] + """ + Negate the result of the provided filter condition. + """ + _not: WatchedMovie_Filter + """ + Apply multiple filter conditions using `OR` logic. + """ + _or: [WatchedMovie_Filter!] + """ + ✨ Generated from Field `WatchedMovie`.`userId` of type `String!` + """ + userId: String_Filter + """ + ✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!` + """ + movieId: UUID_Filter + """ + ✨ Generated from Field `WatchedMovie`.`movie` of type `Movie!` + """ + movie: Movie_Filter + """ + ✨ Generated from Field `WatchedMovie`.`user` of type `User!` + """ + user: User_Filter +} +""" +✨ Generated first-row input type for table 'WatchedMovie'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. +""" +input WatchedMovie_FirstRow { + """ + Order the result by the specified fields. + """ + orderBy: [WatchedMovie_Order!] + """ + Filters rows based on the specified conditions. + """ + where: WatchedMovie_Filter +} +""" +✨ Generated key input type for table 'WatchedMovie'. It represents the primary key fields used to uniquely identify a row in the table. +""" +input WatchedMovie_Key { + """ + ✨ Generated from Field `WatchedMovie`.`userId` of type `String!` + """ + userId: String + """ + ✨ `_expr` server value variant of `userId` (✨ Generated from Field `WatchedMovie`.`userId` of type `String!`) + """ + userId_expr: String_Expr + """ + ✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!` + """ + movieId: UUID + """ + ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!`) + """ + movieId_expr: UUID_Expr +} +""" +✨ Generated list filter input type for table 'WatchedMovie'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. +""" +input WatchedMovie_ListFilter { + """ + The desired number of objects that match the condition (defaults to at least one). + """ + count: Int_Filter = {gt:0} + """ + Condition of the related objects to filter for. + """ + exist: WatchedMovie_Filter +} +""" +✨ Generated order input type for table 'WatchedMovie'. This input defines the sorting order of rows in query results based on one or more fields. +""" +input WatchedMovie_Order { + """ + ✨ Generated from Field `WatchedMovie`.`userId` of type `String!` + """ + userId: OrderDirection + """ + ✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!` + """ + movieId: OrderDirection + """ + ✨ Generated from Field `WatchedMovie`.`movie` of type `Movie!` + """ + movie: Movie_Order + """ + ✨ Generated from Field `WatchedMovie`.`user` of type `User!` + """ + user: User_Order +} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql index 1dad2178..aacee812 100644 --- a/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql +++ b/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql @@ -9,6 +9,15 @@ extend type Mutation { data: Actor_Data! ): Actor_KeyOutput! @fdc_generated(from: "Actor", purpose: INSERT_SINGLE) """ + ✨ Insert a single `FavoriteActor` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + favorite_actor_insert( + """ + Data object to insert into the table. + """ + data: FavoriteActor_Data! + ): FavoriteActor_KeyOutput! @fdc_generated(from: "FavoriteActor", purpose: INSERT_SINGLE) + """ ✨ Insert a single `FavoriteMovie` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). """ favorite_movie_insert( @@ -63,6 +72,15 @@ extend type Mutation { data: User_Data! ): User_KeyOutput! @fdc_generated(from: "User", purpose: INSERT_SINGLE) """ + ✨ Insert a single `WatchedMovie` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + watched_movie_insert( + """ + Data object to insert into the table. + """ + data: WatchedMovie_Data! + ): WatchedMovie_KeyOutput! @fdc_generated(from: "WatchedMovie", purpose: INSERT_SINGLE) + """ ✨ Insert `Actor` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). """ actor_insertMany( @@ -72,6 +90,15 @@ extend type Mutation { data: [Actor_Data!]! ): [Actor_KeyOutput!]! @fdc_generated(from: "Actor", purpose: INSERT_MULTIPLE) """ + ✨ Insert `FavoriteActor` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + favorite_actor_insertMany( + """ + List of data objects to insert into the table. + """ + data: [FavoriteActor_Data!]! + ): [FavoriteActor_KeyOutput!]! @fdc_generated(from: "FavoriteActor", purpose: INSERT_MULTIPLE) + """ ✨ Insert `FavoriteMovie` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). """ favorite_movie_insertMany( @@ -126,6 +153,15 @@ extend type Mutation { data: [User_Data!]! ): [User_KeyOutput!]! @fdc_generated(from: "User", purpose: INSERT_MULTIPLE) """ + ✨ Insert `WatchedMovie` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). + """ + watched_movie_insertMany( + """ + List of data objects to insert into the table. + """ + data: [WatchedMovie_Data!]! + ): [WatchedMovie_KeyOutput!]! @fdc_generated(from: "WatchedMovie", purpose: INSERT_MULTIPLE) + """ ✨ Insert or update a single `Actor` into the table, based on the primary key. Returns the key of the newly inserted `Actor`. """ actor_upsert( @@ -135,6 +171,15 @@ extend type Mutation { data: Actor_Data! ): Actor_KeyOutput! @fdc_generated(from: "Actor", purpose: UPSERT_SINGLE) """ + ✨ Insert or update a single `FavoriteActor` into the table, based on the primary key. Returns the key of the newly inserted `FavoriteActor`. + """ + favorite_actor_upsert( + """ + Data object to insert or update if it already exists. + """ + data: FavoriteActor_Data! + ): FavoriteActor_KeyOutput! @fdc_generated(from: "FavoriteActor", purpose: UPSERT_SINGLE) + """ ✨ Insert or update a single `FavoriteMovie` into the table, based on the primary key. Returns the key of the newly inserted `FavoriteMovie`. """ favorite_movie_upsert( @@ -189,6 +234,15 @@ extend type Mutation { data: User_Data! ): User_KeyOutput! @fdc_generated(from: "User", purpose: UPSERT_SINGLE) """ + ✨ Insert or update a single `WatchedMovie` into the table, based on the primary key. Returns the key of the newly inserted `WatchedMovie`. + """ + watched_movie_upsert( + """ + Data object to insert or update if it already exists. + """ + data: WatchedMovie_Data! + ): WatchedMovie_KeyOutput! @fdc_generated(from: "WatchedMovie", purpose: UPSERT_SINGLE) + """ ✨ Insert or update `Actor` objects into the table, based on the primary key. Returns the key of the newly inserted `Actor`. """ actor_upsertMany( @@ -198,6 +252,15 @@ extend type Mutation { data: [Actor_Data!]! ): [Actor_KeyOutput!]! @fdc_generated(from: "Actor", purpose: UPSERT_MULTIPLE) """ + ✨ Insert or update `FavoriteActor` objects into the table, based on the primary key. Returns the key of the newly inserted `FavoriteActor`. + """ + favorite_actor_upsertMany( + """ + List of data objects to insert or update if it already exists. + """ + data: [FavoriteActor_Data!]! + ): [FavoriteActor_KeyOutput!]! @fdc_generated(from: "FavoriteActor", purpose: UPSERT_MULTIPLE) + """ ✨ Insert or update `FavoriteMovie` objects into the table, based on the primary key. Returns the key of the newly inserted `FavoriteMovie`. """ favorite_movie_upsertMany( @@ -252,6 +315,15 @@ extend type Mutation { data: [User_Data!]! ): [User_KeyOutput!]! @fdc_generated(from: "User", purpose: UPSERT_MULTIPLE) """ + ✨ Insert or update `WatchedMovie` objects into the table, based on the primary key. Returns the key of the newly inserted `WatchedMovie`. + """ + watched_movie_upsertMany( + """ + List of data objects to insert or update if it already exists. + """ + data: [WatchedMovie_Data!]! + ): [WatchedMovie_KeyOutput!]! @fdc_generated(from: "WatchedMovie", purpose: UPSERT_MULTIPLE) + """ ✨ Update a single `Actor` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. """ actor_update( @@ -276,6 +348,25 @@ extend type Mutation { data: Actor_Data! ): Actor_KeyOutput @fdc_generated(from: "Actor", purpose: UPDATE_SINGLE) """ + ✨ Update a single `FavoriteActor` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. + """ + favorite_actor_update( + """ + The key used to identify the object. + """ + key: FavoriteActor_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: FavoriteActor_FirstRow + + """ + Data object containing fields to be updated. + """ + data: FavoriteActor_Data! + ): FavoriteActor_KeyOutput @fdc_generated(from: "FavoriteActor", purpose: UPDATE_SINGLE) + """ ✨ Update a single `FavoriteMovie` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. """ favorite_movie_update( @@ -410,6 +501,25 @@ extend type Mutation { data: User_Data! ): User_KeyOutput @fdc_generated(from: "User", purpose: UPDATE_SINGLE) """ + ✨ Update a single `WatchedMovie` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. + """ + watched_movie_update( + """ + The key used to identify the object. + """ + key: WatchedMovie_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: WatchedMovie_FirstRow + + """ + Data object containing fields to be updated. + """ + data: WatchedMovie_Data! + ): WatchedMovie_KeyOutput @fdc_generated(from: "WatchedMovie", purpose: UPDATE_SINGLE) + """ ✨ Update `Actor` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. """ actor_updateMany( @@ -429,6 +539,25 @@ extend type Mutation { data: Actor_Data! ): Int! @fdc_generated(from: "Actor", purpose: UPDATE_MULTIPLE) """ + ✨ Update `FavoriteActor` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + favorite_actor_updateMany( + """ + Filter condition to specify which rows to update. + """ + where: FavoriteActor_Filter + + """ + Set to true to update all rows. + """ + all: Boolean = false + + """ + Data object containing fields to update. + """ + data: FavoriteActor_Data! + ): Int! @fdc_generated(from: "FavoriteActor", purpose: UPDATE_MULTIPLE) + """ ✨ Update `FavoriteMovie` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. """ favorite_movie_updateMany( @@ -543,6 +672,25 @@ extend type Mutation { data: User_Data! ): Int! @fdc_generated(from: "User", purpose: UPDATE_MULTIPLE) """ + ✨ Update `WatchedMovie` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. + """ + watched_movie_updateMany( + """ + Filter condition to specify which rows to update. + """ + where: WatchedMovie_Filter + + """ + Set to true to update all rows. + """ + all: Boolean = false + + """ + Data object containing fields to update. + """ + data: WatchedMovie_Data! + ): Int! @fdc_generated(from: "WatchedMovie", purpose: UPDATE_MULTIPLE) + """ ✨ Delete a single `Actor` based on `id`, `key` or `first` and return its key (or `null` if not found). """ actor_delete( @@ -562,6 +710,20 @@ extend type Mutation { first: Actor_FirstRow ): Actor_KeyOutput @fdc_generated(from: "Actor", purpose: DELETE_SINGLE) """ + ✨ Delete a single `FavoriteActor` based on `id`, `key` or `first` and return its key (or `null` if not found). + """ + favorite_actor_delete( + """ + The key used to identify the object. + """ + key: FavoriteActor_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: FavoriteActor_FirstRow + ): FavoriteActor_KeyOutput @fdc_generated(from: "FavoriteActor", purpose: DELETE_SINGLE) + """ ✨ Delete a single `FavoriteMovie` based on `id`, `key` or `first` and return its key (or `null` if not found). """ favorite_movie_delete( @@ -666,6 +828,20 @@ extend type Mutation { first: User_FirstRow ): User_KeyOutput @fdc_generated(from: "User", purpose: DELETE_SINGLE) """ + ✨ Delete a single `WatchedMovie` based on `id`, `key` or `first` and return its key (or `null` if not found). + """ + watched_movie_delete( + """ + The key used to identify the object. + """ + key: WatchedMovie_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: WatchedMovie_FirstRow + ): WatchedMovie_KeyOutput @fdc_generated(from: "WatchedMovie", purpose: DELETE_SINGLE) + """ ✨ Delete `Actor` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. """ actor_deleteMany( @@ -680,6 +856,20 @@ extend type Mutation { all: Boolean = false ): Int! @fdc_generated(from: "Actor", purpose: DELETE_MULTIPLE) """ + ✨ Delete `FavoriteActor` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + favorite_actor_deleteMany( + """ + Filter condition to specify which rows to delete. + """ + where: FavoriteActor_Filter + + """ + Set to true to delete all rows. + """ + all: Boolean = false + ): Int! @fdc_generated(from: "FavoriteActor", purpose: DELETE_MULTIPLE) + """ ✨ Delete `FavoriteMovie` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. """ favorite_movie_deleteMany( @@ -763,4 +953,18 @@ extend type Mutation { """ all: Boolean = false ): Int! @fdc_generated(from: "User", purpose: DELETE_MULTIPLE) + """ + ✨ Delete `WatchedMovie` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. + """ + watched_movie_deleteMany( + """ + Filter condition to specify which rows to delete. + """ + where: WatchedMovie_Filter + + """ + Set to true to delete all rows. + """ + all: Boolean = false + ): Int! @fdc_generated(from: "WatchedMovie", purpose: DELETE_MULTIPLE) } diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/query.gql b/dataconnect/dataconnect/.dataconnect/schema/main/query.gql index a2f3bc6f..ed0a411d 100644 --- a/dataconnect/dataconnect/.dataconnect/schema/main/query.gql +++ b/dataconnect/dataconnect/.dataconnect/schema/main/query.gql @@ -19,6 +19,20 @@ extend type Query { first: Actor_FirstRow ): Actor @fdc_generated(from: "Actor", purpose: QUERY_SINGLE) """ + ✨ Look up a single `FavoriteActor` based on `id`, `key` or `first` and return selected fields (or `null` if not found). + """ + favorite_actor( + """ + The key used to identify the object. + """ + key: FavoriteActor_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: FavoriteActor_FirstRow + ): FavoriteActor @fdc_generated(from: "FavoriteActor", purpose: QUERY_SINGLE) + """ ✨ Look up a single `FavoriteMovie` based on `id`, `key` or `first` and return selected fields (or `null` if not found). """ favorite_movie( @@ -123,6 +137,20 @@ extend type Query { first: User_FirstRow ): User @fdc_generated(from: "User", purpose: QUERY_SINGLE) """ + ✨ Look up a single `WatchedMovie` based on `id`, `key` or `first` and return selected fields (or `null` if not found). + """ + watched_movie( + """ + The key used to identify the object. + """ + key: WatchedMovie_Key + + """ + Fetch the first row based on the filters and ordering. + """ + first: WatchedMovie_FirstRow + ): WatchedMovie @fdc_generated(from: "WatchedMovie", purpose: QUERY_SINGLE) + """ ✨ List `Actor` objects in the table, optionally filtered by `where` conditions. """ actors( @@ -147,6 +175,30 @@ extend type Query { limit: Int = 100 ): [Actor!]! @fdc_generated(from: "Actor", purpose: QUERY_MULTIPLE) """ + ✨ List `FavoriteActor` objects in the table, optionally filtered by `where` conditions. + """ + favorite_actors( + """ + Filter condition to narrow down the query results. + """ + where: FavoriteActor_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [FavoriteActor_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [FavoriteActor!]! @fdc_generated(from: "FavoriteActor", purpose: QUERY_MULTIPLE) + """ ✨ List `FavoriteMovie` objects in the table, optionally filtered by `where` conditions. """ favorite_movies( @@ -314,4 +366,28 @@ extend type Query { """ limit: Int = 100 ): [User!]! @fdc_generated(from: "User", purpose: QUERY_MULTIPLE) + """ + ✨ List `WatchedMovie` objects in the table, optionally filtered by `where` conditions. + """ + watched_movies( + """ + Filter condition to narrow down the query results. + """ + where: WatchedMovie_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [WatchedMovie_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [WatchedMovie!]! @fdc_generated(from: "WatchedMovie", purpose: QUERY_MULTIPLE) } diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql index 5b1d7799..9f73ee86 100644 --- a/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql +++ b/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql @@ -1,4 +1,28 @@ extend type Actor { + """ + ✨ List `FavoriteActor` objects in a one-to-many relationship (where `FavoriteActor`.`actor` is this object). + """ + favorite_actors_on_actor( + """ + Filter condition to narrow down the query results. + """ + where: FavoriteActor_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [FavoriteActor_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [FavoriteActor!]! @fdc_generated(from: "FavoriteActor.actor", purpose: QUERY_MULTIPLE_ONE_TO_MANY) """ ✨ List `MovieActor` objects in a one-to-many relationship (where `MovieActor`.`actor` is this object). """ @@ -47,6 +71,30 @@ extend type Actor { """ limit: Int = 100 ): [Movie!]! @fdc_generated(from: "MovieActor", purpose: QUERY_MULTIPLE_MANY_TO_MANY) + """ + ✨ List `User` objects using `FavoriteActor` as the join table (a `FavoriteActor` object exists where its `actor` is this and its `user` is that). + """ + users_via_FavoriteActor( + """ + Filter condition to narrow down the query results. + """ + where: FavoriteActor_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [FavoriteActor_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [User!]! @fdc_generated(from: "FavoriteActor", purpose: QUERY_MULTIPLE_MANY_TO_MANY) } extend type Movie { """ @@ -146,6 +194,30 @@ extend type Movie { limit: Int = 100 ): [Review!]! @fdc_generated(from: "Review.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY) """ + ✨ List `WatchedMovie` objects in a one-to-many relationship (where `WatchedMovie`.`movie` is this object). + """ + watched_movies_on_movie( + """ + Filter condition to narrow down the query results. + """ + where: WatchedMovie_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [WatchedMovie_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [WatchedMovie!]! @fdc_generated(from: "WatchedMovie.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY) + """ ✨ List `Actor` objects using `MovieActor` as the join table (a `MovieActor` object exists where its `movie` is this and its `actor` is that). """ actors_via_MovieActor( @@ -217,8 +289,56 @@ extend type Movie { """ limit: Int = 100 ): [User!]! @fdc_generated(from: "Review", purpose: QUERY_MULTIPLE_MANY_TO_MANY) + """ + ✨ List `User` objects using `WatchedMovie` as the join table (a `WatchedMovie` object exists where its `movie` is this and its `user` is that). + """ + users_via_WatchedMovie( + """ + Filter condition to narrow down the query results. + """ + where: WatchedMovie_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [WatchedMovie_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [User!]! @fdc_generated(from: "WatchedMovie", purpose: QUERY_MULTIPLE_MANY_TO_MANY) } extend type User { + """ + ✨ List `FavoriteActor` objects in a one-to-many relationship (where `FavoriteActor`.`user` is this object). + """ + favorite_actors_on_user( + """ + Filter condition to narrow down the query results. + """ + where: FavoriteActor_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [FavoriteActor_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [FavoriteActor!]! @fdc_generated(from: "FavoriteActor.user", purpose: QUERY_MULTIPLE_ONE_TO_MANY) """ ✨ List `FavoriteMovie` objects in a one-to-many relationship (where `FavoriteMovie`.`user` is this object). """ @@ -268,6 +388,54 @@ extend type User { limit: Int = 100 ): [Review!]! @fdc_generated(from: "Review.user", purpose: QUERY_MULTIPLE_ONE_TO_MANY) """ + ✨ List `WatchedMovie` objects in a one-to-many relationship (where `WatchedMovie`.`user` is this object). + """ + watched_movies_on_user( + """ + Filter condition to narrow down the query results. + """ + where: WatchedMovie_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [WatchedMovie_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [WatchedMovie!]! @fdc_generated(from: "WatchedMovie.user", purpose: QUERY_MULTIPLE_ONE_TO_MANY) + """ + ✨ List `Actor` objects using `FavoriteActor` as the join table (a `FavoriteActor` object exists where its `user` is this and its `actor` is that). + """ + actors_via_FavoriteActor( + """ + Filter condition to narrow down the query results. + """ + where: FavoriteActor_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [FavoriteActor_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [Actor!]! @fdc_generated(from: "FavoriteActor", purpose: QUERY_MULTIPLE_MANY_TO_MANY) + """ ✨ List `Movie` objects using `FavoriteMovie` as the join table (a `FavoriteMovie` object exists where its `user` is this and its `movie` is that). """ movies_via_FavoriteMovie( @@ -315,4 +483,28 @@ extend type User { """ limit: Int = 100 ): [Movie!]! @fdc_generated(from: "Review", purpose: QUERY_MULTIPLE_MANY_TO_MANY) + """ + ✨ List `Movie` objects using `WatchedMovie` as the join table (a `WatchedMovie` object exists where its `user` is this and its `movie` is that). + """ + movies_via_WatchedMovie( + """ + Filter condition to narrow down the query results. + """ + where: WatchedMovie_Filter + + """ + Order the query results by specific fields. + """ + orderBy: [WatchedMovie_Order!] + + """ + Number of rows to skip before starting to return the results. + """ + offset: Int + + """ + Maximum number of rows to return (defaults to 100 rows). + """ + limit: Int = 100 + ): [Movie!]! @fdc_generated(from: "WatchedMovie", purpose: QUERY_MULTIPLE_MANY_TO_MANY) } diff --git a/dataconnect/dataconnect/connector/mutations.gql b/dataconnect/dataconnect/connector/mutations.gql index 0d7545e4..1498eeb4 100644 --- a/dataconnect/dataconnect/connector/mutations.gql +++ b/dataconnect/dataconnect/connector/mutations.gql @@ -1,8 +1,9 @@ -mutation UpsertUser($username: String!) @auth(level: USER) { +mutation UpsertUser($username: String!, $name: String!) @auth(level: USER) { user_upsert( data: { id_expr: "auth.uid" username: $username + name: $name } ) } @@ -12,15 +13,24 @@ mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) { favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId }) } + # Remove a movie from the user's favorites list mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) { favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId }) } +# Add a movie to the user's favorites list +mutation DeleteFavoritedActor($actorId: UUID!) @auth(level: USER) { + favorite_actor_delete(key: { userId_expr: "auth.uid", actorId: $actorId }) +} +mutation DeleteWatchedMovie($movieId: UUID!) @auth(level: USER) { + watched_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId }) +} + # Add a review for a movie mutation AddReview($movieId: UUID!, $rating: Int!, $reviewText: String!) @auth(level: USER) { - review_insert( + review_upsert( data: { userId_expr: "auth.uid" movieId: $movieId diff --git a/dataconnect/dataconnect/connector/queries.gql b/dataconnect/dataconnect/connector/queries.gql index 67e09571..cd54b43d 100644 --- a/dataconnect/dataconnect/connector/queries.gql +++ b/dataconnect/dataconnect/connector/queries.gql @@ -114,6 +114,7 @@ query GetCurrentUser @auth(level: USER) { user(key: { id_expr: "auth.uid" }) { id username + name reviews: reviews_on_user { id rating @@ -139,15 +140,42 @@ query GetCurrentUser @auth(level: USER) { } } } + favoriteActors: favorite_actors_on_user { + actor { + id + name + imageUrl + } + } + watchedMovies: watched_movies_on_user { + movie { + id + title + genre + imageUrl + releaseYear + rating + description + tags + metadata: movieMetadatas_on_movie { + director + } + } + } + } } -query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) { +query GetMovieInfoForUser($movieId: UUID!) @auth(level: USER) { favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) { movieId } + watched_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) { + movieId + } } + # Search for movies, actors, and reviews query SearchAll( $input: String @@ -236,16 +264,16 @@ query SearchAll( # # The queries below are unused by the application, but are useful examples for more complex cases -# # List movies by partial title match -# query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) { -# movies(where: { title: { contains: $input } }) { -# id -# title -# genre -# rating -# imageUrl -# } -# } +# List movies by partial title match +query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) { + movies(where: { title: { contains: $input } }) { + id + title + genre + rating + imageUrl + } +} # # List movies by tag # query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) { diff --git a/dataconnect/dataconnect/lib/movies_connector/add_favorited_movie.dart b/dataconnect/dataconnect/lib/movies_connector/add_favorited_movie.dart deleted file mode 100644 index 9f2a90b9..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/add_favorited_movie.dart +++ /dev/null @@ -1,192 +0,0 @@ -part of movies_connector; - -class AddFavoritedMovieVariablesBuilder { - String movieId; - - - FirebaseDataConnect _dataConnect; - - AddFavoritedMovieVariablesBuilder(this._dataConnect, {required String this.movieId,}); - Deserializer dataDeserializer = (dynamic json) => AddFavoritedMovieData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (AddFavoritedMovieVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - MutationRef ref() { - AddFavoritedMovieVariables vars=AddFavoritedMovieVariables(movieId: movieId,); - - return _dataConnect.mutation("AddFavoritedMovie", dataDeserializer, varsSerializer, vars); - } -} - - - class AddFavoritedMovieFavoriteMovieUpsert { - - String userId; - - - String movieId; - - - - - - - AddFavoritedMovieFavoriteMovieUpsert.fromJson(dynamic json): - userId = - - nativeFromJson(json['userId']) - - - - , - - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['userId'] = - - nativeToJson(userId) - -; - - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - AddFavoritedMovieFavoriteMovieUpsert({ - - required this.userId, - - required this.movieId, - - }); -} - - - - class AddFavoritedMovieData { - - AddFavoritedMovieFavoriteMovieUpsert favorite_movie_upsert; - - - - - - - AddFavoritedMovieData.fromJson(dynamic json): - favorite_movie_upsert = - - AddFavoritedMovieFavoriteMovieUpsert.fromJson(json['favorite_movie_upsert']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['favorite_movie_upsert'] = - - favorite_movie_upsert.toJson() - -; - - - return json; - } - - AddFavoritedMovieData({ - - required this.favorite_movie_upsert, - - }); -} - - - - class AddFavoritedMovieVariables { - - String movieId; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - AddFavoritedMovieVariables.fromJson(Map json): - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - AddFavoritedMovieVariables({ - - required this.movieId, - - }); -} - - - - - - - diff --git a/dataconnect/dataconnect/lib/movies_connector/add_review.dart b/dataconnect/dataconnect/lib/movies_connector/add_review.dart deleted file mode 100644 index 1205433f..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/add_review.dart +++ /dev/null @@ -1,240 +0,0 @@ -part of movies_connector; - -class AddReviewVariablesBuilder { - String movieId; -int rating; -String reviewText; - - - FirebaseDataConnect _dataConnect; - - AddReviewVariablesBuilder(this._dataConnect, {required String this.movieId,required int this.rating,required String this.reviewText,}); - Deserializer dataDeserializer = (dynamic json) => AddReviewData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (AddReviewVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - MutationRef ref() { - AddReviewVariables vars=AddReviewVariables(movieId: movieId,rating: rating,reviewText: reviewText,); - - return _dataConnect.mutation("AddReview", dataDeserializer, varsSerializer, vars); - } -} - - - class AddReviewReviewInsert { - - String userId; - - - String movieId; - - - - - - - AddReviewReviewInsert.fromJson(dynamic json): - userId = - - nativeFromJson(json['userId']) - - - - , - - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['userId'] = - - nativeToJson(userId) - -; - - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - AddReviewReviewInsert({ - - required this.userId, - - required this.movieId, - - }); -} - - - - class AddReviewData { - - AddReviewReviewInsert review_insert; - - - - - - - AddReviewData.fromJson(dynamic json): - review_insert = - - AddReviewReviewInsert.fromJson(json['review_insert']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['review_insert'] = - - review_insert.toJson() - -; - - - return json; - } - - AddReviewData({ - - required this.review_insert, - - }); -} - - - - class AddReviewVariables { - - String movieId; - - - int rating; - - - String reviewText; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - AddReviewVariables.fromJson(Map json): - movieId = - - nativeFromJson(json['movieId']) - - - - , - - rating = - - nativeFromJson(json['rating']) - - - - , - - reviewText = - - nativeFromJson(json['reviewText']) - - - - - { - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - - json['rating'] = - - nativeToJson(rating) - -; - - - - json['reviewText'] = - - nativeToJson(reviewText) - -; - - - return json; - } - - AddReviewVariables({ - - required this.movieId, - - required this.rating, - - required this.reviewText, - - }); -} - - - - - - - diff --git a/dataconnect/dataconnect/lib/movies_connector/delete_favorited_movie.dart b/dataconnect/dataconnect/lib/movies_connector/delete_favorited_movie.dart deleted file mode 100644 index 2071ee5d..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/delete_favorited_movie.dart +++ /dev/null @@ -1,194 +0,0 @@ -part of movies_connector; - -class DeleteFavoritedMovieVariablesBuilder { - String movieId; - - - FirebaseDataConnect _dataConnect; - - DeleteFavoritedMovieVariablesBuilder(this._dataConnect, {required String this.movieId,}); - Deserializer dataDeserializer = (dynamic json) => DeleteFavoritedMovieData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (DeleteFavoritedMovieVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - MutationRef ref() { - DeleteFavoritedMovieVariables vars=DeleteFavoritedMovieVariables(movieId: movieId,); - - return _dataConnect.mutation("DeleteFavoritedMovie", dataDeserializer, varsSerializer, vars); - } -} - - - class DeleteFavoritedMovieFavoriteMovieDelete { - - String userId; - - - String movieId; - - - - - - - DeleteFavoritedMovieFavoriteMovieDelete.fromJson(dynamic json): - userId = - - nativeFromJson(json['userId']) - - - - , - - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['userId'] = - - nativeToJson(userId) - -; - - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - DeleteFavoritedMovieFavoriteMovieDelete({ - - required this.userId, - - required this.movieId, - - }); -} - - - - class DeleteFavoritedMovieData { - - DeleteFavoritedMovieFavoriteMovieDelete? favorite_movie_delete; - - - - - - - DeleteFavoritedMovieData.fromJson(dynamic json): - favorite_movie_delete = json['favorite_movie_delete'] == null ? null : - - DeleteFavoritedMovieFavoriteMovieDelete.fromJson(json['favorite_movie_delete']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (favorite_movie_delete != null) { - json['favorite_movie_delete'] = - - favorite_movie_delete!.toJson() - -; - } - - - return json; - } - - DeleteFavoritedMovieData({ - - this.favorite_movie_delete, - - }); -} - - - - class DeleteFavoritedMovieVariables { - - String movieId; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - DeleteFavoritedMovieVariables.fromJson(Map json): - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - DeleteFavoritedMovieVariables({ - - required this.movieId, - - }); -} - - - - - - - diff --git a/dataconnect/dataconnect/lib/movies_connector/get_actor_by_id.dart b/dataconnect/dataconnect/lib/movies_connector/get_actor_by_id.dart deleted file mode 100644 index 5400fa07..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/get_actor_by_id.dart +++ /dev/null @@ -1,573 +0,0 @@ -part of movies_connector; - -class GetActorByIdVariablesBuilder { - String id; - - - FirebaseDataConnect _dataConnect; - - GetActorByIdVariablesBuilder(this._dataConnect, {required String this.id,}); - Deserializer dataDeserializer = (dynamic json) => GetActorByIdData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (GetActorByIdVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - QueryRef ref() { - GetActorByIdVariables vars=GetActorByIdVariables(id: id,); - - return _dataConnect.query("GetActorById", dataDeserializer, varsSerializer, vars); - } -} - - - class GetActorByIdActor { - - String id; - - - String name; - - - String imageUrl; - - - List mainActors; - - - List supportingActors; - - - - - - - GetActorByIdActor.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - name = - - nativeFromJson(json['name']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - , - - mainActors = - - - (json['mainActors'] as List) - .map((e) => GetActorByIdActorMainActors.fromJson(e)) - .toList() - - - - - , - - supportingActors = - - - (json['supportingActors'] as List) - .map((e) => GetActorByIdActorSupportingActors.fromJson(e)) - .toList() - - - - - - { - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['name'] = - - nativeToJson(name) - -; - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - - json['mainActors'] = - - - mainActors.map((e) => e.toJson()).toList() - - -; - - - - json['supportingActors'] = - - - supportingActors.map((e) => e.toJson()).toList() - - -; - - - return json; - } - - GetActorByIdActor({ - - required this.id, - - required this.name, - - required this.imageUrl, - - required this.mainActors, - - required this.supportingActors, - - }); -} - - - - class GetActorByIdActorMainActors { - - String id; - - - String title; - - - String? genre; - - - List? tags; - - - String imageUrl; - - - - - - - GetActorByIdActorMainActors.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - title = - - nativeFromJson(json['title']) - - - - , - - genre = json['genre'] == null ? null : - - nativeFromJson(json['genre']) - - - - , - - tags = json['tags'] == null ? null : - - - (json['tags'] as List) - .map((e) => nativeFromJson(e)) - .toList() - - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - - { - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['title'] = - - nativeToJson(title) - -; - - - - if (genre != null) { - json['genre'] = - - nativeToJson(genre) - -; - } - - - - if (tags != null) { - json['tags'] = - - - tags?.map((e) => nativeToJson(e)).toList() - - -; - } - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - return json; - } - - GetActorByIdActorMainActors({ - - required this.id, - - required this.title, - - this.genre, - - this.tags, - - required this.imageUrl, - - }); -} - - - - class GetActorByIdActorSupportingActors { - - String id; - - - String title; - - - String? genre; - - - List? tags; - - - String imageUrl; - - - - - - - GetActorByIdActorSupportingActors.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - title = - - nativeFromJson(json['title']) - - - - , - - genre = json['genre'] == null ? null : - - nativeFromJson(json['genre']) - - - - , - - tags = json['tags'] == null ? null : - - - (json['tags'] as List) - .map((e) => nativeFromJson(e)) - .toList() - - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - - { - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['title'] = - - nativeToJson(title) - -; - - - - if (genre != null) { - json['genre'] = - - nativeToJson(genre) - -; - } - - - - if (tags != null) { - json['tags'] = - - - tags?.map((e) => nativeToJson(e)).toList() - - -; - } - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - return json; - } - - GetActorByIdActorSupportingActors({ - - required this.id, - - required this.title, - - this.genre, - - this.tags, - - required this.imageUrl, - - }); -} - - - - class GetActorByIdData { - - GetActorByIdActor? actor; - - - - - - - GetActorByIdData.fromJson(dynamic json): - actor = json['actor'] == null ? null : - - GetActorByIdActor.fromJson(json['actor']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (actor != null) { - json['actor'] = - - actor!.toJson() - -; - } - - - return json; - } - - GetActorByIdData({ - - this.actor, - - }); -} - - - - class GetActorByIdVariables { - - String id; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - GetActorByIdVariables.fromJson(Map json): - id = - - nativeFromJson(json['id']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - return json; - } - - GetActorByIdVariables({ - - required this.id, - - }); -} - - - - - - - diff --git a/dataconnect/dataconnect/lib/movies_connector/get_current_user.dart b/dataconnect/dataconnect/lib/movies_connector/get_current_user.dart deleted file mode 100644 index 38a7e191..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/get_current_user.dart +++ /dev/null @@ -1,763 +0,0 @@ -part of movies_connector; - -class GetCurrentUserVariablesBuilder { - - - FirebaseDataConnect _dataConnect; - - GetCurrentUserVariablesBuilder(this._dataConnect, ); - Deserializer dataDeserializer = (dynamic json) => GetCurrentUserData.fromJson(jsonDecode(json)); - - Future> execute() { - return this.ref().execute(); - } - QueryRef ref() { - - return _dataConnect.query("GetCurrentUser", dataDeserializer, emptySerializer, null); - } -} - - - class GetCurrentUserUser { - - String id; - - - String username; - - - List reviews; - - - List favoriteMovies; - - - - - - - GetCurrentUserUser.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - username = - - nativeFromJson(json['username']) - - - - , - - reviews = - - - (json['reviews'] as List) - .map((e) => GetCurrentUserUserReviews.fromJson(e)) - .toList() - - - - - , - - favoriteMovies = - - - (json['favoriteMovies'] as List) - .map((e) => GetCurrentUserUserFavoriteMovies.fromJson(e)) - .toList() - - - - - - { - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['username'] = - - nativeToJson(username) - -; - - - - json['reviews'] = - - - reviews.map((e) => e.toJson()).toList() - - -; - - - - json['favoriteMovies'] = - - - favoriteMovies.map((e) => e.toJson()).toList() - - -; - - - return json; - } - - GetCurrentUserUser({ - - required this.id, - - required this.username, - - required this.reviews, - - required this.favoriteMovies, - - }); -} - - - - class GetCurrentUserUserReviews { - - String id; - - - int? rating; - - - DateTime reviewDate; - - - String? reviewText; - - - GetCurrentUserUserReviewsMovie movie; - - - - - - - GetCurrentUserUserReviews.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - rating = json['rating'] == null ? null : - - nativeFromJson(json['rating']) - - - - , - - reviewDate = - - nativeFromJson(json['reviewDate']) - - - - , - - reviewText = json['reviewText'] == null ? null : - - nativeFromJson(json['reviewText']) - - - - , - - movie = - - GetCurrentUserUserReviewsMovie.fromJson(json['movie']) - - - - - { - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - if (rating != null) { - json['rating'] = - - nativeToJson(rating) - -; - } - - - - json['reviewDate'] = - - nativeToJson(reviewDate) - -; - - - - if (reviewText != null) { - json['reviewText'] = - - nativeToJson(reviewText) - -; - } - - - - json['movie'] = - - movie.toJson() - -; - - - return json; - } - - GetCurrentUserUserReviews({ - - required this.id, - - this.rating, - - required this.reviewDate, - - this.reviewText, - - required this.movie, - - }); -} - - - - class GetCurrentUserUserReviewsMovie { - - String id; - - - String title; - - - - - - - GetCurrentUserUserReviewsMovie.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - title = - - nativeFromJson(json['title']) - - - - - { - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['title'] = - - nativeToJson(title) - -; - - - return json; - } - - GetCurrentUserUserReviewsMovie({ - - required this.id, - - required this.title, - - }); -} - - - - class GetCurrentUserUserFavoriteMovies { - - GetCurrentUserUserFavoriteMoviesMovie movie; - - - - - - - GetCurrentUserUserFavoriteMovies.fromJson(dynamic json): - movie = - - GetCurrentUserUserFavoriteMoviesMovie.fromJson(json['movie']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['movie'] = - - movie.toJson() - -; - - - return json; - } - - GetCurrentUserUserFavoriteMovies({ - - required this.movie, - - }); -} - - - - class GetCurrentUserUserFavoriteMoviesMovie { - - String id; - - - String title; - - - String? genre; - - - String imageUrl; - - - int? releaseYear; - - - double? rating; - - - String? description; - - - List? tags; - - - List metadata; - - - - - - - GetCurrentUserUserFavoriteMoviesMovie.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - title = - - nativeFromJson(json['title']) - - - - , - - genre = json['genre'] == null ? null : - - nativeFromJson(json['genre']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - , - - releaseYear = json['releaseYear'] == null ? null : - - nativeFromJson(json['releaseYear']) - - - - , - - rating = json['rating'] == null ? null : - - nativeFromJson(json['rating']) - - - - , - - description = json['description'] == null ? null : - - nativeFromJson(json['description']) - - - - , - - tags = json['tags'] == null ? null : - - - (json['tags'] as List) - .map((e) => nativeFromJson(e)) - .toList() - - - - - , - - metadata = - - - (json['metadata'] as List) - .map((e) => GetCurrentUserUserFavoriteMoviesMovieMetadata.fromJson(e)) - .toList() - - - - - - { - - - - - - - - - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['title'] = - - nativeToJson(title) - -; - - - - if (genre != null) { - json['genre'] = - - nativeToJson(genre) - -; - } - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - - if (releaseYear != null) { - json['releaseYear'] = - - nativeToJson(releaseYear) - -; - } - - - - if (rating != null) { - json['rating'] = - - nativeToJson(rating) - -; - } - - - - if (description != null) { - json['description'] = - - nativeToJson(description) - -; - } - - - - if (tags != null) { - json['tags'] = - - - tags?.map((e) => nativeToJson(e)).toList() - - -; - } - - - - json['metadata'] = - - - metadata.map((e) => e.toJson()).toList() - - -; - - - return json; - } - - GetCurrentUserUserFavoriteMoviesMovie({ - - required this.id, - - required this.title, - - this.genre, - - required this.imageUrl, - - this.releaseYear, - - this.rating, - - this.description, - - this.tags, - - required this.metadata, - - }); -} - - - - class GetCurrentUserUserFavoriteMoviesMovieMetadata { - - String? director; - - - - - - - GetCurrentUserUserFavoriteMoviesMovieMetadata.fromJson(dynamic json): - director = json['director'] == null ? null : - - nativeFromJson(json['director']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (director != null) { - json['director'] = - - nativeToJson(director) - -; - } - - - return json; - } - - GetCurrentUserUserFavoriteMoviesMovieMetadata({ - - this.director, - - }); -} - - - - class GetCurrentUserData { - - GetCurrentUserUser? user; - - - - - - - GetCurrentUserData.fromJson(dynamic json): - user = json['user'] == null ? null : - - GetCurrentUserUser.fromJson(json['user']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (user != null) { - json['user'] = - - user!.toJson() - -; - } - - - return json; - } - - GetCurrentUserData({ - - this.user, - - }); -} - - - - - - - diff --git a/dataconnect/dataconnect/lib/movies_connector/get_if_favorited_movie.dart b/dataconnect/dataconnect/lib/movies_connector/get_if_favorited_movie.dart deleted file mode 100644 index 901fb84e..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/get_if_favorited_movie.dart +++ /dev/null @@ -1,171 +0,0 @@ -part of movies_connector; - -class GetIfFavoritedMovieVariablesBuilder { - String movieId; - - - FirebaseDataConnect _dataConnect; - - GetIfFavoritedMovieVariablesBuilder(this._dataConnect, {required String this.movieId,}); - Deserializer dataDeserializer = (dynamic json) => GetIfFavoritedMovieData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (GetIfFavoritedMovieVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - QueryRef ref() { - GetIfFavoritedMovieVariables vars=GetIfFavoritedMovieVariables(movieId: movieId,); - - return _dataConnect.query("GetIfFavoritedMovie", dataDeserializer, varsSerializer, vars); - } -} - - - class GetIfFavoritedMovieFavoriteMovie { - - String movieId; - - - - - - - GetIfFavoritedMovieFavoriteMovie.fromJson(dynamic json): - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - GetIfFavoritedMovieFavoriteMovie({ - - required this.movieId, - - }); -} - - - - class GetIfFavoritedMovieData { - - GetIfFavoritedMovieFavoriteMovie? favorite_movie; - - - - - - - GetIfFavoritedMovieData.fromJson(dynamic json): - favorite_movie = json['favorite_movie'] == null ? null : - - GetIfFavoritedMovieFavoriteMovie.fromJson(json['favorite_movie']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (favorite_movie != null) { - json['favorite_movie'] = - - favorite_movie!.toJson() - -; - } - - - return json; - } - - GetIfFavoritedMovieData({ - - this.favorite_movie, - - }); -} - - - - class GetIfFavoritedMovieVariables { - - String movieId; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - GetIfFavoritedMovieVariables.fromJson(Map json): - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - GetIfFavoritedMovieVariables({ - - required this.movieId, - - }); -} - - - - - - - diff --git a/dataconnect/dataconnect/lib/movies_connector/get_movie_by_id.dart b/dataconnect/dataconnect/lib/movies_connector/get_movie_by_id.dart deleted file mode 100644 index 56cc681c..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/get_movie_by_id.dart +++ /dev/null @@ -1,912 +0,0 @@ -part of movies_connector; - -class GetMovieByIdVariablesBuilder { - String id; - - - FirebaseDataConnect _dataConnect; - - GetMovieByIdVariablesBuilder(this._dataConnect, {required String this.id,}); - Deserializer dataDeserializer = (dynamic json) => GetMovieByIdData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (GetMovieByIdVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - QueryRef ref() { - GetMovieByIdVariables vars=GetMovieByIdVariables(id: id,); - - return _dataConnect.query("GetMovieById", dataDeserializer, varsSerializer, vars); - } -} - - - class GetMovieByIdMovie { - - String id; - - - String title; - - - String imageUrl; - - - int? releaseYear; - - - String? genre; - - - double? rating; - - - String? description; - - - List? tags; - - - List metadata; - - - List mainActors; - - - List supportingActors; - - - List reviews; - - - - - - - GetMovieByIdMovie.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - title = - - nativeFromJson(json['title']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - , - - releaseYear = json['releaseYear'] == null ? null : - - nativeFromJson(json['releaseYear']) - - - - , - - genre = json['genre'] == null ? null : - - nativeFromJson(json['genre']) - - - - , - - rating = json['rating'] == null ? null : - - nativeFromJson(json['rating']) - - - - , - - description = json['description'] == null ? null : - - nativeFromJson(json['description']) - - - - , - - tags = json['tags'] == null ? null : - - - (json['tags'] as List) - .map((e) => nativeFromJson(e)) - .toList() - - - - - , - - metadata = - - - (json['metadata'] as List) - .map((e) => GetMovieByIdMovieMetadata.fromJson(e)) - .toList() - - - - - , - - mainActors = - - - (json['mainActors'] as List) - .map((e) => GetMovieByIdMovieMainActors.fromJson(e)) - .toList() - - - - - , - - supportingActors = - - - (json['supportingActors'] as List) - .map((e) => GetMovieByIdMovieSupportingActors.fromJson(e)) - .toList() - - - - - , - - reviews = - - - (json['reviews'] as List) - .map((e) => GetMovieByIdMovieReviews.fromJson(e)) - .toList() - - - - - - { - - - - - - - - - - - - - - - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['title'] = - - nativeToJson(title) - -; - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - - if (releaseYear != null) { - json['releaseYear'] = - - nativeToJson(releaseYear) - -; - } - - - - if (genre != null) { - json['genre'] = - - nativeToJson(genre) - -; - } - - - - if (rating != null) { - json['rating'] = - - nativeToJson(rating) - -; - } - - - - if (description != null) { - json['description'] = - - nativeToJson(description) - -; - } - - - - if (tags != null) { - json['tags'] = - - - tags?.map((e) => nativeToJson(e)).toList() - - -; - } - - - - json['metadata'] = - - - metadata.map((e) => e.toJson()).toList() - - -; - - - - json['mainActors'] = - - - mainActors.map((e) => e.toJson()).toList() - - -; - - - - json['supportingActors'] = - - - supportingActors.map((e) => e.toJson()).toList() - - -; - - - - json['reviews'] = - - - reviews.map((e) => e.toJson()).toList() - - -; - - - return json; - } - - GetMovieByIdMovie({ - - required this.id, - - required this.title, - - required this.imageUrl, - - this.releaseYear, - - this.genre, - - this.rating, - - this.description, - - this.tags, - - required this.metadata, - - required this.mainActors, - - required this.supportingActors, - - required this.reviews, - - }); -} - - - - class GetMovieByIdMovieMetadata { - - String? director; - - - - - - - GetMovieByIdMovieMetadata.fromJson(dynamic json): - director = json['director'] == null ? null : - - nativeFromJson(json['director']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (director != null) { - json['director'] = - - nativeToJson(director) - -; - } - - - return json; - } - - GetMovieByIdMovieMetadata({ - - this.director, - - }); -} - - - - class GetMovieByIdMovieMainActors { - - String id; - - - String name; - - - String imageUrl; - - - - - - - GetMovieByIdMovieMainActors.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - name = - - nativeFromJson(json['name']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - - { - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['name'] = - - nativeToJson(name) - -; - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - return json; - } - - GetMovieByIdMovieMainActors({ - - required this.id, - - required this.name, - - required this.imageUrl, - - }); -} - - - - class GetMovieByIdMovieSupportingActors { - - String id; - - - String name; - - - String imageUrl; - - - - - - - GetMovieByIdMovieSupportingActors.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - name = - - nativeFromJson(json['name']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - - { - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['name'] = - - nativeToJson(name) - -; - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - return json; - } - - GetMovieByIdMovieSupportingActors({ - - required this.id, - - required this.name, - - required this.imageUrl, - - }); -} - - - - class GetMovieByIdMovieReviews { - - String id; - - - String? reviewText; - - - DateTime reviewDate; - - - int? rating; - - - GetMovieByIdMovieReviewsUser user; - - - - - - - GetMovieByIdMovieReviews.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - reviewText = json['reviewText'] == null ? null : - - nativeFromJson(json['reviewText']) - - - - , - - reviewDate = - - nativeFromJson(json['reviewDate']) - - - - , - - rating = json['rating'] == null ? null : - - nativeFromJson(json['rating']) - - - - , - - user = - - GetMovieByIdMovieReviewsUser.fromJson(json['user']) - - - - - { - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - if (reviewText != null) { - json['reviewText'] = - - nativeToJson(reviewText) - -; - } - - - - json['reviewDate'] = - - nativeToJson(reviewDate) - -; - - - - if (rating != null) { - json['rating'] = - - nativeToJson(rating) - -; - } - - - - json['user'] = - - user.toJson() - -; - - - return json; - } - - GetMovieByIdMovieReviews({ - - required this.id, - - this.reviewText, - - required this.reviewDate, - - this.rating, - - required this.user, - - }); -} - - - - class GetMovieByIdMovieReviewsUser { - - String id; - - - String username; - - - - - - - GetMovieByIdMovieReviewsUser.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - username = - - nativeFromJson(json['username']) - - - - - { - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['username'] = - - nativeToJson(username) - -; - - - return json; - } - - GetMovieByIdMovieReviewsUser({ - - required this.id, - - required this.username, - - }); -} - - - - class GetMovieByIdData { - - GetMovieByIdMovie? movie; - - - - - - - GetMovieByIdData.fromJson(dynamic json): - movie = json['movie'] == null ? null : - - GetMovieByIdMovie.fromJson(json['movie']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (movie != null) { - json['movie'] = - - movie!.toJson() - -; - } - - - return json; - } - - GetMovieByIdData({ - - this.movie, - - }); -} - - - - class GetMovieByIdVariables { - - String id; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - GetMovieByIdVariables.fromJson(Map json): - id = - - nativeFromJson(json['id']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - return json; - } - - GetMovieByIdVariables({ - - required this.id, - - }); -} - - - - - - - diff --git a/dataconnect/dataconnect/lib/movies_connector/list_movies.dart b/dataconnect/dataconnect/lib/movies_connector/list_movies.dart deleted file mode 100644 index 57399267..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/list_movies.dart +++ /dev/null @@ -1,403 +0,0 @@ -part of movies_connector; - -class ListMoviesVariablesBuilder { - Optional _orderByRating = Optional.optional(orderDirectionDeserializer, enumSerializer); -Optional _orderByReleaseYear = Optional.optional(orderDirectionDeserializer, enumSerializer); -Optional _limit = Optional.optional(nativeFromJson, nativeToJson); - - - FirebaseDataConnect _dataConnect; - ListMoviesVariablesBuilder orderByRating(OrderDirection? t) { -this._orderByRating.value = t; -return this; -} -ListMoviesVariablesBuilder orderByReleaseYear(OrderDirection? t) { -this._orderByReleaseYear.value = t; -return this; -} -ListMoviesVariablesBuilder limit(int? t) { -this._limit.value = t; -return this; -} - - ListMoviesVariablesBuilder(this._dataConnect, ); - Deserializer dataDeserializer = (dynamic json) => ListMoviesData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (ListMoviesVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - QueryRef ref() { - ListMoviesVariables vars=ListMoviesVariables(orderByRating: _orderByRating,orderByReleaseYear: _orderByReleaseYear,limit: _limit,); - - return _dataConnect.query("ListMovies", dataDeserializer, varsSerializer, vars); - } -} - - - class ListMoviesMovies { - - String id; - - - String title; - - - String imageUrl; - - - int? releaseYear; - - - String? genre; - - - double? rating; - - - List? tags; - - - String? description; - - - - - - - ListMoviesMovies.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - title = - - nativeFromJson(json['title']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - , - - releaseYear = json['releaseYear'] == null ? null : - - nativeFromJson(json['releaseYear']) - - - - , - - genre = json['genre'] == null ? null : - - nativeFromJson(json['genre']) - - - - , - - rating = json['rating'] == null ? null : - - nativeFromJson(json['rating']) - - - - , - - tags = json['tags'] == null ? null : - - - (json['tags'] as List) - .map((e) => nativeFromJson(e)) - .toList() - - - - - , - - description = json['description'] == null ? null : - - nativeFromJson(json['description']) - - - - - { - - - - - - - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['title'] = - - nativeToJson(title) - -; - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - - if (releaseYear != null) { - json['releaseYear'] = - - nativeToJson(releaseYear) - -; - } - - - - if (genre != null) { - json['genre'] = - - nativeToJson(genre) - -; - } - - - - if (rating != null) { - json['rating'] = - - nativeToJson(rating) - -; - } - - - - if (tags != null) { - json['tags'] = - - - tags?.map((e) => nativeToJson(e)).toList() - - -; - } - - - - if (description != null) { - json['description'] = - - nativeToJson(description) - -; - } - - - return json; - } - - ListMoviesMovies({ - - required this.id, - - required this.title, - - required this.imageUrl, - - this.releaseYear, - - this.genre, - - this.rating, - - this.tags, - - this.description, - - }); -} - - - - class ListMoviesData { - - List movies; - - - - - - - ListMoviesData.fromJson(dynamic json): - movies = - - - (json['movies'] as List) - .map((e) => ListMoviesMovies.fromJson(e)) - .toList() - - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['movies'] = - - - movies.map((e) => e.toJson()).toList() - - -; - - - return json; - } - - ListMoviesData({ - - required this.movies, - - }); -} - - - - class ListMoviesVariables { - - late OptionalorderByRating; - - - late OptionalorderByReleaseYear; - - - late Optionallimit; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - ListMoviesVariables.fromJson(Map json) { - - - orderByRating = Optional.optional(orderDirectionDeserializer, enumSerializer); - orderByRating.value = json['orderByRating'] == null ? null : - - OrderDirection.values.byName(json['orderByRating']) - -; - - - - orderByReleaseYear = Optional.optional(orderDirectionDeserializer, enumSerializer); - orderByReleaseYear.value = json['orderByReleaseYear'] == null ? null : - - OrderDirection.values.byName(json['orderByReleaseYear']) - -; - - - - limit = Optional.optional(nativeFromJson, nativeToJson); - limit.value = json['limit'] == null ? null : - - nativeFromJson(json['limit']) - -; - - - } - - - Map toJson() { - Map json = {}; - - - if(orderByRating.state == OptionalState.set) { - json['orderByRating'] = orderByRating.toJson(); - } - - - - if(orderByReleaseYear.state == OptionalState.set) { - json['orderByReleaseYear'] = orderByReleaseYear.toJson(); - } - - - - if(limit.state == OptionalState.set) { - json['limit'] = limit.toJson(); - } - - - return json; - } - - ListMoviesVariables({ - - required this.orderByRating, - - required this.orderByReleaseYear, - - required this.limit, - - }); -} - - - - - - - diff --git a/dataconnect/dataconnect/lib/movies_connector/movies.dart b/dataconnect/dataconnect/lib/movies_connector/movies.dart deleted file mode 100644 index 2ab02827..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/movies.dart +++ /dev/null @@ -1,136 +0,0 @@ -library movies_connector; -import 'package:firebase_data_connect/firebase_data_connect.dart'; -import 'dart:convert'; - -part 'upsert_user.dart'; - -part 'add_favorited_movie.dart'; - -part 'delete_favorited_movie.dart'; - -part 'add_review.dart'; - -part 'update_review.dart'; - -part 'delete_review.dart'; - -part 'list_movies.dart'; - -part 'list_genres.dart'; - -part 'get_movie_by_id.dart'; - -part 'get_actor_by_id.dart'; - -part 'get_current_user.dart'; - -part 'get_if_favorited_movie.dart'; - -part 'search_all.dart'; - - - - enum OrderDirection { - - ASC, - - DESC, - - } - OrderDirection orderDirectionDeserializer(dynamic data) { - return OrderDirection.values.byName(data); - } - - - -String enumSerializer(Enum e) { - return e.name; -} - - - -class MoviesConnector { - - - UpsertUserVariablesBuilder upsertUser ({required String username,}) { - return UpsertUserVariablesBuilder(dataConnect, username: username,); - } - - - AddFavoritedMovieVariablesBuilder addFavoritedMovie ({required String movieId,}) { - return AddFavoritedMovieVariablesBuilder(dataConnect, movieId: movieId,); - } - - - DeleteFavoritedMovieVariablesBuilder deleteFavoritedMovie ({required String movieId,}) { - return DeleteFavoritedMovieVariablesBuilder(dataConnect, movieId: movieId,); - } - - - AddReviewVariablesBuilder addReview ({required String movieId,required int rating,required String reviewText,}) { - return AddReviewVariablesBuilder(dataConnect, movieId: movieId,rating: rating,reviewText: reviewText,); - } - - - UpdateReviewVariablesBuilder updateReview ({required String movieId,required int rating,required String reviewText,}) { - return UpdateReviewVariablesBuilder(dataConnect, movieId: movieId,rating: rating,reviewText: reviewText,); - } - - - DeleteReviewVariablesBuilder deleteReview ({required String movieId,}) { - return DeleteReviewVariablesBuilder(dataConnect, movieId: movieId,); - } - - - ListMoviesVariablesBuilder listMovies () { - return ListMoviesVariablesBuilder(dataConnect, ); - } - - - ListGenresVariablesBuilder listGenres () { - return ListGenresVariablesBuilder(dataConnect, ); - } - - - GetMovieByIdVariablesBuilder getMovieById ({required String id,}) { - return GetMovieByIdVariablesBuilder(dataConnect, id: id,); - } - - - GetActorByIdVariablesBuilder getActorById ({required String id,}) { - return GetActorByIdVariablesBuilder(dataConnect, id: id,); - } - - - GetCurrentUserVariablesBuilder getCurrentUser () { - return GetCurrentUserVariablesBuilder(dataConnect, ); - } - - - GetIfFavoritedMovieVariablesBuilder getIfFavoritedMovie ({required String movieId,}) { - return GetIfFavoritedMovieVariablesBuilder(dataConnect, movieId: movieId,); - } - - - SearchAllVariablesBuilder searchAll ({required int minYear,required int maxYear,required double minRating,required double maxRating,required String genre,}) { - return SearchAllVariablesBuilder(dataConnect, minYear: minYear,maxYear: maxYear,minRating: minRating,maxRating: maxRating,genre: genre,); - } - - - static ConnectorConfig connectorConfig = ConnectorConfig( - 'us-central1', - 'movies', - 'dataconnect', - ); - - MoviesConnector({required this.dataConnect}); - static MoviesConnector get instance { - return MoviesConnector( - dataConnect: FirebaseDataConnect.instanceFor( - connectorConfig: connectorConfig, - sdkType: CallerSDKType.generated)); - } - - FirebaseDataConnect dataConnect; -} - diff --git a/dataconnect/dataconnect/lib/movies_connector/search_all.dart b/dataconnect/dataconnect/lib/movies_connector/search_all.dart deleted file mode 100644 index 27803d0a..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/search_all.dart +++ /dev/null @@ -1,1021 +0,0 @@ -part of movies_connector; - -class SearchAllVariablesBuilder { - Optional _input = Optional.optional(nativeFromJson, nativeToJson); -int minYear; -int maxYear; -double minRating; -double maxRating; -String genre; - - - FirebaseDataConnect _dataConnect; - SearchAllVariablesBuilder input(String? t) { -this._input.value = t; -return this; -} - - SearchAllVariablesBuilder(this._dataConnect, {required int this.minYear,required int this.maxYear,required double this.minRating,required double this.maxRating,required String this.genre,}); - Deserializer dataDeserializer = (dynamic json) => SearchAllData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (SearchAllVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - QueryRef ref() { - SearchAllVariables vars=SearchAllVariables(input: _input,minYear: minYear,maxYear: maxYear,minRating: minRating,maxRating: maxRating,genre: genre,); - - return _dataConnect.query("SearchAll", dataDeserializer, varsSerializer, vars); - } -} - - - class SearchAllMoviesMatchingTitle { - - String id; - - - String title; - - - String? genre; - - - double? rating; - - - String imageUrl; - - - - - - - SearchAllMoviesMatchingTitle.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - title = - - nativeFromJson(json['title']) - - - - , - - genre = json['genre'] == null ? null : - - nativeFromJson(json['genre']) - - - - , - - rating = json['rating'] == null ? null : - - nativeFromJson(json['rating']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - - { - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['title'] = - - nativeToJson(title) - -; - - - - if (genre != null) { - json['genre'] = - - nativeToJson(genre) - -; - } - - - - if (rating != null) { - json['rating'] = - - nativeToJson(rating) - -; - } - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - return json; - } - - SearchAllMoviesMatchingTitle({ - - required this.id, - - required this.title, - - this.genre, - - this.rating, - - required this.imageUrl, - - }); -} - - - - class SearchAllMoviesMatchingDescription { - - String id; - - - String title; - - - String? genre; - - - double? rating; - - - String imageUrl; - - - - - - - SearchAllMoviesMatchingDescription.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - title = - - nativeFromJson(json['title']) - - - - , - - genre = json['genre'] == null ? null : - - nativeFromJson(json['genre']) - - - - , - - rating = json['rating'] == null ? null : - - nativeFromJson(json['rating']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - - { - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['title'] = - - nativeToJson(title) - -; - - - - if (genre != null) { - json['genre'] = - - nativeToJson(genre) - -; - } - - - - if (rating != null) { - json['rating'] = - - nativeToJson(rating) - -; - } - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - return json; - } - - SearchAllMoviesMatchingDescription({ - - required this.id, - - required this.title, - - this.genre, - - this.rating, - - required this.imageUrl, - - }); -} - - - - class SearchAllActorsMatchingName { - - String id; - - - String name; - - - String imageUrl; - - - - - - - SearchAllActorsMatchingName.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - name = - - nativeFromJson(json['name']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - - { - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['name'] = - - nativeToJson(name) - -; - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - return json; - } - - SearchAllActorsMatchingName({ - - required this.id, - - required this.name, - - required this.imageUrl, - - }); -} - - - - class SearchAllReviewsMatchingText { - - String id; - - - int? rating; - - - String? reviewText; - - - DateTime reviewDate; - - - SearchAllReviewsMatchingTextMovie movie; - - - SearchAllReviewsMatchingTextUser user; - - - - - - - SearchAllReviewsMatchingText.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - rating = json['rating'] == null ? null : - - nativeFromJson(json['rating']) - - - - , - - reviewText = json['reviewText'] == null ? null : - - nativeFromJson(json['reviewText']) - - - - , - - reviewDate = - - nativeFromJson(json['reviewDate']) - - - - , - - movie = - - SearchAllReviewsMatchingTextMovie.fromJson(json['movie']) - - - - , - - user = - - SearchAllReviewsMatchingTextUser.fromJson(json['user']) - - - - - { - - - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - if (rating != null) { - json['rating'] = - - nativeToJson(rating) - -; - } - - - - if (reviewText != null) { - json['reviewText'] = - - nativeToJson(reviewText) - -; - } - - - - json['reviewDate'] = - - nativeToJson(reviewDate) - -; - - - - json['movie'] = - - movie.toJson() - -; - - - - json['user'] = - - user.toJson() - -; - - - return json; - } - - SearchAllReviewsMatchingText({ - - required this.id, - - this.rating, - - this.reviewText, - - required this.reviewDate, - - required this.movie, - - required this.user, - - }); -} - - - - class SearchAllReviewsMatchingTextMovie { - - String id; - - - String title; - - - - - - - SearchAllReviewsMatchingTextMovie.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - title = - - nativeFromJson(json['title']) - - - - - { - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['title'] = - - nativeToJson(title) - -; - - - return json; - } - - SearchAllReviewsMatchingTextMovie({ - - required this.id, - - required this.title, - - }); -} - - - - class SearchAllReviewsMatchingTextUser { - - String id; - - - String username; - - - - - - - SearchAllReviewsMatchingTextUser.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - username = - - nativeFromJson(json['username']) - - - - - { - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['username'] = - - nativeToJson(username) - -; - - - return json; - } - - SearchAllReviewsMatchingTextUser({ - - required this.id, - - required this.username, - - }); -} - - - - class SearchAllData { - - List moviesMatchingTitle; - - - List moviesMatchingDescription; - - - List actorsMatchingName; - - - List reviewsMatchingText; - - - - - - - SearchAllData.fromJson(dynamic json): - moviesMatchingTitle = - - - (json['moviesMatchingTitle'] as List) - .map((e) => SearchAllMoviesMatchingTitle.fromJson(e)) - .toList() - - - - - , - - moviesMatchingDescription = - - - (json['moviesMatchingDescription'] as List) - .map((e) => SearchAllMoviesMatchingDescription.fromJson(e)) - .toList() - - - - - , - - actorsMatchingName = - - - (json['actorsMatchingName'] as List) - .map((e) => SearchAllActorsMatchingName.fromJson(e)) - .toList() - - - - - , - - reviewsMatchingText = - - - (json['reviewsMatchingText'] as List) - .map((e) => SearchAllReviewsMatchingText.fromJson(e)) - .toList() - - - - - - { - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['moviesMatchingTitle'] = - - - moviesMatchingTitle.map((e) => e.toJson()).toList() - - -; - - - - json['moviesMatchingDescription'] = - - - moviesMatchingDescription.map((e) => e.toJson()).toList() - - -; - - - - json['actorsMatchingName'] = - - - actorsMatchingName.map((e) => e.toJson()).toList() - - -; - - - - json['reviewsMatchingText'] = - - - reviewsMatchingText.map((e) => e.toJson()).toList() - - -; - - - return json; - } - - SearchAllData({ - - required this.moviesMatchingTitle, - - required this.moviesMatchingDescription, - - required this.actorsMatchingName, - - required this.reviewsMatchingText, - - }); -} - - - - class SearchAllVariables { - - late Optionalinput; - - - int minYear; - - - int maxYear; - - - double minRating; - - - double maxRating; - - - String genre; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - SearchAllVariables.fromJson(Map json): - minYear = - - nativeFromJson(json['minYear']) - - - - , - - maxYear = - - nativeFromJson(json['maxYear']) - - - - , - - minRating = - - nativeFromJson(json['minRating']) - - - - , - - maxRating = - - nativeFromJson(json['maxRating']) - - - - , - - genre = - - nativeFromJson(json['genre']) - - - - - { - - - input = Optional.optional(nativeFromJson, nativeToJson); - input.value = json['input'] == null ? null : - - nativeFromJson(json['input']) - -; - - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - if(input.state == OptionalState.set) { - json['input'] = input.toJson(); - } - - - - json['minYear'] = - - nativeToJson(minYear) - -; - - - - json['maxYear'] = - - nativeToJson(maxYear) - -; - - - - json['minRating'] = - - nativeToJson(minRating) - -; - - - - json['maxRating'] = - - nativeToJson(maxRating) - -; - - - - json['genre'] = - - nativeToJson(genre) - -; - - - return json; - } - - SearchAllVariables({ - - required this.input, - - required this.minYear, - - required this.maxYear, - - required this.minRating, - - required this.maxRating, - - required this.genre, - - }); -} - - - - - - - diff --git a/dataconnect/dataconnect/lib/movies_connector/update_review.dart b/dataconnect/dataconnect/lib/movies_connector/update_review.dart deleted file mode 100644 index bbd614a2..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/update_review.dart +++ /dev/null @@ -1,242 +0,0 @@ -part of movies_connector; - -class UpdateReviewVariablesBuilder { - String movieId; -int rating; -String reviewText; - - - FirebaseDataConnect _dataConnect; - - UpdateReviewVariablesBuilder(this._dataConnect, {required String this.movieId,required int this.rating,required String this.reviewText,}); - Deserializer dataDeserializer = (dynamic json) => UpdateReviewData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (UpdateReviewVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - MutationRef ref() { - UpdateReviewVariables vars=UpdateReviewVariables(movieId: movieId,rating: rating,reviewText: reviewText,); - - return _dataConnect.mutation("UpdateReview", dataDeserializer, varsSerializer, vars); - } -} - - - class UpdateReviewReviewUpdate { - - String userId; - - - String movieId; - - - - - - - UpdateReviewReviewUpdate.fromJson(dynamic json): - userId = - - nativeFromJson(json['userId']) - - - - , - - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['userId'] = - - nativeToJson(userId) - -; - - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - UpdateReviewReviewUpdate({ - - required this.userId, - - required this.movieId, - - }); -} - - - - class UpdateReviewData { - - UpdateReviewReviewUpdate? review_update; - - - - - - - UpdateReviewData.fromJson(dynamic json): - review_update = json['review_update'] == null ? null : - - UpdateReviewReviewUpdate.fromJson(json['review_update']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (review_update != null) { - json['review_update'] = - - review_update!.toJson() - -; - } - - - return json; - } - - UpdateReviewData({ - - this.review_update, - - }); -} - - - - class UpdateReviewVariables { - - String movieId; - - - int rating; - - - String reviewText; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - UpdateReviewVariables.fromJson(Map json): - movieId = - - nativeFromJson(json['movieId']) - - - - , - - rating = - - nativeFromJson(json['rating']) - - - - , - - reviewText = - - nativeFromJson(json['reviewText']) - - - - - { - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - - json['rating'] = - - nativeToJson(rating) - -; - - - - json['reviewText'] = - - nativeToJson(reviewText) - -; - - - return json; - } - - UpdateReviewVariables({ - - required this.movieId, - - required this.rating, - - required this.reviewText, - - }); -} - - - - - - - diff --git a/dataconnect/dataconnect/lib/movies_connector/upsert_user.dart b/dataconnect/dataconnect/lib/movies_connector/upsert_user.dart deleted file mode 100644 index 16d90738..00000000 --- a/dataconnect/dataconnect/lib/movies_connector/upsert_user.dart +++ /dev/null @@ -1,169 +0,0 @@ -part of movies_connector; - -class UpsertUserVariablesBuilder { - String username; - - - FirebaseDataConnect _dataConnect; - - UpsertUserVariablesBuilder(this._dataConnect, {required String this.username,}); - Deserializer dataDeserializer = (dynamic json) => UpsertUserData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (UpsertUserVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - MutationRef ref() { - UpsertUserVariables vars=UpsertUserVariables(username: username,); - - return _dataConnect.mutation("UpsertUser", dataDeserializer, varsSerializer, vars); - } -} - - - class UpsertUserUserUpsert { - - String id; - - - - - - - UpsertUserUserUpsert.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - return json; - } - - UpsertUserUserUpsert({ - - required this.id, - - }); -} - - - - class UpsertUserData { - - UpsertUserUserUpsert user_upsert; - - - - - - - UpsertUserData.fromJson(dynamic json): - user_upsert = - - UpsertUserUserUpsert.fromJson(json['user_upsert']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['user_upsert'] = - - user_upsert.toJson() - -; - - - return json; - } - - UpsertUserData({ - - required this.user_upsert, - - }); -} - - - - class UpsertUserVariables { - - String username; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - UpsertUserVariables.fromJson(Map json): - username = - - nativeFromJson(json['username']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['username'] = - - nativeToJson(username) - -; - - - return json; - } - - UpsertUserVariables({ - - required this.username, - - }); -} - - - - - - - diff --git a/dataconnect/dataconnect/moviedata_insert.gql b/dataconnect/dataconnect/moviedata_insert.gql index 2f205012..e5b65795 100644 --- a/dataconnect/dataconnect/moviedata_insert.gql +++ b/dataconnect/dataconnect/moviedata_insert.gql @@ -597,9 +597,9 @@ movieActor_insertMany( ) user_insertMany( data: [ - { id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", username: "sherlock_h" } - { id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", username: "hercule_p" } - { id: "TBedjwCX0Jf955Uuoxk6k74sY0l1", username: "jane_d" } + { id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", username: "sherlock_h", name: "Sherlock Holmes" } + { id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", username: "hercule_p", name: "Hercule Poirot" } + { id: "TBedjwCX0Jf955Uuoxk6k74sY0l1", username: "jane_d", name: "Jane Doe" } ] ) diff --git a/dataconnect/dataconnect/schema/schema.gql b/dataconnect/dataconnect/schema/schema.gql index 721b9a77..444ccfbb 100644 --- a/dataconnect/dataconnect/schema/schema.gql +++ b/dataconnect/dataconnect/schema/schema.gql @@ -46,6 +46,7 @@ type User @table { id: String! @col(name: "user_auth") username: String! @col(name: "username", dataType: "varchar(50)") + name: String! # The following are generated from the @ref in the Review table # reviews_on_user # movies_via_Review @@ -92,4 +93,16 @@ type FavoriteMovie # @ref is implicit user: User! movie: Movie! +} +type FavoriteActor + @table(name: "FavoriteActors", singular: "favorite_actor", plural: "favorite_actors", key: ["user", "actor"]) { + # @ref is implicit + user: User! + actor: Actor! +} +type WatchedMovie + @table(name: "WatchedMovies", singular: "watched_movie", plural: "watched_movies", key: ["user", "movie"]) { + # @ref is implicit + user: User! + movie: Movie! } \ No newline at end of file diff --git a/dataconnect/lib/extensions.dart b/dataconnect/lib/extensions.dart new file mode 100644 index 00000000..490ea227 --- /dev/null +++ b/dataconnect/lib/extensions.dart @@ -0,0 +1,49 @@ +import 'movies_connector/movies.dart'; + +extension GetCurrentUserUserFavoriteMoviesMovieExtension + on GetCurrentUserUserFavoriteMoviesMovie { + ListMoviesMovies get toListMoviesMovies => ListMoviesMovies( + id: id, + title: title, + imageUrl: imageUrl, + description: description, + genre: genre, + rating: rating, + releaseYear: releaseYear, + tags: tags); +} + +extension GetCurrentUserUserWatchedMoviesMovieExtension + on GetCurrentUserUserWatchedMoviesMovie { + ListMoviesMovies get toListMoviesMovies => ListMoviesMovies( + id: id, + title: title, + imageUrl: imageUrl, + description: description, + genre: genre, + rating: rating, + releaseYear: releaseYear, + tags: tags); +} + +extension SearchAllMoviesMatchingTitleExtension + on SearchAllMoviesMatchingTitle { + ListMoviesMovies get toListMoviesMovies => ListMoviesMovies( + id: id, + title: title, + imageUrl: imageUrl, + genre: genre, + rating: rating, + ); +} + +extension SearchAllMoviesMatchingDescriptionExtension + on SearchAllMoviesMatchingDescription { + ListMoviesMovies get toListMoviesMovies => ListMoviesMovies( + id: id, + title: title, + imageUrl: imageUrl, + genre: genre, + rating: rating, + ); +} diff --git a/dataconnect/lib/login.dart b/dataconnect/lib/login.dart index 3817a85a..97f6b3ba 100644 --- a/dataconnect/lib/login.dart +++ b/dataconnect/lib/login.dart @@ -1,3 +1,4 @@ +import 'package:dataconnect/movies_connector/movies.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -35,6 +36,8 @@ class _LoginState extends State { ), const SizedBox(height: 30), TextFormField( + obscureText: true, + autocorrect: false, decoration: const InputDecoration( hintText: "Password", border: OutlineInputBorder()), onChanged: (value) { diff --git a/dataconnect/lib/movie_detail.dart b/dataconnect/lib/movie_detail.dart index 90810f29..8034f80d 100644 --- a/dataconnect/lib/movie_detail.dart +++ b/dataconnect/lib/movie_detail.dart @@ -1,4 +1,5 @@ import 'package:dataconnect/movies_connector/movies.dart'; +import 'package:dataconnect/widgets/login_guard.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; @@ -14,20 +15,41 @@ class MovieDetail extends StatefulWidget { class _MovieDetailState extends State { double _ratingValue = 0; + String _reviewText = ""; bool loading = true; GetMovieByIdData? data; + bool _watched = false; + bool _favorited = false; + + TextEditingController _reviewTextController = TextEditingController(); @override void initState() { super.initState(); MoviesConnector.instance .getMovieById(id: widget.id) - .execute() - .then((value) { + .ref() + .subscribe() + .listen((value) { setState(() { loading = false; data = value.data; }); }); + MoviesConnector.instance + .getMovieInfoForUser(movieId: widget.id) + .ref() + .subscribe() + .listen((value) { + setState(() { + _watched = value.data.watched_movie != null; + _favorited = value.data.favorite_movie != null; + }); + }); + } + + void _refreshData() { + MoviesConnector.instance.getMovieById(id: widget.id).execute(); + MoviesConnector.instance.getMovieInfoForUser(movieId: widget.id).execute(); } List _buildMainDescription() { @@ -79,21 +101,45 @@ class _MovieDetailState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - // TODO(mtewani): Check if the movie has been watched by the user - OutlinedButton.icon( + LoginGuard( + widgetToGuard: OutlinedButton.icon( onPressed: () { - // TODO(mtewani): Check if user is logged in. + (_watched + ? MoviesConnector.instance + .deleteFavoritedMovie(movieId: widget.id) + .execute() + : MoviesConnector.instance + .addFavoritedMovie(movieId: widget.id) + .execute()) + .then( + (value) => setState(() { + _watched = !_watched; + }), + ); }, - icon: const Icon(Icons.check_circle), + icon: Icon( + _watched ? Icons.check_circle : Icons.check_circle_outline), label: const Text('Watched'), - ), - OutlinedButton.icon( + )), + LoginGuard( + widgetToGuard: OutlinedButton.icon( onPressed: () { - // TODO(mtewani): Check if user is logged in. + (_favorited + ? MoviesConnector.instance + .deleteFavoritedMovie(movieId: widget.id) + .execute() + : MoviesConnector.instance + .addFavoritedMovie(movieId: widget.id) + .execute()) + .then((value) { + setState(() { + _favorited = !_favorited; + }); + }); }, - icon: const Icon(Icons.favorite), + icon: Icon(_favorited ? Icons.favorite : Icons.favorite_border), label: const Text('Add To Favorites'), - ) + )) ], ) ]; @@ -184,8 +230,8 @@ class _MovieDetailState extends State { Text("Rating: $_ratingValue"), Slider( value: _ratingValue, - max: 5, - divisions: 10, + max: 10, + divisions: 20, label: _ratingValue.toString(), onChanged: (double value) { setState(() { @@ -193,18 +239,33 @@ class _MovieDetailState extends State { }); }, ), - const TextField( - decoration: InputDecoration( - hintText: "Write your review", - border: OutlineInputBorder(), + LoginGuard( + widgetToGuard: TextField( + decoration: const InputDecoration( + hintText: "Write your review", + border: OutlineInputBorder(), + ), + controller: _reviewTextController, + ), + message: "writing a review"), + LoginGuard( + widgetToGuard: OutlinedButton.icon( + onPressed: () { + // TODO(mtewani): Check if user is logged in. + MoviesConnector.instance + .addReview( + movieId: widget.id, + rating: _ratingValue.toInt(), + reviewText: _reviewTextController.text) + .execute() + .then((_) { + _refreshData(); + _reviewTextController.clear(); + }); + }, + label: const Text('Submit Review'), ), ), - OutlinedButton.icon( - onPressed: () { - // TODO(mtewani): Check if user is logged in. - }, - label: const Text('Submit Review'), - ), ...data!.movie!.reviews.map((review) { return Card( child: Padding( diff --git a/dataconnect/lib/movies_connector/add_review.dart b/dataconnect/lib/movies_connector/add_review.dart index 1205433f..bbf6f7af 100644 --- a/dataconnect/lib/movies_connector/add_review.dart +++ b/dataconnect/lib/movies_connector/add_review.dart @@ -22,7 +22,7 @@ String reviewText; } - class AddReviewReviewInsert { + class AddReviewReviewUpsert { String userId; @@ -34,7 +34,7 @@ String reviewText; - AddReviewReviewInsert.fromJson(dynamic json): + AddReviewReviewUpsert.fromJson(dynamic json): userId = nativeFromJson(json['userId']) @@ -81,7 +81,7 @@ String reviewText; return json; } - AddReviewReviewInsert({ + AddReviewReviewUpsert({ required this.userId, @@ -94,7 +94,7 @@ String reviewText; class AddReviewData { - AddReviewReviewInsert review_insert; + AddReviewReviewUpsert review_upsert; @@ -102,9 +102,9 @@ String reviewText; AddReviewData.fromJson(dynamic json): - review_insert = + review_upsert = - AddReviewReviewInsert.fromJson(json['review_insert']) + AddReviewReviewUpsert.fromJson(json['review_upsert']) @@ -120,9 +120,9 @@ String reviewText; Map json = {}; - json['review_insert'] = + json['review_upsert'] = - review_insert.toJson() + review_upsert.toJson() ; @@ -132,7 +132,7 @@ String reviewText; AddReviewData({ - required this.review_insert, + required this.review_upsert, }); } diff --git a/dataconnect/lib/movies_connector/delete_favorited_actor.dart b/dataconnect/lib/movies_connector/delete_favorited_actor.dart new file mode 100644 index 00000000..ca0d48a8 --- /dev/null +++ b/dataconnect/lib/movies_connector/delete_favorited_actor.dart @@ -0,0 +1,194 @@ +part of movies_connector; + +class DeleteFavoritedActorVariablesBuilder { + String actorId; + + + FirebaseDataConnect _dataConnect; + + DeleteFavoritedActorVariablesBuilder(this._dataConnect, {required String this.actorId,}); + Deserializer dataDeserializer = (dynamic json) => DeleteFavoritedActorData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (DeleteFavoritedActorVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + MutationRef ref() { + DeleteFavoritedActorVariables vars=DeleteFavoritedActorVariables(actorId: actorId,); + + return _dataConnect.mutation("DeleteFavoritedActor", dataDeserializer, varsSerializer, vars); + } +} + + + class DeleteFavoritedActorFavoriteActorDelete { + + String userId; + + + String actorId; + + + + + + + DeleteFavoritedActorFavoriteActorDelete.fromJson(dynamic json): + userId = + + nativeFromJson(json['userId']) + + + + , + + actorId = + + nativeFromJson(json['actorId']) + + + + + { + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['userId'] = + + nativeToJson(userId) + +; + + + + json['actorId'] = + + nativeToJson(actorId) + +; + + + return json; + } + + DeleteFavoritedActorFavoriteActorDelete({ + + required this.userId, + + required this.actorId, + + }); +} + + + + class DeleteFavoritedActorData { + + DeleteFavoritedActorFavoriteActorDelete? favorite_actor_delete; + + + + + + + DeleteFavoritedActorData.fromJson(dynamic json): + favorite_actor_delete = json['favorite_actor_delete'] == null ? null : + + DeleteFavoritedActorFavoriteActorDelete.fromJson(json['favorite_actor_delete']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (favorite_actor_delete != null) { + json['favorite_actor_delete'] = + + favorite_actor_delete!.toJson() + +; + } + + + return json; + } + + DeleteFavoritedActorData({ + + this.favorite_actor_delete, + + }); +} + + + + class DeleteFavoritedActorVariables { + + String actorId; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + DeleteFavoritedActorVariables.fromJson(Map json): + actorId = + + nativeFromJson(json['actorId']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['actorId'] = + + nativeToJson(actorId) + +; + + + return json; + } + + DeleteFavoritedActorVariables({ + + required this.actorId, + + }); +} + + + + + + + diff --git a/dataconnect/dataconnect/lib/movies_connector/delete_review.dart b/dataconnect/lib/movies_connector/delete_watched_movie.dart similarity index 50% rename from dataconnect/dataconnect/lib/movies_connector/delete_review.dart rename to dataconnect/lib/movies_connector/delete_watched_movie.dart index 49fe10cd..6c9ae830 100644 --- a/dataconnect/dataconnect/lib/movies_connector/delete_review.dart +++ b/dataconnect/lib/movies_connector/delete_watched_movie.dart @@ -1,26 +1,26 @@ part of movies_connector; -class DeleteReviewVariablesBuilder { +class DeleteWatchedMovieVariablesBuilder { String movieId; FirebaseDataConnect _dataConnect; - DeleteReviewVariablesBuilder(this._dataConnect, {required String this.movieId,}); - Deserializer dataDeserializer = (dynamic json) => DeleteReviewData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (DeleteReviewVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { + DeleteWatchedMovieVariablesBuilder(this._dataConnect, {required String this.movieId,}); + Deserializer dataDeserializer = (dynamic json) => DeleteWatchedMovieData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (DeleteWatchedMovieVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { return this.ref().execute(); } - MutationRef ref() { - DeleteReviewVariables vars=DeleteReviewVariables(movieId: movieId,); + MutationRef ref() { + DeleteWatchedMovieVariables vars=DeleteWatchedMovieVariables(movieId: movieId,); - return _dataConnect.mutation("DeleteReview", dataDeserializer, varsSerializer, vars); + return _dataConnect.mutation("DeleteWatchedMovie", dataDeserializer, varsSerializer, vars); } } - class DeleteReviewReviewDelete { + class DeleteWatchedMovieWatchedMovieDelete { String userId; @@ -32,7 +32,7 @@ class DeleteReviewVariablesBuilder { - DeleteReviewReviewDelete.fromJson(dynamic json): + DeleteWatchedMovieWatchedMovieDelete.fromJson(dynamic json): userId = nativeFromJson(json['userId']) @@ -79,7 +79,7 @@ class DeleteReviewVariablesBuilder { return json; } - DeleteReviewReviewDelete({ + DeleteWatchedMovieWatchedMovieDelete({ required this.userId, @@ -90,19 +90,19 @@ class DeleteReviewVariablesBuilder { - class DeleteReviewData { + class DeleteWatchedMovieData { - DeleteReviewReviewDelete? review_delete; + DeleteWatchedMovieWatchedMovieDelete? watched_movie_delete; - DeleteReviewData.fromJson(dynamic json): - review_delete = json['review_delete'] == null ? null : + DeleteWatchedMovieData.fromJson(dynamic json): + watched_movie_delete = json['watched_movie_delete'] == null ? null : - DeleteReviewReviewDelete.fromJson(json['review_delete']) + DeleteWatchedMovieWatchedMovieDelete.fromJson(json['watched_movie_delete']) @@ -118,10 +118,10 @@ class DeleteReviewVariablesBuilder { Map json = {}; - if (review_delete != null) { - json['review_delete'] = + if (watched_movie_delete != null) { + json['watched_movie_delete'] = - review_delete!.toJson() + watched_movie_delete!.toJson() ; } @@ -130,16 +130,16 @@ class DeleteReviewVariablesBuilder { return json; } - DeleteReviewData({ + DeleteWatchedMovieData({ - this.review_delete, + this.watched_movie_delete, }); } - class DeleteReviewVariables { + class DeleteWatchedMovieVariables { String movieId; @@ -150,7 +150,7 @@ class DeleteReviewVariablesBuilder { @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - DeleteReviewVariables.fromJson(Map json): + DeleteWatchedMovieVariables.fromJson(Map json): movieId = nativeFromJson(json['movieId']) @@ -179,7 +179,7 @@ class DeleteReviewVariablesBuilder { return json; } - DeleteReviewVariables({ + DeleteWatchedMovieVariables({ required this.movieId, diff --git a/dataconnect/lib/movies_connector/get_current_user.dart b/dataconnect/lib/movies_connector/get_current_user.dart index 38a7e191..d319c1f0 100644 --- a/dataconnect/lib/movies_connector/get_current_user.dart +++ b/dataconnect/lib/movies_connector/get_current_user.dart @@ -26,12 +26,21 @@ class GetCurrentUserVariablesBuilder { String username; + String name; + + List reviews; List favoriteMovies; + List favoriteActors; + + + List watchedMovies; + + @@ -51,6 +60,14 @@ class GetCurrentUserVariablesBuilder { + , + + name = + + nativeFromJson(json['name']) + + + , reviews = @@ -75,6 +92,30 @@ class GetCurrentUserVariablesBuilder { + , + + favoriteActors = + + + (json['favoriteActors'] as List) + .map((e) => GetCurrentUserUserFavoriteActors.fromJson(e)) + .toList() + + + + + , + + watchedMovies = + + + (json['watchedMovies'] as List) + .map((e) => GetCurrentUserUserWatchedMovies.fromJson(e)) + .toList() + + + + { @@ -86,6 +127,12 @@ class GetCurrentUserVariablesBuilder { + + + + + + } @@ -109,6 +156,14 @@ class GetCurrentUserVariablesBuilder { + json['name'] = + + nativeToJson(name) + +; + + + json['reviews'] = @@ -125,6 +180,26 @@ class GetCurrentUserVariablesBuilder { favoriteMovies.map((e) => e.toJson()).toList() +; + + + + json['favoriteActors'] = + + + favoriteActors.map((e) => e.toJson()).toList() + + +; + + + + json['watchedMovies'] = + + + watchedMovies.map((e) => e.toJson()).toList() + + ; @@ -137,10 +212,16 @@ class GetCurrentUserVariablesBuilder { required this.username, + required this.name, + required this.reviews, required this.favoriteMovies, + required this.favoriteActors, + + required this.watchedMovies, + }); } @@ -708,6 +789,495 @@ class GetCurrentUserVariablesBuilder { + class GetCurrentUserUserFavoriteActors { + + GetCurrentUserUserFavoriteActorsActor actor; + + + + + + + GetCurrentUserUserFavoriteActors.fromJson(dynamic json): + actor = + + GetCurrentUserUserFavoriteActorsActor.fromJson(json['actor']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['actor'] = + + actor.toJson() + +; + + + return json; + } + + GetCurrentUserUserFavoriteActors({ + + required this.actor, + + }); +} + + + + class GetCurrentUserUserFavoriteActorsActor { + + String id; + + + String name; + + + String imageUrl; + + + + + + + GetCurrentUserUserFavoriteActorsActor.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + name = + + nativeFromJson(json['name']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + + { + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['name'] = + + nativeToJson(name) + +; + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + return json; + } + + GetCurrentUserUserFavoriteActorsActor({ + + required this.id, + + required this.name, + + required this.imageUrl, + + }); +} + + + + class GetCurrentUserUserWatchedMovies { + + GetCurrentUserUserWatchedMoviesMovie movie; + + + + + + + GetCurrentUserUserWatchedMovies.fromJson(dynamic json): + movie = + + GetCurrentUserUserWatchedMoviesMovie.fromJson(json['movie']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movie'] = + + movie.toJson() + +; + + + return json; + } + + GetCurrentUserUserWatchedMovies({ + + required this.movie, + + }); +} + + + + class GetCurrentUserUserWatchedMoviesMovie { + + String id; + + + String title; + + + String? genre; + + + String imageUrl; + + + int? releaseYear; + + + double? rating; + + + String? description; + + + List? tags; + + + List metadata; + + + + + + + GetCurrentUserUserWatchedMoviesMovie.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + , + + genre = json['genre'] == null ? null : + + nativeFromJson(json['genre']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + , + + releaseYear = json['releaseYear'] == null ? null : + + nativeFromJson(json['releaseYear']) + + + + , + + rating = json['rating'] == null ? null : + + nativeFromJson(json['rating']) + + + + , + + description = json['description'] == null ? null : + + nativeFromJson(json['description']) + + + + , + + tags = json['tags'] == null ? null : + + + (json['tags'] as List) + .map((e) => nativeFromJson(e)) + .toList() + + + + + , + + metadata = + + + (json['metadata'] as List) + .map((e) => GetCurrentUserUserWatchedMoviesMovieMetadata.fromJson(e)) + .toList() + + + + + + { + + + + + + + + + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + + if (genre != null) { + json['genre'] = + + nativeToJson(genre) + +; + } + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + + if (releaseYear != null) { + json['releaseYear'] = + + nativeToJson(releaseYear) + +; + } + + + + if (rating != null) { + json['rating'] = + + nativeToJson(rating) + +; + } + + + + if (description != null) { + json['description'] = + + nativeToJson(description) + +; + } + + + + if (tags != null) { + json['tags'] = + + + tags?.map((e) => nativeToJson(e)).toList() + + +; + } + + + + json['metadata'] = + + + metadata.map((e) => e.toJson()).toList() + + +; + + + return json; + } + + GetCurrentUserUserWatchedMoviesMovie({ + + required this.id, + + required this.title, + + this.genre, + + required this.imageUrl, + + this.releaseYear, + + this.rating, + + this.description, + + this.tags, + + required this.metadata, + + }); +} + + + + class GetCurrentUserUserWatchedMoviesMovieMetadata { + + String? director; + + + + + + + GetCurrentUserUserWatchedMoviesMovieMetadata.fromJson(dynamic json): + director = json['director'] == null ? null : + + nativeFromJson(json['director']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + if (director != null) { + json['director'] = + + nativeToJson(director) + +; + } + + + return json; + } + + GetCurrentUserUserWatchedMoviesMovieMetadata({ + + this.director, + + }); +} + + + class GetCurrentUserData { GetCurrentUserUser? user; diff --git a/dataconnect/lib/movies_connector/get_if_favorited_movie.dart b/dataconnect/lib/movies_connector/get_if_favorited_movie.dart deleted file mode 100644 index 901fb84e..00000000 --- a/dataconnect/lib/movies_connector/get_if_favorited_movie.dart +++ /dev/null @@ -1,171 +0,0 @@ -part of movies_connector; - -class GetIfFavoritedMovieVariablesBuilder { - String movieId; - - - FirebaseDataConnect _dataConnect; - - GetIfFavoritedMovieVariablesBuilder(this._dataConnect, {required String this.movieId,}); - Deserializer dataDeserializer = (dynamic json) => GetIfFavoritedMovieData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (GetIfFavoritedMovieVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - QueryRef ref() { - GetIfFavoritedMovieVariables vars=GetIfFavoritedMovieVariables(movieId: movieId,); - - return _dataConnect.query("GetIfFavoritedMovie", dataDeserializer, varsSerializer, vars); - } -} - - - class GetIfFavoritedMovieFavoriteMovie { - - String movieId; - - - - - - - GetIfFavoritedMovieFavoriteMovie.fromJson(dynamic json): - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - GetIfFavoritedMovieFavoriteMovie({ - - required this.movieId, - - }); -} - - - - class GetIfFavoritedMovieData { - - GetIfFavoritedMovieFavoriteMovie? favorite_movie; - - - - - - - GetIfFavoritedMovieData.fromJson(dynamic json): - favorite_movie = json['favorite_movie'] == null ? null : - - GetIfFavoritedMovieFavoriteMovie.fromJson(json['favorite_movie']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (favorite_movie != null) { - json['favorite_movie'] = - - favorite_movie!.toJson() - -; - } - - - return json; - } - - GetIfFavoritedMovieData({ - - this.favorite_movie, - - }); -} - - - - class GetIfFavoritedMovieVariables { - - String movieId; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - GetIfFavoritedMovieVariables.fromJson(Map json): - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - GetIfFavoritedMovieVariables({ - - required this.movieId, - - }); -} - - - - - - - diff --git a/dataconnect/lib/movies_connector/get_movie_info_for_user.dart b/dataconnect/lib/movies_connector/get_movie_info_for_user.dart new file mode 100644 index 00000000..272e49ea --- /dev/null +++ b/dataconnect/lib/movies_connector/get_movie_info_for_user.dart @@ -0,0 +1,243 @@ +part of movies_connector; + +class GetMovieInfoForUserVariablesBuilder { + String movieId; + + + FirebaseDataConnect _dataConnect; + + GetMovieInfoForUserVariablesBuilder(this._dataConnect, {required String this.movieId,}); + Deserializer dataDeserializer = (dynamic json) => GetMovieInfoForUserData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (GetMovieInfoForUserVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + QueryRef ref() { + GetMovieInfoForUserVariables vars=GetMovieInfoForUserVariables(movieId: movieId,); + + return _dataConnect.query("GetMovieInfoForUser", dataDeserializer, varsSerializer, vars); + } +} + + + class GetMovieInfoForUserFavoriteMovie { + + String movieId; + + + + + + + GetMovieInfoForUserFavoriteMovie.fromJson(dynamic json): + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + GetMovieInfoForUserFavoriteMovie({ + + required this.movieId, + + }); +} + + + + class GetMovieInfoForUserWatchedMovie { + + String movieId; + + + + + + + GetMovieInfoForUserWatchedMovie.fromJson(dynamic json): + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + GetMovieInfoForUserWatchedMovie({ + + required this.movieId, + + }); +} + + + + class GetMovieInfoForUserData { + + GetMovieInfoForUserFavoriteMovie? favorite_movie; + + + GetMovieInfoForUserWatchedMovie? watched_movie; + + + + + + + GetMovieInfoForUserData.fromJson(dynamic json): + favorite_movie = json['favorite_movie'] == null ? null : + + GetMovieInfoForUserFavoriteMovie.fromJson(json['favorite_movie']) + + + + , + + watched_movie = json['watched_movie'] == null ? null : + + GetMovieInfoForUserWatchedMovie.fromJson(json['watched_movie']) + + + + + { + + + + + + } + + + Map toJson() { + Map json = {}; + + + if (favorite_movie != null) { + json['favorite_movie'] = + + favorite_movie!.toJson() + +; + } + + + + if (watched_movie != null) { + json['watched_movie'] = + + watched_movie!.toJson() + +; + } + + + return json; + } + + GetMovieInfoForUserData({ + + this.favorite_movie, + + this.watched_movie, + + }); +} + + + + class GetMovieInfoForUserVariables { + + String movieId; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + GetMovieInfoForUserVariables.fromJson(Map json): + movieId = + + nativeFromJson(json['movieId']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movieId'] = + + nativeToJson(movieId) + +; + + + return json; + } + + GetMovieInfoForUserVariables({ + + required this.movieId, + + }); +} + + + + + + + diff --git a/dataconnect/lib/movies_connector/list_movies_by_partial_title.dart b/dataconnect/lib/movies_connector/list_movies_by_partial_title.dart new file mode 100644 index 00000000..f9e40abc --- /dev/null +++ b/dataconnect/lib/movies_connector/list_movies_by_partial_title.dart @@ -0,0 +1,271 @@ +part of movies_connector; + +class ListMoviesByPartialTitleVariablesBuilder { + String input; + + + FirebaseDataConnect _dataConnect; + + ListMoviesByPartialTitleVariablesBuilder(this._dataConnect, {required String this.input,}); + Deserializer dataDeserializer = (dynamic json) => ListMoviesByPartialTitleData.fromJson(jsonDecode(json)); + Serializer varsSerializer = (ListMoviesByPartialTitleVariables vars) => jsonEncode(vars.toJson()); + Future> execute() { + return this.ref().execute(); + } + QueryRef ref() { + ListMoviesByPartialTitleVariables vars=ListMoviesByPartialTitleVariables(input: input,); + + return _dataConnect.query("ListMoviesByPartialTitle", dataDeserializer, varsSerializer, vars); + } +} + + + class ListMoviesByPartialTitleMovies { + + String id; + + + String title; + + + String? genre; + + + double? rating; + + + String imageUrl; + + + + + + + ListMoviesByPartialTitleMovies.fromJson(dynamic json): + id = + + nativeFromJson(json['id']) + + + + , + + title = + + nativeFromJson(json['title']) + + + + , + + genre = json['genre'] == null ? null : + + nativeFromJson(json['genre']) + + + + , + + rating = json['rating'] == null ? null : + + nativeFromJson(json['rating']) + + + + , + + imageUrl = + + nativeFromJson(json['imageUrl']) + + + + + { + + + + + + + + + + + + } + + + Map toJson() { + Map json = {}; + + + json['id'] = + + nativeToJson(id) + +; + + + + json['title'] = + + nativeToJson(title) + +; + + + + if (genre != null) { + json['genre'] = + + nativeToJson(genre) + +; + } + + + + if (rating != null) { + json['rating'] = + + nativeToJson(rating) + +; + } + + + + json['imageUrl'] = + + nativeToJson(imageUrl) + +; + + + return json; + } + + ListMoviesByPartialTitleMovies({ + + required this.id, + + required this.title, + + this.genre, + + this.rating, + + required this.imageUrl, + + }); +} + + + + class ListMoviesByPartialTitleData { + + List movies; + + + + + + + ListMoviesByPartialTitleData.fromJson(dynamic json): + movies = + + + (json['movies'] as List) + .map((e) => ListMoviesByPartialTitleMovies.fromJson(e)) + .toList() + + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['movies'] = + + + movies.map((e) => e.toJson()).toList() + + +; + + + return json; + } + + ListMoviesByPartialTitleData({ + + required this.movies, + + }); +} + + + + class ListMoviesByPartialTitleVariables { + + String input; + + + + + + @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + + + ListMoviesByPartialTitleVariables.fromJson(Map json): + input = + + nativeFromJson(json['input']) + + + + + { + + + + } + + + Map toJson() { + Map json = {}; + + + json['input'] = + + nativeToJson(input) + +; + + + return json; + } + + ListMoviesByPartialTitleVariables({ + + required this.input, + + }); +} + + + + + + + diff --git a/dataconnect/lib/movies_connector/movies.dart b/dataconnect/lib/movies_connector/movies.dart index cf9114d7..d0bbd1ea 100644 --- a/dataconnect/lib/movies_connector/movies.dart +++ b/dataconnect/lib/movies_connector/movies.dart @@ -8,6 +8,10 @@ part 'add_favorited_movie.dart'; part 'delete_favorited_movie.dart'; +part 'delete_favorited_actor.dart'; + +part 'delete_watched_movie.dart'; + part 'add_review.dart'; part 'update_review.dart'; @@ -26,10 +30,12 @@ part 'get_actor_by_id.dart'; part 'get_current_user.dart'; -part 'get_if_favorited_movie.dart'; +part 'get_movie_info_for_user.dart'; part 'search_all.dart'; +part 'list_movies_by_partial_title.dart'; + enum OrderDirection { @@ -54,8 +60,8 @@ String enumSerializer(Enum e) { class MoviesConnector { - UpsertUserVariablesBuilder upsertUser ({required String username,}) { - return UpsertUserVariablesBuilder(dataConnect, username: username,); + UpsertUserVariablesBuilder upsertUser ({required String username,required String name,}) { + return UpsertUserVariablesBuilder(dataConnect, username: username,name: name,); } @@ -69,6 +75,16 @@ class MoviesConnector { } + DeleteFavoritedActorVariablesBuilder deleteFavoritedActor ({required String actorId,}) { + return DeleteFavoritedActorVariablesBuilder(dataConnect, actorId: actorId,); + } + + + DeleteWatchedMovieVariablesBuilder deleteWatchedMovie ({required String movieId,}) { + return DeleteWatchedMovieVariablesBuilder(dataConnect, movieId: movieId,); + } + + AddReviewVariablesBuilder addReview ({required String movieId,required int rating,required String reviewText,}) { return AddReviewVariablesBuilder(dataConnect, movieId: movieId,rating: rating,reviewText: reviewText,); } @@ -114,8 +130,8 @@ class MoviesConnector { } - GetIfFavoritedMovieVariablesBuilder getIfFavoritedMovie ({required String movieId,}) { - return GetIfFavoritedMovieVariablesBuilder(dataConnect, movieId: movieId,); + GetMovieInfoForUserVariablesBuilder getMovieInfoForUser ({required String movieId,}) { + return GetMovieInfoForUserVariablesBuilder(dataConnect, movieId: movieId,); } @@ -123,6 +139,11 @@ class MoviesConnector { return SearchAllVariablesBuilder(dataConnect, minYear: minYear,maxYear: maxYear,minRating: minRating,maxRating: maxRating,genre: genre,); } + + ListMoviesByPartialTitleVariablesBuilder listMoviesByPartialTitle ({required String input,}) { + return ListMoviesByPartialTitleVariablesBuilder(dataConnect, input: input,); + } + static ConnectorConfig connectorConfig = ConnectorConfig( 'us-central1', diff --git a/dataconnect/lib/movies_connector/upsert_user.dart b/dataconnect/lib/movies_connector/upsert_user.dart index 16d90738..6e472735 100644 --- a/dataconnect/lib/movies_connector/upsert_user.dart +++ b/dataconnect/lib/movies_connector/upsert_user.dart @@ -2,18 +2,19 @@ part of movies_connector; class UpsertUserVariablesBuilder { String username; +String name; FirebaseDataConnect _dataConnect; - UpsertUserVariablesBuilder(this._dataConnect, {required String this.username,}); + UpsertUserVariablesBuilder(this._dataConnect, {required String this.username,required String this.name,}); Deserializer dataDeserializer = (dynamic json) => UpsertUserData.fromJson(jsonDecode(json)); Serializer varsSerializer = (UpsertUserVariables vars) => jsonEncode(vars.toJson()); Future> execute() { return this.ref().execute(); } MutationRef ref() { - UpsertUserVariables vars=UpsertUserVariables(username: username,); + UpsertUserVariables vars=UpsertUserVariables(username: username,name: name,); return _dataConnect.mutation("UpsertUser", dataDeserializer, varsSerializer, vars); } @@ -119,6 +120,9 @@ class UpsertUserVariablesBuilder { String username; + String name; + + @@ -132,11 +136,21 @@ class UpsertUserVariablesBuilder { + , + + name = + + nativeFromJson(json['name']) + + + { + + } @@ -151,6 +165,14 @@ class UpsertUserVariablesBuilder { ; + + json['name'] = + + nativeToJson(name) + +; + + return json; } @@ -158,6 +180,8 @@ class UpsertUserVariablesBuilder { required this.username, + required this.name, + }); } diff --git a/dataconnect/lib/profile.dart b/dataconnect/lib/profile.dart index 1a7768ff..14364f78 100644 --- a/dataconnect/lib/profile.dart +++ b/dataconnect/lib/profile.dart @@ -1,5 +1,8 @@ +import 'package:dataconnect/extensions.dart'; import 'package:dataconnect/main.dart'; +import 'package:dataconnect/movies_connector/movies.dart'; import 'package:dataconnect/util/auth.dart'; +import 'package:dataconnect/widgets/list_movies.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -13,6 +16,10 @@ class Profile extends StatefulWidget { class _ProfileState extends State { User? _currentUser; + List _favoriteMovies = []; + List _favoriteActors = []; + List _watchedMovies = []; + String? _displayName; @override void initState() { super.initState(); @@ -21,6 +28,16 @@ class _ProfileState extends State { _currentUser = user; }); }); + MoviesConnector.instance.getCurrentUser().execute().then((res) { + setState(() { + _displayName = res.data.user!.name; + _favoriteMovies = + res.data.user!.favoriteMovies.map((e) => e.movie).toList(); + _favoriteActors = res.data.user!.favoriteActors; + _watchedMovies = + res.data.user!.watchedMovies.map((e) => e.movie).toList(); + }); + }); } Widget _UserInfo() { @@ -47,11 +64,30 @@ class _ProfileState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [CircularProgressIndicator()], ) - : Container( + : SingleChildScrollView( + child: Container( padding: EdgeInsets.all(30), child: Column( - children: [_UserInfo()], + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _UserInfo(), + ListMovies( + title: "Watched Movies", + movies: _watchedMovies + .map( + (e) => e.toListMoviesMovies, + ) + .toList()), + ListMovies( + title: "Favorite Movies", + movies: _favoriteMovies + .map( + (e) => e.toListMoviesMovies, + ) + .toList()) + ], ), - ); + )); } } diff --git a/dataconnect/lib/router.dart b/dataconnect/lib/router.dart index f639a8b3..fbe1d0b1 100644 --- a/dataconnect/lib/router.dart +++ b/dataconnect/lib/router.dart @@ -1,6 +1,7 @@ import 'package:dataconnect/destination.dart'; import 'package:dataconnect/login.dart'; import 'package:dataconnect/profile.dart'; +import 'package:dataconnect/search.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -55,7 +56,7 @@ var router = GoRouter(initialLocation: homePath.path, routes: [ StatefulShellBranch(routes: [ GoRoute( path: "/search", - builder: (context, state) => const Text('abc'), + builder: (context, state) => const Search(), ), ]), StatefulShellBranch(routes: [ @@ -68,6 +69,9 @@ var router = GoRouter(initialLocation: homePath.path, routes: [ GoRoute( path: "/login", builder: (context, state) => const Login(), + redirect: (context, state) async { + return (await Auth.isLoggedIn()) ? '/profile' : null; + }, ), GoRoute( path: "/signup", diff --git a/dataconnect/lib/search.dart b/dataconnect/lib/search.dart new file mode 100644 index 00000000..342b771f --- /dev/null +++ b/dataconnect/lib/search.dart @@ -0,0 +1,270 @@ +import 'package:dataconnect/extensions.dart'; +import 'package:dataconnect/movies_connector/movies.dart'; +import 'package:dataconnect/widgets/list_actors.dart'; +import 'package:dataconnect/widgets/list_movies.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class Search extends StatefulWidget { + const Search({super.key}); + + @override + State createState() => _SearchState(); +} + +class SearchFormState { + String title = ''; + int maxYear = 2024; + int minYear = 1900; + double minRating = 1.0; + double maxRating = 5.0; + String genre = ''; + @override + String toString() { + return { + 'title': title, + 'maxYear': maxYear, + 'minYear': minYear, + 'minRating': minRating, + 'maxRating': maxRating, + 'genre': genre + }.toString(); + } +} + +class _SearchState extends State { + final _formKey = GlobalKey(); + final SearchFormState _searchFormState = SearchFormState(); + List _resultsMovieMatchingTitle = []; + List _resultsMovieMatchingDescription = + []; + List _actorsMatchingName = []; + List _reviewsMatchingText = []; + + void _searchMovie() { + MoviesConnector.instance + .searchAll( + minYear: _searchFormState.minYear, + maxYear: _searchFormState.maxYear, + minRating: _searchFormState.minRating, + maxRating: _searchFormState.maxRating, + genre: _searchFormState.genre, + ) + .input(_searchFormState.title) + .execute() + .then((value) { + setState(() { + _actorsMatchingName = value.data.actorsMatchingName; + _resultsMovieMatchingTitle = value.data.moviesMatchingTitle; + _resultsMovieMatchingDescription = value.data.moviesMatchingDescription; + _reviewsMatchingText = value.data.reviewsMatchingText; + }); + }); + } + + Widget _buildForm() { + return Form( + key: _formKey, + child: Column( + children: [ + Row( + children: [ + Expanded( + flex: 4, + child: TextFormField( + initialValue: _searchFormState.title, + decoration: const InputDecoration(hintText: 'Title'), + onChanged: (value) { + setState(() { + _searchFormState.title = value; + }); + }, + ), + ), + const SizedBox(width: 10), + Expanded( + flex: 1, + child: IconButton( + icon: const Icon(Icons.search), + onPressed: () { + _searchMovie(); + }, + ), + ), + ], + ), + Row( + children: [ + Expanded( + flex: 1, + child: TextFormField( + initialValue: _searchFormState.minYear.toString(), + decoration: + const InputDecoration(hintText: 'Release Year From'), + keyboardType: TextInputType.number, + onChanged: (value) { + print(value); + setState(() { + _searchFormState.minYear = int.parse(value); + }); + }, + ), + ), + const SizedBox(width: 10), + Expanded( + flex: 1, + child: TextFormField( + initialValue: _searchFormState.genre, + decoration: const InputDecoration(hintText: 'Genre'), + onChanged: (value) { + setState(() { + _searchFormState.genre = value; + }); + }, + ), + ), + const SizedBox(width: 10), + Expanded( + flex: 1, + child: TextFormField( + initialValue: _searchFormState.minRating.toString(), + decoration: const InputDecoration(hintText: 'Rating From'), + keyboardType: TextInputType.number, + onChanged: (value) { + setState(() { + _searchFormState.minRating = + value.isEmpty ? 0 : double.parse(value); + }); + }, + ), + ) + ], + ), + Row( + children: [ + Expanded( + flex: 1, + child: TextFormField( + initialValue: _searchFormState.maxYear.toString(), + decoration: + const InputDecoration(hintText: 'Release Year To'), + keyboardType: TextInputType.number, + onChanged: (value) { + setState(() { + _searchFormState.maxYear = int.parse(value); + }); + }, + ), + ), + const Expanded( + flex: 1, + child: SizedBox(), + ), + const SizedBox(width: 10), + Expanded( + flex: 1, + child: TextFormField( + initialValue: _searchFormState.maxRating.toString(), + decoration: const InputDecoration(hintText: 'Rating To'), + keyboardType: TextInputType.number, + onChanged: (value) { + setState(() { + _searchFormState.maxRating = + value.isEmpty ? 0 : double.parse(value); + }); + }, + ), + ) + ], + ) + ], + )); + } + + Widget _buildRatingList() { + return SizedBox( + height: 125, + child: Expanded( + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + var rating = _reviewsMatchingText[index]; + return Card( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(rating.user.username), + Row( + children: [ + Text(DateFormat.yMMMd().format(rating.reviewDate)), + const SizedBox( + width: 10, + ), + Text("Rating ${rating.rating}") + ], + ), + Text(rating.reviewText!) + ], + )), + ); + }, + itemCount: _reviewsMatchingText.length, + ))); + + // return Expanded(child: Text('abc')); + } + + Widget _buildResults() { + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('Results', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30)), + ListMovies( + movies: _resultsMovieMatchingTitle + .map((e) => e.toListMoviesMovies) + .toList(), + title: "Movies Matching Title"), + ListMovies( + movies: _resultsMovieMatchingDescription + .map((e) => e.toListMoviesMovies) + .toList(), + title: "Movies Matching Description"), + const Text('Results matching reviews', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20)), + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: SingleChildScrollView( + child: Container( + margin: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('Advanced Search', + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 30)), + _buildForm(), + _buildResults(), + _buildRatingList(), + ListActors( + title: "Actors Matching Title", + actors: _actorsMatchingName + .map((actor) => Actor( + id: actor.id, + imageUrl: actor.imageUrl, + name: actor.name)) + .toList()) + ], + ))))); + } +} diff --git a/dataconnect/lib/sign_up.dart b/dataconnect/lib/sign_up.dart index 676f1387..fcdcd226 100644 --- a/dataconnect/lib/sign_up.dart +++ b/dataconnect/lib/sign_up.dart @@ -1,3 +1,4 @@ +import 'package:dataconnect/movies_connector/movies.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -13,7 +14,7 @@ class _SignUpState extends State { final _formKey = GlobalKey(); String _username = ''; String _password = ''; - String _confirmPassword = ''; + String _name = ''; Widget _buildForm() { return Form( key: _formKey, @@ -36,22 +37,17 @@ class _SignUpState extends State { ), const SizedBox(height: 30), TextFormField( - obscureText: true, enableSuggestions: false, - autocorrect: false, decoration: const InputDecoration( - hintText: "Password", border: OutlineInputBorder()), + hintText: "Name", border: OutlineInputBorder()), onChanged: (value) { setState(() { - _password = value; + _name = value; }); }, validator: (value) { if (value == null || value.isEmpty) { - return 'Please enter a password'; - } - if (value != _confirmPassword) { - return 'Passwords do not match'; + return 'Please enter a name'; } return null; }, @@ -62,19 +58,16 @@ class _SignUpState extends State { enableSuggestions: false, autocorrect: false, decoration: const InputDecoration( - hintText: "Confirm Password", border: OutlineInputBorder()), + hintText: "Password", border: OutlineInputBorder()), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter some text'; } - if (value != _password) { - return 'Passwords do not match'; - } return null; }, onChanged: (value) { setState(() { - _confirmPassword = value; + _password = value; }); }, ), @@ -95,6 +88,9 @@ class _SignUpState extends State { try { await FirebaseAuth.instance.createUserWithEmailAndPassword( email: _username, password: _password); + await MoviesConnector.instance + .upsertUser(username: _username, name: _name) + .execute(); if (mounted) { context.go('/home'); } diff --git a/dataconnect/lib/util/auth.dart b/dataconnect/lib/util/auth.dart index b31c1409..5935ce58 100644 --- a/dataconnect/lib/util/auth.dart +++ b/dataconnect/lib/util/auth.dart @@ -1,9 +1,18 @@ import 'package:firebase_auth/firebase_auth.dart'; class Auth { - static isLoggedIn() async { + static Future isLoggedIn() async { User? user = await FirebaseAuth.instance.authStateChanges().first; - return user != null; + if (user == null) { + return false; + } + try { + String? idToken = await user.getIdToken(); + print(idToken); + return idToken != null; + } catch (_) { + return false; + } } static getCurrentUser() { diff --git a/dataconnect/lib/widgets/list_actors.dart b/dataconnect/lib/widgets/list_actors.dart new file mode 100644 index 00000000..47ea5dbd --- /dev/null +++ b/dataconnect/lib/widgets/list_actors.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; + +class Actor { + Actor({required this.imageUrl, required this.name, required this.id}); + String imageUrl; + String name; + String id; +} + +class ListActors extends StatefulWidget { + const ListActors({super.key, required this.actors, required this.title}); + final List actors; + final String title; + + @override + State createState() => _ListActorsState(); +} + +class _ListActorsState extends State { + _buildActor(Actor actor) { + return SizedBox( + width: 100, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + CircleAvatar( + radius: 30, + child: ClipOval(child: Image.network(actor.imageUrl))), + Text( + actor.name, + overflow: TextOverflow.ellipsis, + ) + ])); + } + + _buildActorsList() { + return SizedBox( + height: 125, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.title, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + Expanded( + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + return _buildActor(widget.actors[index]); + }, + itemCount: widget.actors.length, + )) + ], + )); + } + + @override + Widget build(BuildContext context) { + return _buildActorsList(); + } +} diff --git a/dataconnect/lib/widgets/list_movies.dart b/dataconnect/lib/widgets/list_movies.dart new file mode 100644 index 00000000..b9ac39a0 --- /dev/null +++ b/dataconnect/lib/widgets/list_movies.dart @@ -0,0 +1,91 @@ +import 'package:dataconnect/movies_connector/movies.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class ListMovies extends StatefulWidget { + const ListMovies({super.key, required this.movies, required this.title}); + + final List movies; + final String title; + @override + State createState() => _ListMoviesState(); +} + +class _ListMoviesState extends State { + Widget _buildMovieList(String title, List movies) { + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + title, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + ), + movies.isEmpty + ? Padding( + padding: const EdgeInsets.all(10.0), + child: Text( + "No $title", + style: const TextStyle( + fontSize: 15, fontWeight: FontWeight.bold), + )) + : SizedBox( + height: 300, // Adjust the height as needed + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: movies.length, + itemBuilder: (context, index) { + return _buildMovieItem(movies[index]); + }, + ), + ), + ], + ); + } + + void _visitDetail(String id) { + context.push("/movies/$id"); + } + + Widget _buildMovieItem(ListMoviesMovies movie) { + return Container( + width: 150, // Adjust the width as needed + padding: const EdgeInsets.all(4.0), + child: Card( + child: InkWell( + onTap: () { + _visitDetail(movie.id); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: 9 / 16, // 9:16 aspect ratio for the image + child: Image.network( + movie.imageUrl, + fit: BoxFit.cover, + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + movie.title, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + ], + )), + ), + ); + } + + @override + Widget build(BuildContext context) { + return _buildMovieList(widget.title, widget.movies); + } +} diff --git a/dataconnect/lib/widgets/login_guard.dart b/dataconnect/lib/widgets/login_guard.dart new file mode 100644 index 00000000..3072c4c4 --- /dev/null +++ b/dataconnect/lib/widgets/login_guard.dart @@ -0,0 +1,38 @@ +import 'package:dataconnect/util/auth.dart'; +import 'package:flutter/material.dart'; + +class LoginGuard extends StatefulWidget { + const LoginGuard({super.key, required this.widgetToGuard, this.message}); + + final Widget widgetToGuard; + + final String? message; + + @override + State createState() => _LoginGuardState(); +} + +class _LoginGuardState extends State { + bool isLoggedIn = false; + @override + void initState() { + super.initState(); + Auth.isLoggedIn().then((value) { + setState(() { + isLoggedIn = value; + }); + }); + } + + @override + Widget build(BuildContext context) { + if (isLoggedIn) { + return widget.widgetToGuard; + } + if (widget.message == null) { + return const SizedBox(); + } + return Text( + 'Please visit the Profile page to log in before ${widget.message}'); + } +} From 9b786e03c5e872318b53f728fdb1601587a3e05e Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 14 Nov 2024 15:22:27 -0800 Subject: [PATCH 04/17] Removed options file --- dataconnect/lib/firebase_options.dart | 87 --------------------------- 1 file changed, 87 deletions(-) delete mode 100644 dataconnect/lib/firebase_options.dart diff --git a/dataconnect/lib/firebase_options.dart b/dataconnect/lib/firebase_options.dart deleted file mode 100644 index e26e9441..00000000 --- a/dataconnect/lib/firebase_options.dart +++ /dev/null @@ -1,87 +0,0 @@ -// File generated by FlutterFire CLI. -// ignore_for_file: type=lint -import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; -import 'package:flutter/foundation.dart' - show defaultTargetPlatform, kIsWeb, TargetPlatform; - -/// Default [FirebaseOptions] for use with your Firebase apps. -/// -/// Example: -/// ```dart -/// import 'firebase_options.dart'; -/// // ... -/// await Firebase.initializeApp( -/// options: DefaultFirebaseOptions.currentPlatform, -/// ); -/// ``` -class DefaultFirebaseOptions { - static FirebaseOptions get currentPlatform { - if (kIsWeb) { - return web; - } - switch (defaultTargetPlatform) { - case TargetPlatform.android: - return android; - case TargetPlatform.iOS: - return ios; - case TargetPlatform.macOS: - return macos; - case TargetPlatform.windows: - return windows; - case TargetPlatform.linux: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for linux - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); - default: - throw UnsupportedError( - 'DefaultFirebaseOptions are not supported for this platform.', - ); - } - } - - static const FirebaseOptions web = FirebaseOptions( - apiKey: 'AIzaSyDP_NulZ2xnDHFRAbBX45RPqkpzXfGjKJI', - appId: '1:731568610039:web:2896847d0f5655fb7251f2', - messagingSenderId: '731568610039', - projectId: 'quickstart-flutter-cc624', - authDomain: 'quickstart-flutter-cc624.firebaseapp.com', - storageBucket: 'quickstart-flutter-cc624.firebasestorage.app', - ); - - static const FirebaseOptions android = FirebaseOptions( - apiKey: 'AIzaSyA45BWLEXFb2SRqtMu6LoCL2f53k-6_0GM', - appId: '1:731568610039:android:2fda8b27330be9447251f2', - messagingSenderId: '731568610039', - projectId: 'quickstart-flutter-cc624', - storageBucket: 'quickstart-flutter-cc624.firebasestorage.app', - ); - - static const FirebaseOptions ios = FirebaseOptions( - apiKey: 'AIzaSyCqVWdSdrCPRZ6Ld_6j1hjpWfPIUg-7_5I', - appId: '1:731568610039:ios:e78b43f1d75a77d87251f2', - messagingSenderId: '731568610039', - projectId: 'quickstart-flutter-cc624', - storageBucket: 'quickstart-flutter-cc624.firebasestorage.app', - iosBundleId: 'com.example.dataconnect', - ); - - static const FirebaseOptions macos = FirebaseOptions( - apiKey: 'AIzaSyCqVWdSdrCPRZ6Ld_6j1hjpWfPIUg-7_5I', - appId: '1:731568610039:ios:e78b43f1d75a77d87251f2', - messagingSenderId: '731568610039', - projectId: 'quickstart-flutter-cc624', - storageBucket: 'quickstart-flutter-cc624.firebasestorage.app', - iosBundleId: 'com.example.dataconnect', - ); - - static const FirebaseOptions windows = FirebaseOptions( - apiKey: 'AIzaSyDP_NulZ2xnDHFRAbBX45RPqkpzXfGjKJI', - appId: '1:731568610039:web:3c1e404f955f0b467251f2', - messagingSenderId: '731568610039', - projectId: 'quickstart-flutter-cc624', - authDomain: 'quickstart-flutter-cc624.firebaseapp.com', - storageBucket: 'quickstart-flutter-cc624.firebasestorage.app', - ); - -} \ No newline at end of file From 10d8fe56c189ec173de0bbd0d9c405668573854d Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 14 Nov 2024 15:23:19 -0800 Subject: [PATCH 05/17] Removed unnecessary --- .../.dataconnect/schema/main/implicit.gql | 60 - .../.dataconnect/schema/main/input.gql | 1456 ------------ .../.dataconnect/schema/main/mutation.gql | 970 -------- .../.dataconnect/schema/main/query.gql | 393 ---- .../.dataconnect/schema/main/relation.gql | 510 ----- .../.dataconnect/schema/prelude.gql | 2026 ----------------- 6 files changed, 5415 deletions(-) delete mode 100644 dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql delete mode 100644 dataconnect/dataconnect/.dataconnect/schema/main/input.gql delete mode 100644 dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql delete mode 100644 dataconnect/dataconnect/.dataconnect/schema/main/query.gql delete mode 100644 dataconnect/dataconnect/.dataconnect/schema/main/relation.gql delete mode 100644 dataconnect/dataconnect/.dataconnect/schema/prelude.gql diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql b/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql deleted file mode 100644 index a63e2f15..00000000 --- a/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql +++ /dev/null @@ -1,60 +0,0 @@ -extend type FavoriteActor { - """ - ✨ Implicit foreign key field based on `FavoriteActor`.`user`. It must match the value of `User`.`id`. See `@ref` for how to customize it. - """ - userId: String! @fdc_generated(from: "FavoriteActor.user", purpose: IMPLICIT_REF_FIELD) - """ - ✨ Implicit foreign key field based on `FavoriteActor`.`actor`. It must match the value of `Actor`.`id`. See `@ref` for how to customize it. - """ - actorId: UUID! @fdc_generated(from: "FavoriteActor.actor", purpose: IMPLICIT_REF_FIELD) -} -extend type FavoriteMovie { - """ - ✨ Implicit foreign key field based on `FavoriteMovie`.`user`. It must match the value of `User`.`id`. See `@ref` for how to customize it. - """ - userId: String! @fdc_generated(from: "FavoriteMovie.user", purpose: IMPLICIT_REF_FIELD) - """ - ✨ Implicit foreign key field based on `FavoriteMovie`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it. - """ - movieId: UUID! @fdc_generated(from: "FavoriteMovie.movie", purpose: IMPLICIT_REF_FIELD) -} -extend type MovieActor { - """ - ✨ Implicit foreign key field based on `MovieActor`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it. - """ - movieId: UUID! @fdc_generated(from: "MovieActor.movie", purpose: IMPLICIT_REF_FIELD) - """ - ✨ Implicit foreign key field based on `MovieActor`.`actor`. It must match the value of `Actor`.`id`. See `@ref` for how to customize it. - """ - actorId: UUID! @fdc_generated(from: "MovieActor.actor", purpose: IMPLICIT_REF_FIELD) -} -extend type MovieMetadata { - """ - ✨ Implicit primary key field. It's a UUID column default to a generated new value. See `@table` for how to customize it. - """ - id: UUID! @default(expr: "uuidV4()") @fdc_generated(from: "MovieMetadata", purpose: IMPLICIT_KEY_FIELD) - """ - ✨ Implicit foreign key field based on `MovieMetadata`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it. - """ - movieId: UUID! @fdc_generated(from: "MovieMetadata.movie", purpose: IMPLICIT_REF_FIELD) -} -extend type Review { - """ - ✨ Implicit foreign key field based on `Review`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it. - """ - movieId: UUID! @fdc_generated(from: "Review.movie", purpose: IMPLICIT_REF_FIELD) - """ - ✨ Implicit foreign key field based on `Review`.`user`. It must match the value of `User`.`id`. See `@ref` for how to customize it. - """ - userId: String! @fdc_generated(from: "Review.user", purpose: IMPLICIT_REF_FIELD) -} -extend type WatchedMovie { - """ - ✨ Implicit foreign key field based on `WatchedMovie`.`user`. It must match the value of `User`.`id`. See `@ref` for how to customize it. - """ - userId: String! @fdc_generated(from: "WatchedMovie.user", purpose: IMPLICIT_REF_FIELD) - """ - ✨ Implicit foreign key field based on `WatchedMovie`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it. - """ - movieId: UUID! @fdc_generated(from: "WatchedMovie.movie", purpose: IMPLICIT_REF_FIELD) -} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/input.gql b/dataconnect/dataconnect/.dataconnect/schema/main/input.gql deleted file mode 100644 index 8fae7303..00000000 --- a/dataconnect/dataconnect/.dataconnect/schema/main/input.gql +++ /dev/null @@ -1,1456 +0,0 @@ -""" -✨ `Actor_KeyOutput` returns the primary key fields of table type `Actor`. - -It has the same format as `Actor_Key`, but is only used as mutation return value. -""" -scalar Actor_KeyOutput -""" -✨ `FavoriteActor_KeyOutput` returns the primary key fields of table type `FavoriteActor`. - -It has the same format as `FavoriteActor_Key`, but is only used as mutation return value. -""" -scalar FavoriteActor_KeyOutput -""" -✨ `FavoriteMovie_KeyOutput` returns the primary key fields of table type `FavoriteMovie`. - -It has the same format as `FavoriteMovie_Key`, but is only used as mutation return value. -""" -scalar FavoriteMovie_KeyOutput -""" -✨ `Movie_KeyOutput` returns the primary key fields of table type `Movie`. - -It has the same format as `Movie_Key`, but is only used as mutation return value. -""" -scalar Movie_KeyOutput -""" -✨ `MovieActor_KeyOutput` returns the primary key fields of table type `MovieActor`. - -It has the same format as `MovieActor_Key`, but is only used as mutation return value. -""" -scalar MovieActor_KeyOutput -""" -✨ `MovieMetadata_KeyOutput` returns the primary key fields of table type `MovieMetadata`. - -It has the same format as `MovieMetadata_Key`, but is only used as mutation return value. -""" -scalar MovieMetadata_KeyOutput -""" -✨ `Review_KeyOutput` returns the primary key fields of table type `Review`. - -It has the same format as `Review_Key`, but is only used as mutation return value. -""" -scalar Review_KeyOutput -""" -✨ `User_KeyOutput` returns the primary key fields of table type `User`. - -It has the same format as `User_Key`, but is only used as mutation return value. -""" -scalar User_KeyOutput -""" -✨ `WatchedMovie_KeyOutput` returns the primary key fields of table type `WatchedMovie`. - -It has the same format as `WatchedMovie_Key`, but is only used as mutation return value. -""" -scalar WatchedMovie_KeyOutput -""" -✨ Generated data input type for table 'Actor'. It includes all necessary fields for creating or upserting rows into table. -""" -input Actor_Data { - """ - ✨ Generated from Field `Actor`.`id` of type `UUID!` - """ - id: UUID - """ - ✨ `_expr` server value variant of `id` (✨ Generated from Field `Actor`.`id` of type `UUID!`) - """ - id_expr: UUID_Expr - """ - ✨ Generated from Field `Actor`.`imageUrl` of type `String!` - """ - imageUrl: String - """ - ✨ `_expr` server value variant of `imageUrl` (✨ Generated from Field `Actor`.`imageUrl` of type `String!`) - """ - imageUrl_expr: String_Expr - """ - ✨ Generated from Field `Actor`.`name` of type `String!` - """ - name: String - """ - ✨ `_expr` server value variant of `name` (✨ Generated from Field `Actor`.`name` of type `String!`) - """ - name_expr: String_Expr -} -""" -✨ Generated filter input type for table 'Actor'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. -""" -input Actor_Filter { - """ - Apply multiple filter conditions using `AND` logic. - """ - _and: [Actor_Filter!] - """ - Negate the result of the provided filter condition. - """ - _not: Actor_Filter - """ - Apply multiple filter conditions using `OR` logic. - """ - _or: [Actor_Filter!] - """ - ✨ Generated from Field `Actor`.`id` of type `UUID!` - """ - id: UUID_Filter - """ - ✨ Generated from Field `Actor`.`imageUrl` of type `String!` - """ - imageUrl: String_Filter - """ - ✨ Generated from Field `Actor`.`name` of type `String!` - """ - name: String_Filter - """ - ✨ Generated from Field `Actor`.`favorite_actors_on_actor` of type `[FavoriteActor!]!` - """ - favorite_actors_on_actor: FavoriteActor_ListFilter - """ - ✨ Generated from Field `Actor`.`movieActors_on_actor` of type `[MovieActor!]!` - """ - movieActors_on_actor: MovieActor_ListFilter - """ - ✨ Generated from Field `Actor`.`movies_via_MovieActor` of type `[Movie!]!` - """ - movies_via_MovieActor: Movie_ListFilter - """ - ✨ Generated from Field `Actor`.`users_via_FavoriteActor` of type `[User!]!` - """ - users_via_FavoriteActor: User_ListFilter -} -""" -✨ Generated first-row input type for table 'Actor'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. -""" -input Actor_FirstRow { - """ - Order the result by the specified fields. - """ - orderBy: [Actor_Order!] - """ - Filters rows based on the specified conditions. - """ - where: Actor_Filter -} -""" -✨ Generated key input type for table 'Actor'. It represents the primary key fields used to uniquely identify a row in the table. -""" -input Actor_Key { - """ - ✨ Generated from Field `Actor`.`id` of type `UUID!` - """ - id: UUID - """ - ✨ `_expr` server value variant of `id` (✨ Generated from Field `Actor`.`id` of type `UUID!`) - """ - id_expr: UUID_Expr -} -""" -✨ Generated list filter input type for table 'Actor'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. -""" -input Actor_ListFilter { - """ - The desired number of objects that match the condition (defaults to at least one). - """ - count: Int_Filter = {gt:0} - """ - Condition of the related objects to filter for. - """ - exist: Actor_Filter -} -""" -✨ Generated order input type for table 'Actor'. This input defines the sorting order of rows in query results based on one or more fields. -""" -input Actor_Order { - """ - ✨ Generated from Field `Actor`.`id` of type `UUID!` - """ - id: OrderDirection - """ - ✨ Generated from Field `Actor`.`imageUrl` of type `String!` - """ - imageUrl: OrderDirection - """ - ✨ Generated from Field `Actor`.`name` of type `String!` - """ - name: OrderDirection -} -""" -✨ Generated data input type for table 'FavoriteActor'. It includes all necessary fields for creating or upserting rows into table. -""" -input FavoriteActor_Data { - """ - ✨ Generated from Field `FavoriteActor`.`userId` of type `String!` - """ - userId: String - """ - ✨ `_expr` server value variant of `userId` (✨ Generated from Field `FavoriteActor`.`userId` of type `String!`) - """ - userId_expr: String_Expr - """ - ✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!` - """ - actorId: UUID - """ - ✨ `_expr` server value variant of `actorId` (✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!`) - """ - actorId_expr: UUID_Expr - """ - ✨ Generated from Field `FavoriteActor`.`actor` of type `Actor!` - """ - actor: Actor_Key - """ - ✨ Generated from Field `FavoriteActor`.`user` of type `User!` - """ - user: User_Key -} -""" -✨ Generated filter input type for table 'FavoriteActor'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. -""" -input FavoriteActor_Filter { - """ - Apply multiple filter conditions using `AND` logic. - """ - _and: [FavoriteActor_Filter!] - """ - Negate the result of the provided filter condition. - """ - _not: FavoriteActor_Filter - """ - Apply multiple filter conditions using `OR` logic. - """ - _or: [FavoriteActor_Filter!] - """ - ✨ Generated from Field `FavoriteActor`.`userId` of type `String!` - """ - userId: String_Filter - """ - ✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!` - """ - actorId: UUID_Filter - """ - ✨ Generated from Field `FavoriteActor`.`actor` of type `Actor!` - """ - actor: Actor_Filter - """ - ✨ Generated from Field `FavoriteActor`.`user` of type `User!` - """ - user: User_Filter -} -""" -✨ Generated first-row input type for table 'FavoriteActor'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. -""" -input FavoriteActor_FirstRow { - """ - Order the result by the specified fields. - """ - orderBy: [FavoriteActor_Order!] - """ - Filters rows based on the specified conditions. - """ - where: FavoriteActor_Filter -} -""" -✨ Generated key input type for table 'FavoriteActor'. It represents the primary key fields used to uniquely identify a row in the table. -""" -input FavoriteActor_Key { - """ - ✨ Generated from Field `FavoriteActor`.`userId` of type `String!` - """ - userId: String - """ - ✨ `_expr` server value variant of `userId` (✨ Generated from Field `FavoriteActor`.`userId` of type `String!`) - """ - userId_expr: String_Expr - """ - ✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!` - """ - actorId: UUID - """ - ✨ `_expr` server value variant of `actorId` (✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!`) - """ - actorId_expr: UUID_Expr -} -""" -✨ Generated list filter input type for table 'FavoriteActor'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. -""" -input FavoriteActor_ListFilter { - """ - The desired number of objects that match the condition (defaults to at least one). - """ - count: Int_Filter = {gt:0} - """ - Condition of the related objects to filter for. - """ - exist: FavoriteActor_Filter -} -""" -✨ Generated order input type for table 'FavoriteActor'. This input defines the sorting order of rows in query results based on one or more fields. -""" -input FavoriteActor_Order { - """ - ✨ Generated from Field `FavoriteActor`.`userId` of type `String!` - """ - userId: OrderDirection - """ - ✨ Generated from Field `FavoriteActor`.`actorId` of type `UUID!` - """ - actorId: OrderDirection - """ - ✨ Generated from Field `FavoriteActor`.`actor` of type `Actor!` - """ - actor: Actor_Order - """ - ✨ Generated from Field `FavoriteActor`.`user` of type `User!` - """ - user: User_Order -} -""" -✨ Generated data input type for table 'FavoriteMovie'. It includes all necessary fields for creating or upserting rows into table. -""" -input FavoriteMovie_Data { - """ - ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!` - """ - userId: String - """ - ✨ `_expr` server value variant of `userId` (✨ Generated from Field `FavoriteMovie`.`userId` of type `String!`) - """ - userId_expr: String_Expr - """ - ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!` - """ - movieId: UUID - """ - ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!`) - """ - movieId_expr: UUID_Expr - """ - ✨ Generated from Field `FavoriteMovie`.`movie` of type `Movie!` - """ - movie: Movie_Key - """ - ✨ Generated from Field `FavoriteMovie`.`user` of type `User!` - """ - user: User_Key -} -""" -✨ Generated filter input type for table 'FavoriteMovie'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. -""" -input FavoriteMovie_Filter { - """ - Apply multiple filter conditions using `AND` logic. - """ - _and: [FavoriteMovie_Filter!] - """ - Negate the result of the provided filter condition. - """ - _not: FavoriteMovie_Filter - """ - Apply multiple filter conditions using `OR` logic. - """ - _or: [FavoriteMovie_Filter!] - """ - ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!` - """ - userId: String_Filter - """ - ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!` - """ - movieId: UUID_Filter - """ - ✨ Generated from Field `FavoriteMovie`.`movie` of type `Movie!` - """ - movie: Movie_Filter - """ - ✨ Generated from Field `FavoriteMovie`.`user` of type `User!` - """ - user: User_Filter -} -""" -✨ Generated first-row input type for table 'FavoriteMovie'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. -""" -input FavoriteMovie_FirstRow { - """ - Order the result by the specified fields. - """ - orderBy: [FavoriteMovie_Order!] - """ - Filters rows based on the specified conditions. - """ - where: FavoriteMovie_Filter -} -""" -✨ Generated key input type for table 'FavoriteMovie'. It represents the primary key fields used to uniquely identify a row in the table. -""" -input FavoriteMovie_Key { - """ - ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!` - """ - userId: String - """ - ✨ `_expr` server value variant of `userId` (✨ Generated from Field `FavoriteMovie`.`userId` of type `String!`) - """ - userId_expr: String_Expr - """ - ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!` - """ - movieId: UUID - """ - ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!`) - """ - movieId_expr: UUID_Expr -} -""" -✨ Generated list filter input type for table 'FavoriteMovie'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. -""" -input FavoriteMovie_ListFilter { - """ - The desired number of objects that match the condition (defaults to at least one). - """ - count: Int_Filter = {gt:0} - """ - Condition of the related objects to filter for. - """ - exist: FavoriteMovie_Filter -} -""" -✨ Generated order input type for table 'FavoriteMovie'. This input defines the sorting order of rows in query results based on one or more fields. -""" -input FavoriteMovie_Order { - """ - ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!` - """ - userId: OrderDirection - """ - ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!` - """ - movieId: OrderDirection - """ - ✨ Generated from Field `FavoriteMovie`.`movie` of type `Movie!` - """ - movie: Movie_Order - """ - ✨ Generated from Field `FavoriteMovie`.`user` of type `User!` - """ - user: User_Order -} -""" -✨ Generated filter input type for table 'Genre'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. -""" -input Genre_Filter { - """ - Apply multiple filter conditions using `AND` logic. - """ - _and: [Genre_Filter!] - """ - Negate the result of the provided filter condition. - """ - _not: Genre_Filter - """ - Apply multiple filter conditions using `OR` logic. - """ - _or: [Genre_Filter!] - """ - ✨ Generated from Field `Genre`.`genre` of type `String` - """ - genre: String_Filter -} -""" -✨ Generated first-row input type for table 'Genre'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. -""" -input Genre_FirstRow { - """ - Order the result by the specified fields. - """ - orderBy: [Genre_Order!] - """ - Filters rows based on the specified conditions. - """ - where: Genre_Filter -} -""" -✨ Generated list filter input type for table 'Genre'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. -""" -input Genre_ListFilter { - """ - The desired number of objects that match the condition (defaults to at least one). - """ - count: Int_Filter = {gt:0} - """ - Condition of the related objects to filter for. - """ - exist: Genre_Filter -} -""" -✨ Generated order input type for table 'Genre'. This input defines the sorting order of rows in query results based on one or more fields. -""" -input Genre_Order { - """ - ✨ Generated from Field `Genre`.`genre` of type `String` - """ - genre: OrderDirection -} -""" -✨ Generated data input type for table 'Movie'. It includes all necessary fields for creating or upserting rows into table. -""" -input Movie_Data { - """ - ✨ Generated from Field `Movie`.`id` of type `UUID!` - """ - id: UUID - """ - ✨ `_expr` server value variant of `id` (✨ Generated from Field `Movie`.`id` of type `UUID!`) - """ - id_expr: UUID_Expr - """ - ✨ Generated from Field `Movie`.`description` of type `String` - """ - description: String - """ - ✨ `_expr` server value variant of `description` (✨ Generated from Field `Movie`.`description` of type `String`) - """ - description_expr: String_Expr - """ - ✨ Generated from Field `Movie`.`genre` of type `String` - """ - genre: String - """ - ✨ `_expr` server value variant of `genre` (✨ Generated from Field `Movie`.`genre` of type `String`) - """ - genre_expr: String_Expr - """ - ✨ Generated from Field `Movie`.`imageUrl` of type `String!` - """ - imageUrl: String - """ - ✨ `_expr` server value variant of `imageUrl` (✨ Generated from Field `Movie`.`imageUrl` of type `String!`) - """ - imageUrl_expr: String_Expr - """ - ✨ Generated from Field `Movie`.`rating` of type `Float` - """ - rating: Float - """ - ✨ Generated from Field `Movie`.`releaseYear` of type `Int` - """ - releaseYear: Int - """ - ✨ Generated from Field `Movie`.`tags` of type `[String]` - """ - tags: [String!] - """ - ✨ Generated from Field `Movie`.`title` of type `String!` - """ - title: String - """ - ✨ `_expr` server value variant of `title` (✨ Generated from Field `Movie`.`title` of type `String!`) - """ - title_expr: String_Expr -} -""" -✨ Generated filter input type for table 'Movie'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. -""" -input Movie_Filter { - """ - Apply multiple filter conditions using `AND` logic. - """ - _and: [Movie_Filter!] - """ - Negate the result of the provided filter condition. - """ - _not: Movie_Filter - """ - Apply multiple filter conditions using `OR` logic. - """ - _or: [Movie_Filter!] - """ - ✨ Generated from Field `Movie`.`id` of type `UUID!` - """ - id: UUID_Filter - """ - ✨ Generated from Field `Movie`.`description` of type `String` - """ - description: String_Filter - """ - ✨ Generated from Field `Movie`.`genre` of type `String` - """ - genre: String_Filter - """ - ✨ Generated from Field `Movie`.`imageUrl` of type `String!` - """ - imageUrl: String_Filter - """ - ✨ Generated from Field `Movie`.`rating` of type `Float` - """ - rating: Float_Filter - """ - ✨ Generated from Field `Movie`.`releaseYear` of type `Int` - """ - releaseYear: Int_Filter - """ - ✨ Generated from Field `Movie`.`tags` of type `[String]` - """ - tags: String_ListFilter - """ - ✨ Generated from Field `Movie`.`title` of type `String!` - """ - title: String_Filter - """ - ✨ Generated from Field `Movie`.`favorite_movies_on_movie` of type `[FavoriteMovie!]!` - """ - favorite_movies_on_movie: FavoriteMovie_ListFilter - """ - ✨ Generated from Field `Movie`.`movieActors_on_movie` of type `[MovieActor!]!` - """ - movieActors_on_movie: MovieActor_ListFilter - """ - ✨ Generated from Field `Movie`.`movieMetadatas_on_movie` of type `[MovieMetadata!]!` - """ - movieMetadatas_on_movie: MovieMetadata_ListFilter - """ - ✨ Generated from Field `Movie`.`reviews_on_movie` of type `[Review!]!` - """ - reviews_on_movie: Review_ListFilter - """ - ✨ Generated from Field `Movie`.`watched_movies_on_movie` of type `[WatchedMovie!]!` - """ - watched_movies_on_movie: WatchedMovie_ListFilter - """ - ✨ Generated from Field `Movie`.`actors_via_MovieActor` of type `[Actor!]!` - """ - actors_via_MovieActor: Actor_ListFilter - """ - ✨ Generated from Field `Movie`.`users_via_FavoriteMovie` of type `[User!]!` - """ - users_via_FavoriteMovie: User_ListFilter - """ - ✨ Generated from Field `Movie`.`users_via_Review` of type `[User!]!` - """ - users_via_Review: User_ListFilter - """ - ✨ Generated from Field `Movie`.`users_via_WatchedMovie` of type `[User!]!` - """ - users_via_WatchedMovie: User_ListFilter -} -""" -✨ Generated first-row input type for table 'Movie'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. -""" -input Movie_FirstRow { - """ - Order the result by the specified fields. - """ - orderBy: [Movie_Order!] - """ - Filters rows based on the specified conditions. - """ - where: Movie_Filter -} -""" -✨ Generated key input type for table 'Movie'. It represents the primary key fields used to uniquely identify a row in the table. -""" -input Movie_Key { - """ - ✨ Generated from Field `Movie`.`id` of type `UUID!` - """ - id: UUID - """ - ✨ `_expr` server value variant of `id` (✨ Generated from Field `Movie`.`id` of type `UUID!`) - """ - id_expr: UUID_Expr -} -""" -✨ Generated list filter input type for table 'Movie'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. -""" -input Movie_ListFilter { - """ - The desired number of objects that match the condition (defaults to at least one). - """ - count: Int_Filter = {gt:0} - """ - Condition of the related objects to filter for. - """ - exist: Movie_Filter -} -""" -✨ Generated order input type for table 'Movie'. This input defines the sorting order of rows in query results based on one or more fields. -""" -input Movie_Order { - """ - ✨ Generated from Field `Movie`.`id` of type `UUID!` - """ - id: OrderDirection - """ - ✨ Generated from Field `Movie`.`description` of type `String` - """ - description: OrderDirection - """ - ✨ Generated from Field `Movie`.`genre` of type `String` - """ - genre: OrderDirection - """ - ✨ Generated from Field `Movie`.`imageUrl` of type `String!` - """ - imageUrl: OrderDirection - """ - ✨ Generated from Field `Movie`.`rating` of type `Float` - """ - rating: OrderDirection - """ - ✨ Generated from Field `Movie`.`releaseYear` of type `Int` - """ - releaseYear: OrderDirection - """ - ✨ Generated from Field `Movie`.`title` of type `String!` - """ - title: OrderDirection -} -""" -✨ Generated data input type for table 'MovieActor'. It includes all necessary fields for creating or upserting rows into table. -""" -input MovieActor_Data { - """ - ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!` - """ - movieId: UUID - """ - ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `MovieActor`.`movieId` of type `UUID!`) - """ - movieId_expr: UUID_Expr - """ - ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!` - """ - actorId: UUID - """ - ✨ `_expr` server value variant of `actorId` (✨ Generated from Field `MovieActor`.`actorId` of type `UUID!`) - """ - actorId_expr: UUID_Expr - """ - ✨ Generated from Field `MovieActor`.`actor` of type `Actor!` - """ - actor: Actor_Key - """ - ✨ Generated from Field `MovieActor`.`movie` of type `Movie!` - """ - movie: Movie_Key - """ - ✨ Generated from Field `MovieActor`.`role` of type `String!` - """ - role: String - """ - ✨ `_expr` server value variant of `role` (✨ Generated from Field `MovieActor`.`role` of type `String!`) - """ - role_expr: String_Expr -} -""" -✨ Generated filter input type for table 'MovieActor'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. -""" -input MovieActor_Filter { - """ - Apply multiple filter conditions using `AND` logic. - """ - _and: [MovieActor_Filter!] - """ - Negate the result of the provided filter condition. - """ - _not: MovieActor_Filter - """ - Apply multiple filter conditions using `OR` logic. - """ - _or: [MovieActor_Filter!] - """ - ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!` - """ - movieId: UUID_Filter - """ - ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!` - """ - actorId: UUID_Filter - """ - ✨ Generated from Field `MovieActor`.`actor` of type `Actor!` - """ - actor: Actor_Filter - """ - ✨ Generated from Field `MovieActor`.`movie` of type `Movie!` - """ - movie: Movie_Filter - """ - ✨ Generated from Field `MovieActor`.`role` of type `String!` - """ - role: String_Filter -} -""" -✨ Generated first-row input type for table 'MovieActor'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. -""" -input MovieActor_FirstRow { - """ - Order the result by the specified fields. - """ - orderBy: [MovieActor_Order!] - """ - Filters rows based on the specified conditions. - """ - where: MovieActor_Filter -} -""" -✨ Generated key input type for table 'MovieActor'. It represents the primary key fields used to uniquely identify a row in the table. -""" -input MovieActor_Key { - """ - ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!` - """ - movieId: UUID - """ - ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `MovieActor`.`movieId` of type `UUID!`) - """ - movieId_expr: UUID_Expr - """ - ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!` - """ - actorId: UUID - """ - ✨ `_expr` server value variant of `actorId` (✨ Generated from Field `MovieActor`.`actorId` of type `UUID!`) - """ - actorId_expr: UUID_Expr -} -""" -✨ Generated list filter input type for table 'MovieActor'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. -""" -input MovieActor_ListFilter { - """ - The desired number of objects that match the condition (defaults to at least one). - """ - count: Int_Filter = {gt:0} - """ - Condition of the related objects to filter for. - """ - exist: MovieActor_Filter -} -""" -✨ Generated order input type for table 'MovieActor'. This input defines the sorting order of rows in query results based on one or more fields. -""" -input MovieActor_Order { - """ - ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!` - """ - movieId: OrderDirection - """ - ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!` - """ - actorId: OrderDirection - """ - ✨ Generated from Field `MovieActor`.`actor` of type `Actor!` - """ - actor: Actor_Order - """ - ✨ Generated from Field `MovieActor`.`movie` of type `Movie!` - """ - movie: Movie_Order - """ - ✨ Generated from Field `MovieActor`.`role` of type `String!` - """ - role: OrderDirection -} -""" -✨ Generated data input type for table 'MovieMetadata'. It includes all necessary fields for creating or upserting rows into table. -""" -input MovieMetadata_Data { - """ - ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!` - """ - id: UUID - """ - ✨ `_expr` server value variant of `id` (✨ Generated from Field `MovieMetadata`.`id` of type `UUID!`) - """ - id_expr: UUID_Expr - """ - ✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!` - """ - movieId: UUID - """ - ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!`) - """ - movieId_expr: UUID_Expr - """ - ✨ Generated from Field `MovieMetadata`.`movie` of type `Movie!` - """ - movie: Movie_Key - """ - ✨ Generated from Field `MovieMetadata`.`director` of type `String` - """ - director: String - """ - ✨ `_expr` server value variant of `director` (✨ Generated from Field `MovieMetadata`.`director` of type `String`) - """ - director_expr: String_Expr -} -""" -✨ Generated filter input type for table 'MovieMetadata'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. -""" -input MovieMetadata_Filter { - """ - Apply multiple filter conditions using `AND` logic. - """ - _and: [MovieMetadata_Filter!] - """ - Negate the result of the provided filter condition. - """ - _not: MovieMetadata_Filter - """ - Apply multiple filter conditions using `OR` logic. - """ - _or: [MovieMetadata_Filter!] - """ - ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!` - """ - id: UUID_Filter - """ - ✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!` - """ - movieId: UUID_Filter - """ - ✨ Generated from Field `MovieMetadata`.`movie` of type `Movie!` - """ - movie: Movie_Filter - """ - ✨ Generated from Field `MovieMetadata`.`director` of type `String` - """ - director: String_Filter -} -""" -✨ Generated first-row input type for table 'MovieMetadata'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. -""" -input MovieMetadata_FirstRow { - """ - Order the result by the specified fields. - """ - orderBy: [MovieMetadata_Order!] - """ - Filters rows based on the specified conditions. - """ - where: MovieMetadata_Filter -} -""" -✨ Generated key input type for table 'MovieMetadata'. It represents the primary key fields used to uniquely identify a row in the table. -""" -input MovieMetadata_Key { - """ - ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!` - """ - id: UUID - """ - ✨ `_expr` server value variant of `id` (✨ Generated from Field `MovieMetadata`.`id` of type `UUID!`) - """ - id_expr: UUID_Expr -} -""" -✨ Generated list filter input type for table 'MovieMetadata'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. -""" -input MovieMetadata_ListFilter { - """ - The desired number of objects that match the condition (defaults to at least one). - """ - count: Int_Filter = {gt:0} - """ - Condition of the related objects to filter for. - """ - exist: MovieMetadata_Filter -} -""" -✨ Generated order input type for table 'MovieMetadata'. This input defines the sorting order of rows in query results based on one or more fields. -""" -input MovieMetadata_Order { - """ - ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!` - """ - id: OrderDirection - """ - ✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!` - """ - movieId: OrderDirection - """ - ✨ Generated from Field `MovieMetadata`.`movie` of type `Movie!` - """ - movie: Movie_Order - """ - ✨ Generated from Field `MovieMetadata`.`director` of type `String` - """ - director: OrderDirection -} -""" -✨ Generated data input type for table 'Review'. It includes all necessary fields for creating or upserting rows into table. -""" -input Review_Data { - """ - ✨ Generated from Field `Review`.`movieId` of type `UUID!` - """ - movieId: UUID - """ - ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `Review`.`movieId` of type `UUID!`) - """ - movieId_expr: UUID_Expr - """ - ✨ Generated from Field `Review`.`userId` of type `String!` - """ - userId: String - """ - ✨ `_expr` server value variant of `userId` (✨ Generated from Field `Review`.`userId` of type `String!`) - """ - userId_expr: String_Expr - """ - ✨ Generated from Field `Review`.`movie` of type `Movie!` - """ - movie: Movie_Key - """ - ✨ Generated from Field `Review`.`user` of type `User!` - """ - user: User_Key - """ - ✨ Generated from Field `Review`.`id` of type `UUID!` - """ - id: UUID - """ - ✨ `_expr` server value variant of `id` (✨ Generated from Field `Review`.`id` of type `UUID!`) - """ - id_expr: UUID_Expr - """ - ✨ Generated from Field `Review`.`rating` of type `Int` - """ - rating: Int - """ - ✨ Generated from Field `Review`.`reviewDate` of type `Date!` - """ - reviewDate: Date - """ - ✨ `_date` server value variant of `reviewDate` (✨ Generated from Field `Review`.`reviewDate` of type `Date!`) - """ - reviewDate_date: Date_Relative - """ - ✨ `_expr` server value variant of `reviewDate` (✨ Generated from Field `Review`.`reviewDate` of type `Date!`) - """ - reviewDate_expr: Date_Expr - """ - ✨ Generated from Field `Review`.`reviewText` of type `String` - """ - reviewText: String - """ - ✨ `_expr` server value variant of `reviewText` (✨ Generated from Field `Review`.`reviewText` of type `String`) - """ - reviewText_expr: String_Expr -} -""" -✨ Generated filter input type for table 'Review'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. -""" -input Review_Filter { - """ - Apply multiple filter conditions using `AND` logic. - """ - _and: [Review_Filter!] - """ - Negate the result of the provided filter condition. - """ - _not: Review_Filter - """ - Apply multiple filter conditions using `OR` logic. - """ - _or: [Review_Filter!] - """ - ✨ Generated from Field `Review`.`movieId` of type `UUID!` - """ - movieId: UUID_Filter - """ - ✨ Generated from Field `Review`.`userId` of type `String!` - """ - userId: String_Filter - """ - ✨ Generated from Field `Review`.`movie` of type `Movie!` - """ - movie: Movie_Filter - """ - ✨ Generated from Field `Review`.`user` of type `User!` - """ - user: User_Filter - """ - ✨ Generated from Field `Review`.`id` of type `UUID!` - """ - id: UUID_Filter - """ - ✨ Generated from Field `Review`.`rating` of type `Int` - """ - rating: Int_Filter - """ - ✨ Generated from Field `Review`.`reviewDate` of type `Date!` - """ - reviewDate: Date_Filter - """ - ✨ Generated from Field `Review`.`reviewText` of type `String` - """ - reviewText: String_Filter -} -""" -✨ Generated first-row input type for table 'Review'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. -""" -input Review_FirstRow { - """ - Order the result by the specified fields. - """ - orderBy: [Review_Order!] - """ - Filters rows based on the specified conditions. - """ - where: Review_Filter -} -""" -✨ Generated key input type for table 'Review'. It represents the primary key fields used to uniquely identify a row in the table. -""" -input Review_Key { - """ - ✨ Generated from Field `Review`.`movieId` of type `UUID!` - """ - movieId: UUID - """ - ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `Review`.`movieId` of type `UUID!`) - """ - movieId_expr: UUID_Expr - """ - ✨ Generated from Field `Review`.`userId` of type `String!` - """ - userId: String - """ - ✨ `_expr` server value variant of `userId` (✨ Generated from Field `Review`.`userId` of type `String!`) - """ - userId_expr: String_Expr -} -""" -✨ Generated list filter input type for table 'Review'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. -""" -input Review_ListFilter { - """ - The desired number of objects that match the condition (defaults to at least one). - """ - count: Int_Filter = {gt:0} - """ - Condition of the related objects to filter for. - """ - exist: Review_Filter -} -""" -✨ Generated order input type for table 'Review'. This input defines the sorting order of rows in query results based on one or more fields. -""" -input Review_Order { - """ - ✨ Generated from Field `Review`.`movieId` of type `UUID!` - """ - movieId: OrderDirection - """ - ✨ Generated from Field `Review`.`userId` of type `String!` - """ - userId: OrderDirection - """ - ✨ Generated from Field `Review`.`movie` of type `Movie!` - """ - movie: Movie_Order - """ - ✨ Generated from Field `Review`.`user` of type `User!` - """ - user: User_Order - """ - ✨ Generated from Field `Review`.`id` of type `UUID!` - """ - id: OrderDirection - """ - ✨ Generated from Field `Review`.`rating` of type `Int` - """ - rating: OrderDirection - """ - ✨ Generated from Field `Review`.`reviewDate` of type `Date!` - """ - reviewDate: OrderDirection - """ - ✨ Generated from Field `Review`.`reviewText` of type `String` - """ - reviewText: OrderDirection -} -""" -✨ Generated data input type for table 'User'. It includes all necessary fields for creating or upserting rows into table. -""" -input User_Data { - """ - ✨ Generated from Field `User`.`id` of type `String!` - """ - id: String - """ - ✨ `_expr` server value variant of `id` (✨ Generated from Field `User`.`id` of type `String!`) - """ - id_expr: String_Expr - """ - ✨ Generated from Field `User`.`name` of type `String!` - """ - name: String - """ - ✨ `_expr` server value variant of `name` (✨ Generated from Field `User`.`name` of type `String!`) - """ - name_expr: String_Expr - """ - ✨ Generated from Field `User`.`username` of type `String!` - """ - username: String - """ - ✨ `_expr` server value variant of `username` (✨ Generated from Field `User`.`username` of type `String!`) - """ - username_expr: String_Expr -} -""" -✨ Generated filter input type for table 'User'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. -""" -input User_Filter { - """ - Apply multiple filter conditions using `AND` logic. - """ - _and: [User_Filter!] - """ - Negate the result of the provided filter condition. - """ - _not: User_Filter - """ - Apply multiple filter conditions using `OR` logic. - """ - _or: [User_Filter!] - """ - ✨ Generated from Field `User`.`id` of type `String!` - """ - id: String_Filter - """ - ✨ Generated from Field `User`.`name` of type `String!` - """ - name: String_Filter - """ - ✨ Generated from Field `User`.`username` of type `String!` - """ - username: String_Filter - """ - ✨ Generated from Field `User`.`favorite_actors_on_user` of type `[FavoriteActor!]!` - """ - favorite_actors_on_user: FavoriteActor_ListFilter - """ - ✨ Generated from Field `User`.`favorite_movies_on_user` of type `[FavoriteMovie!]!` - """ - favorite_movies_on_user: FavoriteMovie_ListFilter - """ - ✨ Generated from Field `User`.`reviews_on_user` of type `[Review!]!` - """ - reviews_on_user: Review_ListFilter - """ - ✨ Generated from Field `User`.`watched_movies_on_user` of type `[WatchedMovie!]!` - """ - watched_movies_on_user: WatchedMovie_ListFilter - """ - ✨ Generated from Field `User`.`actors_via_FavoriteActor` of type `[Actor!]!` - """ - actors_via_FavoriteActor: Actor_ListFilter - """ - ✨ Generated from Field `User`.`movies_via_FavoriteMovie` of type `[Movie!]!` - """ - movies_via_FavoriteMovie: Movie_ListFilter - """ - ✨ Generated from Field `User`.`movies_via_Review` of type `[Movie!]!` - """ - movies_via_Review: Movie_ListFilter - """ - ✨ Generated from Field `User`.`movies_via_WatchedMovie` of type `[Movie!]!` - """ - movies_via_WatchedMovie: Movie_ListFilter -} -""" -✨ Generated first-row input type for table 'User'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. -""" -input User_FirstRow { - """ - Order the result by the specified fields. - """ - orderBy: [User_Order!] - """ - Filters rows based on the specified conditions. - """ - where: User_Filter -} -""" -✨ Generated key input type for table 'User'. It represents the primary key fields used to uniquely identify a row in the table. -""" -input User_Key { - """ - ✨ Generated from Field `User`.`id` of type `String!` - """ - id: String - """ - ✨ `_expr` server value variant of `id` (✨ Generated from Field `User`.`id` of type `String!`) - """ - id_expr: String_Expr -} -""" -✨ Generated list filter input type for table 'User'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. -""" -input User_ListFilter { - """ - The desired number of objects that match the condition (defaults to at least one). - """ - count: Int_Filter = {gt:0} - """ - Condition of the related objects to filter for. - """ - exist: User_Filter -} -""" -✨ Generated order input type for table 'User'. This input defines the sorting order of rows in query results based on one or more fields. -""" -input User_Order { - """ - ✨ Generated from Field `User`.`id` of type `String!` - """ - id: OrderDirection - """ - ✨ Generated from Field `User`.`name` of type `String!` - """ - name: OrderDirection - """ - ✨ Generated from Field `User`.`username` of type `String!` - """ - username: OrderDirection -} -""" -✨ Generated data input type for table 'WatchedMovie'. It includes all necessary fields for creating or upserting rows into table. -""" -input WatchedMovie_Data { - """ - ✨ Generated from Field `WatchedMovie`.`userId` of type `String!` - """ - userId: String - """ - ✨ `_expr` server value variant of `userId` (✨ Generated from Field `WatchedMovie`.`userId` of type `String!`) - """ - userId_expr: String_Expr - """ - ✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!` - """ - movieId: UUID - """ - ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!`) - """ - movieId_expr: UUID_Expr - """ - ✨ Generated from Field `WatchedMovie`.`movie` of type `Movie!` - """ - movie: Movie_Key - """ - ✨ Generated from Field `WatchedMovie`.`user` of type `User!` - """ - user: User_Key -} -""" -✨ Generated filter input type for table 'WatchedMovie'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters. -""" -input WatchedMovie_Filter { - """ - Apply multiple filter conditions using `AND` logic. - """ - _and: [WatchedMovie_Filter!] - """ - Negate the result of the provided filter condition. - """ - _not: WatchedMovie_Filter - """ - Apply multiple filter conditions using `OR` logic. - """ - _or: [WatchedMovie_Filter!] - """ - ✨ Generated from Field `WatchedMovie`.`userId` of type `String!` - """ - userId: String_Filter - """ - ✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!` - """ - movieId: UUID_Filter - """ - ✨ Generated from Field `WatchedMovie`.`movie` of type `Movie!` - """ - movie: Movie_Filter - """ - ✨ Generated from Field `WatchedMovie`.`user` of type `User!` - """ - user: User_Filter -} -""" -✨ Generated first-row input type for table 'WatchedMovie'. This input selects the first row matching the filter criteria, ordered according to the specified conditions. -""" -input WatchedMovie_FirstRow { - """ - Order the result by the specified fields. - """ - orderBy: [WatchedMovie_Order!] - """ - Filters rows based on the specified conditions. - """ - where: WatchedMovie_Filter -} -""" -✨ Generated key input type for table 'WatchedMovie'. It represents the primary key fields used to uniquely identify a row in the table. -""" -input WatchedMovie_Key { - """ - ✨ Generated from Field `WatchedMovie`.`userId` of type `String!` - """ - userId: String - """ - ✨ `_expr` server value variant of `userId` (✨ Generated from Field `WatchedMovie`.`userId` of type `String!`) - """ - userId_expr: String_Expr - """ - ✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!` - """ - movieId: UUID - """ - ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!`) - """ - movieId_expr: UUID_Expr -} -""" -✨ Generated list filter input type for table 'WatchedMovie'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria. -""" -input WatchedMovie_ListFilter { - """ - The desired number of objects that match the condition (defaults to at least one). - """ - count: Int_Filter = {gt:0} - """ - Condition of the related objects to filter for. - """ - exist: WatchedMovie_Filter -} -""" -✨ Generated order input type for table 'WatchedMovie'. This input defines the sorting order of rows in query results based on one or more fields. -""" -input WatchedMovie_Order { - """ - ✨ Generated from Field `WatchedMovie`.`userId` of type `String!` - """ - userId: OrderDirection - """ - ✨ Generated from Field `WatchedMovie`.`movieId` of type `UUID!` - """ - movieId: OrderDirection - """ - ✨ Generated from Field `WatchedMovie`.`movie` of type `Movie!` - """ - movie: Movie_Order - """ - ✨ Generated from Field `WatchedMovie`.`user` of type `User!` - """ - user: User_Order -} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql deleted file mode 100644 index aacee812..00000000 --- a/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql +++ /dev/null @@ -1,970 +0,0 @@ -extend type Mutation { - """ - ✨ Insert a single `Actor` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - actor_insert( - """ - Data object to insert into the table. - """ - data: Actor_Data! - ): Actor_KeyOutput! @fdc_generated(from: "Actor", purpose: INSERT_SINGLE) - """ - ✨ Insert a single `FavoriteActor` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - favorite_actor_insert( - """ - Data object to insert into the table. - """ - data: FavoriteActor_Data! - ): FavoriteActor_KeyOutput! @fdc_generated(from: "FavoriteActor", purpose: INSERT_SINGLE) - """ - ✨ Insert a single `FavoriteMovie` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - favorite_movie_insert( - """ - Data object to insert into the table. - """ - data: FavoriteMovie_Data! - ): FavoriteMovie_KeyOutput! @fdc_generated(from: "FavoriteMovie", purpose: INSERT_SINGLE) - """ - ✨ Insert a single `Movie` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - movie_insert( - """ - Data object to insert into the table. - """ - data: Movie_Data! - ): Movie_KeyOutput! @fdc_generated(from: "Movie", purpose: INSERT_SINGLE) - """ - ✨ Insert a single `MovieActor` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - movieActor_insert( - """ - Data object to insert into the table. - """ - data: MovieActor_Data! - ): MovieActor_KeyOutput! @fdc_generated(from: "MovieActor", purpose: INSERT_SINGLE) - """ - ✨ Insert a single `MovieMetadata` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - movieMetadata_insert( - """ - Data object to insert into the table. - """ - data: MovieMetadata_Data! - ): MovieMetadata_KeyOutput! @fdc_generated(from: "MovieMetadata", purpose: INSERT_SINGLE) - """ - ✨ Insert a single `Review` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - review_insert( - """ - Data object to insert into the table. - """ - data: Review_Data! - ): Review_KeyOutput! @fdc_generated(from: "Review", purpose: INSERT_SINGLE) - """ - ✨ Insert a single `User` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - user_insert( - """ - Data object to insert into the table. - """ - data: User_Data! - ): User_KeyOutput! @fdc_generated(from: "User", purpose: INSERT_SINGLE) - """ - ✨ Insert a single `WatchedMovie` into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - watched_movie_insert( - """ - Data object to insert into the table. - """ - data: WatchedMovie_Data! - ): WatchedMovie_KeyOutput! @fdc_generated(from: "WatchedMovie", purpose: INSERT_SINGLE) - """ - ✨ Insert `Actor` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - actor_insertMany( - """ - List of data objects to insert into the table. - """ - data: [Actor_Data!]! - ): [Actor_KeyOutput!]! @fdc_generated(from: "Actor", purpose: INSERT_MULTIPLE) - """ - ✨ Insert `FavoriteActor` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - favorite_actor_insertMany( - """ - List of data objects to insert into the table. - """ - data: [FavoriteActor_Data!]! - ): [FavoriteActor_KeyOutput!]! @fdc_generated(from: "FavoriteActor", purpose: INSERT_MULTIPLE) - """ - ✨ Insert `FavoriteMovie` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - favorite_movie_insertMany( - """ - List of data objects to insert into the table. - """ - data: [FavoriteMovie_Data!]! - ): [FavoriteMovie_KeyOutput!]! @fdc_generated(from: "FavoriteMovie", purpose: INSERT_MULTIPLE) - """ - ✨ Insert `Movie` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - movie_insertMany( - """ - List of data objects to insert into the table. - """ - data: [Movie_Data!]! - ): [Movie_KeyOutput!]! @fdc_generated(from: "Movie", purpose: INSERT_MULTIPLE) - """ - ✨ Insert `MovieActor` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - movieActor_insertMany( - """ - List of data objects to insert into the table. - """ - data: [MovieActor_Data!]! - ): [MovieActor_KeyOutput!]! @fdc_generated(from: "MovieActor", purpose: INSERT_MULTIPLE) - """ - ✨ Insert `MovieMetadata` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - movieMetadata_insertMany( - """ - List of data objects to insert into the table. - """ - data: [MovieMetadata_Data!]! - ): [MovieMetadata_KeyOutput!]! @fdc_generated(from: "MovieMetadata", purpose: INSERT_MULTIPLE) - """ - ✨ Insert `Review` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - review_insertMany( - """ - List of data objects to insert into the table. - """ - data: [Review_Data!]! - ): [Review_KeyOutput!]! @fdc_generated(from: "Review", purpose: INSERT_MULTIPLE) - """ - ✨ Insert `User` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - user_insertMany( - """ - List of data objects to insert into the table. - """ - data: [User_Data!]! - ): [User_KeyOutput!]! @fdc_generated(from: "User", purpose: INSERT_MULTIPLE) - """ - ✨ Insert `WatchedMovie` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`). - """ - watched_movie_insertMany( - """ - List of data objects to insert into the table. - """ - data: [WatchedMovie_Data!]! - ): [WatchedMovie_KeyOutput!]! @fdc_generated(from: "WatchedMovie", purpose: INSERT_MULTIPLE) - """ - ✨ 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 object to insert or update if it already exists. - """ - data: Actor_Data! - ): Actor_KeyOutput! @fdc_generated(from: "Actor", purpose: UPSERT_SINGLE) - """ - ✨ Insert or update a single `FavoriteActor` into the table, based on the primary key. Returns the key of the newly inserted `FavoriteActor`. - """ - favorite_actor_upsert( - """ - Data object to insert or update if it already exists. - """ - data: FavoriteActor_Data! - ): FavoriteActor_KeyOutput! @fdc_generated(from: "FavoriteActor", purpose: UPSERT_SINGLE) - """ - ✨ Insert or update a single `FavoriteMovie` into the table, based on the primary key. Returns the key of the newly inserted `FavoriteMovie`. - """ - favorite_movie_upsert( - """ - Data object to insert or update if it already exists. - """ - data: FavoriteMovie_Data! - ): FavoriteMovie_KeyOutput! @fdc_generated(from: "FavoriteMovie", purpose: UPSERT_SINGLE) - """ - ✨ 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 object to insert or update if it already exists. - """ - data: Movie_Data! - ): Movie_KeyOutput! @fdc_generated(from: "Movie", purpose: UPSERT_SINGLE) - """ - ✨ 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 object to insert or update if it already exists. - """ - data: MovieActor_Data! - ): MovieActor_KeyOutput! @fdc_generated(from: "MovieActor", purpose: UPSERT_SINGLE) - """ - ✨ 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 object to insert or update if it already exists. - """ - data: MovieMetadata_Data! - ): MovieMetadata_KeyOutput! @fdc_generated(from: "MovieMetadata", purpose: UPSERT_SINGLE) - """ - ✨ 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 object to insert or update if it already exists. - """ - data: Review_Data! - ): Review_KeyOutput! @fdc_generated(from: "Review", purpose: UPSERT_SINGLE) - """ - ✨ 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 object to insert or update if it already exists. - """ - data: User_Data! - ): User_KeyOutput! @fdc_generated(from: "User", purpose: UPSERT_SINGLE) - """ - ✨ Insert or update a single `WatchedMovie` into the table, based on the primary key. Returns the key of the newly inserted `WatchedMovie`. - """ - watched_movie_upsert( - """ - Data object to insert or update if it already exists. - """ - data: WatchedMovie_Data! - ): WatchedMovie_KeyOutput! @fdc_generated(from: "WatchedMovie", purpose: UPSERT_SINGLE) - """ - ✨ Insert or update `Actor` objects into the table, based on the primary key. Returns the key of the newly inserted `Actor`. - """ - actor_upsertMany( - """ - List of data objects to insert or update if it already exists. - """ - data: [Actor_Data!]! - ): [Actor_KeyOutput!]! @fdc_generated(from: "Actor", purpose: UPSERT_MULTIPLE) - """ - ✨ Insert or update `FavoriteActor` objects into the table, based on the primary key. Returns the key of the newly inserted `FavoriteActor`. - """ - favorite_actor_upsertMany( - """ - List of data objects to insert or update if it already exists. - """ - data: [FavoriteActor_Data!]! - ): [FavoriteActor_KeyOutput!]! @fdc_generated(from: "FavoriteActor", purpose: UPSERT_MULTIPLE) - """ - ✨ Insert or update `FavoriteMovie` objects into the table, based on the primary key. Returns the key of the newly inserted `FavoriteMovie`. - """ - favorite_movie_upsertMany( - """ - List of data objects to insert or update if it already exists. - """ - data: [FavoriteMovie_Data!]! - ): [FavoriteMovie_KeyOutput!]! @fdc_generated(from: "FavoriteMovie", purpose: UPSERT_MULTIPLE) - """ - ✨ Insert or update `Movie` objects into the table, based on the primary key. Returns the key of the newly inserted `Movie`. - """ - movie_upsertMany( - """ - List of data objects to insert or update if it already exists. - """ - data: [Movie_Data!]! - ): [Movie_KeyOutput!]! @fdc_generated(from: "Movie", purpose: UPSERT_MULTIPLE) - """ - ✨ Insert or update `MovieActor` objects into the table, based on the primary key. Returns the key of the newly inserted `MovieActor`. - """ - movieActor_upsertMany( - """ - List of data objects to insert or update if it already exists. - """ - data: [MovieActor_Data!]! - ): [MovieActor_KeyOutput!]! @fdc_generated(from: "MovieActor", purpose: UPSERT_MULTIPLE) - """ - ✨ Insert or update `MovieMetadata` objects into the table, based on the primary key. Returns the key of the newly inserted `MovieMetadata`. - """ - movieMetadata_upsertMany( - """ - List of data objects to insert or update if it already exists. - """ - data: [MovieMetadata_Data!]! - ): [MovieMetadata_KeyOutput!]! @fdc_generated(from: "MovieMetadata", purpose: UPSERT_MULTIPLE) - """ - ✨ Insert or update `Review` objects into the table, based on the primary key. Returns the key of the newly inserted `Review`. - """ - review_upsertMany( - """ - List of data objects to insert or update if it already exists. - """ - data: [Review_Data!]! - ): [Review_KeyOutput!]! @fdc_generated(from: "Review", purpose: UPSERT_MULTIPLE) - """ - ✨ Insert or update `User` objects into the table, based on the primary key. Returns the key of the newly inserted `User`. - """ - user_upsertMany( - """ - List of data objects to insert or update if it already exists. - """ - data: [User_Data!]! - ): [User_KeyOutput!]! @fdc_generated(from: "User", purpose: UPSERT_MULTIPLE) - """ - ✨ Insert or update `WatchedMovie` objects into the table, based on the primary key. Returns the key of the newly inserted `WatchedMovie`. - """ - watched_movie_upsertMany( - """ - List of data objects to insert or update if it already exists. - """ - data: [WatchedMovie_Data!]! - ): [WatchedMovie_KeyOutput!]! @fdc_generated(from: "WatchedMovie", purpose: UPSERT_MULTIPLE) - """ - ✨ Update a single `Actor` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. - """ - actor_update( - """ - The unique ID of the object. - """ - id: UUID - - """ - The key used to identify the object. - """ - key: Actor_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: Actor_FirstRow - - """ - Data object containing fields to be updated. - """ - data: Actor_Data! - ): Actor_KeyOutput @fdc_generated(from: "Actor", purpose: UPDATE_SINGLE) - """ - ✨ Update a single `FavoriteActor` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. - """ - favorite_actor_update( - """ - The key used to identify the object. - """ - key: FavoriteActor_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: FavoriteActor_FirstRow - - """ - Data object containing fields to be updated. - """ - data: FavoriteActor_Data! - ): FavoriteActor_KeyOutput @fdc_generated(from: "FavoriteActor", purpose: UPDATE_SINGLE) - """ - ✨ Update a single `FavoriteMovie` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. - """ - favorite_movie_update( - """ - The key used to identify the object. - """ - key: FavoriteMovie_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: FavoriteMovie_FirstRow - - """ - Data object containing fields to be updated. - """ - data: FavoriteMovie_Data! - ): FavoriteMovie_KeyOutput @fdc_generated(from: "FavoriteMovie", purpose: UPDATE_SINGLE) - """ - ✨ Update a single `Movie` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. - """ - movie_update( - """ - The unique ID of the object. - """ - id: UUID - - """ - The key used to identify the object. - """ - key: Movie_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: Movie_FirstRow - - """ - Data object containing fields to be updated. - """ - data: Movie_Data! - ): Movie_KeyOutput @fdc_generated(from: "Movie", purpose: UPDATE_SINGLE) - """ - ✨ Update a single `MovieActor` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. - """ - movieActor_update( - """ - The key used to identify the object. - """ - key: MovieActor_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: MovieActor_FirstRow - - """ - Data object containing fields to be updated. - """ - data: MovieActor_Data! - ): MovieActor_KeyOutput @fdc_generated(from: "MovieActor", purpose: UPDATE_SINGLE) - """ - ✨ Update a single `MovieMetadata` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. - """ - movieMetadata_update( - """ - The unique ID of the object. - """ - id: UUID - - """ - The key used to identify the object. - """ - key: MovieMetadata_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: MovieMetadata_FirstRow - - """ - Data object containing fields to be updated. - """ - data: MovieMetadata_Data! - ): MovieMetadata_KeyOutput @fdc_generated(from: "MovieMetadata", purpose: UPDATE_SINGLE) - """ - ✨ Update a single `Review` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. - """ - review_update( - """ - The key used to identify the object. - """ - key: Review_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: Review_FirstRow - - """ - Data object containing fields to be updated. - """ - data: Review_Data! - ): Review_KeyOutput @fdc_generated(from: "Review", purpose: UPDATE_SINGLE) - """ - ✨ Update a single `User` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. - """ - user_update( - """ - The unique ID of the object. - """ - id: String - - """ - ✨ `_expr` server value variant of `id` (The unique ID of the object.) - """ - id_expr: String_Expr - - """ - The key used to identify the object. - """ - key: User_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: User_FirstRow - - """ - Data object containing fields to be updated. - """ - data: User_Data! - ): User_KeyOutput @fdc_generated(from: "User", purpose: UPDATE_SINGLE) - """ - ✨ Update a single `WatchedMovie` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found. - """ - watched_movie_update( - """ - The key used to identify the object. - """ - key: WatchedMovie_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: WatchedMovie_FirstRow - - """ - Data object containing fields to be updated. - """ - data: WatchedMovie_Data! - ): WatchedMovie_KeyOutput @fdc_generated(from: "WatchedMovie", purpose: UPDATE_SINGLE) - """ - ✨ Update `Actor` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. - """ - actor_updateMany( - """ - Filter condition to specify which rows to update. - """ - where: Actor_Filter - - """ - Set to true to update all rows. - """ - all: Boolean = false - - """ - Data object containing fields to update. - """ - data: Actor_Data! - ): Int! @fdc_generated(from: "Actor", purpose: UPDATE_MULTIPLE) - """ - ✨ Update `FavoriteActor` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. - """ - favorite_actor_updateMany( - """ - Filter condition to specify which rows to update. - """ - where: FavoriteActor_Filter - - """ - Set to true to update all rows. - """ - all: Boolean = false - - """ - Data object containing fields to update. - """ - data: FavoriteActor_Data! - ): Int! @fdc_generated(from: "FavoriteActor", purpose: UPDATE_MULTIPLE) - """ - ✨ Update `FavoriteMovie` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. - """ - favorite_movie_updateMany( - """ - Filter condition to specify which rows to update. - """ - where: FavoriteMovie_Filter - - """ - Set to true to update all rows. - """ - all: Boolean = false - - """ - Data object containing fields to update. - """ - data: FavoriteMovie_Data! - ): Int! @fdc_generated(from: "FavoriteMovie", purpose: UPDATE_MULTIPLE) - """ - ✨ Update `Movie` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. - """ - movie_updateMany( - """ - Filter condition to specify which rows to update. - """ - where: Movie_Filter - - """ - Set to true to update all rows. - """ - all: Boolean = false - - """ - Data object containing fields to update. - """ - data: Movie_Data! - ): Int! @fdc_generated(from: "Movie", purpose: UPDATE_MULTIPLE) - """ - ✨ Update `MovieActor` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. - """ - movieActor_updateMany( - """ - Filter condition to specify which rows to update. - """ - where: MovieActor_Filter - - """ - Set to true to update all rows. - """ - all: Boolean = false - - """ - Data object containing fields to update. - """ - data: MovieActor_Data! - ): Int! @fdc_generated(from: "MovieActor", purpose: UPDATE_MULTIPLE) - """ - ✨ Update `MovieMetadata` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. - """ - movieMetadata_updateMany( - """ - Filter condition to specify which rows to update. - """ - where: MovieMetadata_Filter - - """ - Set to true to update all rows. - """ - all: Boolean = false - - """ - Data object containing fields to update. - """ - data: MovieMetadata_Data! - ): Int! @fdc_generated(from: "MovieMetadata", purpose: UPDATE_MULTIPLE) - """ - ✨ Update `Review` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. - """ - review_updateMany( - """ - Filter condition to specify which rows to update. - """ - where: Review_Filter - - """ - Set to true to update all rows. - """ - all: Boolean = false - - """ - Data object containing fields to update. - """ - data: Review_Data! - ): Int! @fdc_generated(from: "Review", purpose: UPDATE_MULTIPLE) - """ - ✨ Update `User` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. - """ - user_updateMany( - """ - Filter condition to specify which rows to update. - """ - where: User_Filter - - """ - Set to true to update all rows. - """ - all: Boolean = false - - """ - Data object containing fields to update. - """ - data: User_Data! - ): Int! @fdc_generated(from: "User", purpose: UPDATE_MULTIPLE) - """ - ✨ Update `WatchedMovie` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated. - """ - watched_movie_updateMany( - """ - Filter condition to specify which rows to update. - """ - where: WatchedMovie_Filter - - """ - Set to true to update all rows. - """ - all: Boolean = false - - """ - Data object containing fields to update. - """ - data: WatchedMovie_Data! - ): Int! @fdc_generated(from: "WatchedMovie", purpose: UPDATE_MULTIPLE) - """ - ✨ Delete a single `Actor` based on `id`, `key` or `first` and return its key (or `null` if not found). - """ - actor_delete( - """ - The unique ID of the object. - """ - id: UUID - - """ - The key used to identify the object. - """ - key: Actor_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: Actor_FirstRow - ): Actor_KeyOutput @fdc_generated(from: "Actor", purpose: DELETE_SINGLE) - """ - ✨ Delete a single `FavoriteActor` based on `id`, `key` or `first` and return its key (or `null` if not found). - """ - favorite_actor_delete( - """ - The key used to identify the object. - """ - key: FavoriteActor_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: FavoriteActor_FirstRow - ): FavoriteActor_KeyOutput @fdc_generated(from: "FavoriteActor", purpose: DELETE_SINGLE) - """ - ✨ Delete a single `FavoriteMovie` based on `id`, `key` or `first` and return its key (or `null` if not found). - """ - favorite_movie_delete( - """ - The key used to identify the object. - """ - key: FavoriteMovie_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: FavoriteMovie_FirstRow - ): FavoriteMovie_KeyOutput @fdc_generated(from: "FavoriteMovie", purpose: DELETE_SINGLE) - """ - ✨ Delete a single `Movie` based on `id`, `key` or `first` and return its key (or `null` if not found). - """ - movie_delete( - """ - The unique ID of the object. - """ - id: UUID - - """ - The key used to identify the object. - """ - key: Movie_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: Movie_FirstRow - ): Movie_KeyOutput @fdc_generated(from: "Movie", purpose: DELETE_SINGLE) - """ - ✨ Delete a single `MovieActor` based on `id`, `key` or `first` and return its key (or `null` if not found). - """ - movieActor_delete( - """ - The key used to identify the object. - """ - key: MovieActor_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: MovieActor_FirstRow - ): MovieActor_KeyOutput @fdc_generated(from: "MovieActor", purpose: DELETE_SINGLE) - """ - ✨ Delete a single `MovieMetadata` based on `id`, `key` or `first` and return its key (or `null` if not found). - """ - movieMetadata_delete( - """ - The unique ID of the object. - """ - id: UUID - - """ - The key used to identify the object. - """ - key: MovieMetadata_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: MovieMetadata_FirstRow - ): MovieMetadata_KeyOutput @fdc_generated(from: "MovieMetadata", purpose: DELETE_SINGLE) - """ - ✨ Delete a single `Review` based on `id`, `key` or `first` and return its key (or `null` if not found). - """ - review_delete( - """ - The key used to identify the object. - """ - key: Review_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: Review_FirstRow - ): Review_KeyOutput @fdc_generated(from: "Review", purpose: DELETE_SINGLE) - """ - ✨ Delete a single `User` based on `id`, `key` or `first` and return its key (or `null` if not found). - """ - user_delete( - """ - The unique ID of the object. - """ - id: String - - """ - ✨ `_expr` server value variant of `id` (The unique ID of the object.) - """ - id_expr: String_Expr - - """ - The key used to identify the object. - """ - key: User_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: User_FirstRow - ): User_KeyOutput @fdc_generated(from: "User", purpose: DELETE_SINGLE) - """ - ✨ Delete a single `WatchedMovie` based on `id`, `key` or `first` and return its key (or `null` if not found). - """ - watched_movie_delete( - """ - The key used to identify the object. - """ - key: WatchedMovie_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: WatchedMovie_FirstRow - ): WatchedMovie_KeyOutput @fdc_generated(from: "WatchedMovie", purpose: DELETE_SINGLE) - """ - ✨ Delete `Actor` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. - """ - actor_deleteMany( - """ - Filter condition to specify which rows to delete. - """ - where: Actor_Filter - - """ - Set to true to delete all rows. - """ - all: Boolean = false - ): Int! @fdc_generated(from: "Actor", purpose: DELETE_MULTIPLE) - """ - ✨ Delete `FavoriteActor` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. - """ - favorite_actor_deleteMany( - """ - Filter condition to specify which rows to delete. - """ - where: FavoriteActor_Filter - - """ - Set to true to delete all rows. - """ - all: Boolean = false - ): Int! @fdc_generated(from: "FavoriteActor", purpose: DELETE_MULTIPLE) - """ - ✨ Delete `FavoriteMovie` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. - """ - favorite_movie_deleteMany( - """ - Filter condition to specify which rows to delete. - """ - where: FavoriteMovie_Filter - - """ - Set to true to delete all rows. - """ - all: Boolean = false - ): Int! @fdc_generated(from: "FavoriteMovie", purpose: DELETE_MULTIPLE) - """ - ✨ Delete `Movie` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. - """ - movie_deleteMany( - """ - Filter condition to specify which rows to delete. - """ - where: Movie_Filter - - """ - Set to true to delete all rows. - """ - all: Boolean = false - ): Int! @fdc_generated(from: "Movie", purpose: DELETE_MULTIPLE) - """ - ✨ Delete `MovieActor` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. - """ - movieActor_deleteMany( - """ - Filter condition to specify which rows to delete. - """ - where: MovieActor_Filter - - """ - Set to true to delete all rows. - """ - all: Boolean = false - ): Int! @fdc_generated(from: "MovieActor", purpose: DELETE_MULTIPLE) - """ - ✨ Delete `MovieMetadata` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. - """ - movieMetadata_deleteMany( - """ - Filter condition to specify which rows to delete. - """ - where: MovieMetadata_Filter - - """ - Set to true to delete all rows. - """ - all: Boolean = false - ): Int! @fdc_generated(from: "MovieMetadata", purpose: DELETE_MULTIPLE) - """ - ✨ Delete `Review` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. - """ - review_deleteMany( - """ - Filter condition to specify which rows to delete. - """ - where: Review_Filter - - """ - Set to true to delete all rows. - """ - all: Boolean = false - ): Int! @fdc_generated(from: "Review", purpose: DELETE_MULTIPLE) - """ - ✨ Delete `User` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. - """ - user_deleteMany( - """ - Filter condition to specify which rows to delete. - """ - where: User_Filter - - """ - Set to true to delete all rows. - """ - all: Boolean = false - ): Int! @fdc_generated(from: "User", purpose: DELETE_MULTIPLE) - """ - ✨ Delete `WatchedMovie` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted. - """ - watched_movie_deleteMany( - """ - Filter condition to specify which rows to delete. - """ - where: WatchedMovie_Filter - - """ - Set to true to delete all rows. - """ - all: Boolean = false - ): Int! @fdc_generated(from: "WatchedMovie", purpose: DELETE_MULTIPLE) -} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/query.gql b/dataconnect/dataconnect/.dataconnect/schema/main/query.gql deleted file mode 100644 index ed0a411d..00000000 --- a/dataconnect/dataconnect/.dataconnect/schema/main/query.gql +++ /dev/null @@ -1,393 +0,0 @@ -extend type Query { - """ - ✨ Look up a single `Actor` based on `id`, `key` or `first` and return selected fields (or `null` if not found). - """ - actor( - """ - The unique ID of the object. - """ - id: UUID - - """ - The key used to identify the object. - """ - key: Actor_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: Actor_FirstRow - ): Actor @fdc_generated(from: "Actor", purpose: QUERY_SINGLE) - """ - ✨ Look up a single `FavoriteActor` based on `id`, `key` or `first` and return selected fields (or `null` if not found). - """ - favorite_actor( - """ - The key used to identify the object. - """ - key: FavoriteActor_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: FavoriteActor_FirstRow - ): FavoriteActor @fdc_generated(from: "FavoriteActor", purpose: QUERY_SINGLE) - """ - ✨ Look up a single `FavoriteMovie` based on `id`, `key` or `first` and return selected fields (or `null` if not found). - """ - favorite_movie( - """ - The key used to identify the object. - """ - key: FavoriteMovie_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: FavoriteMovie_FirstRow - ): FavoriteMovie @fdc_generated(from: "FavoriteMovie", purpose: QUERY_SINGLE) - """ - ✨ Look up a single `Movie` based on `id`, `key` or `first` and return selected fields (or `null` if not found). - """ - movie( - """ - The unique ID of the object. - """ - id: UUID - - """ - The key used to identify the object. - """ - key: Movie_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: Movie_FirstRow - ): Movie @fdc_generated(from: "Movie", purpose: QUERY_SINGLE) - """ - ✨ Look up a single `MovieActor` based on `id`, `key` or `first` and return selected fields (or `null` if not found). - """ - movieActor( - """ - The key used to identify the object. - """ - key: MovieActor_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: MovieActor_FirstRow - ): MovieActor @fdc_generated(from: "MovieActor", purpose: QUERY_SINGLE) - """ - ✨ Look up a single `MovieMetadata` based on `id`, `key` or `first` and return selected fields (or `null` if not found). - """ - movieMetadata( - """ - The unique ID of the object. - """ - id: UUID - - """ - The key used to identify the object. - """ - key: MovieMetadata_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: MovieMetadata_FirstRow - ): MovieMetadata @fdc_generated(from: "MovieMetadata", purpose: QUERY_SINGLE) - """ - ✨ Look up a single `Review` based on `id`, `key` or `first` and return selected fields (or `null` if not found). - """ - review( - """ - The key used to identify the object. - """ - key: Review_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: Review_FirstRow - ): Review @fdc_generated(from: "Review", purpose: QUERY_SINGLE) - """ - ✨ Look up a single `User` based on `id`, `key` or `first` and return selected fields (or `null` if not found). - """ - user( - """ - The unique ID of the object. - """ - id: String - - """ - ✨ `_expr` server value variant of `id` (The unique ID of the object.) - """ - id_expr: String_Expr - - """ - The key used to identify the object. - """ - key: User_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: User_FirstRow - ): User @fdc_generated(from: "User", purpose: QUERY_SINGLE) - """ - ✨ Look up a single `WatchedMovie` based on `id`, `key` or `first` and return selected fields (or `null` if not found). - """ - watched_movie( - """ - The key used to identify the object. - """ - key: WatchedMovie_Key - - """ - Fetch the first row based on the filters and ordering. - """ - first: WatchedMovie_FirstRow - ): WatchedMovie @fdc_generated(from: "WatchedMovie", purpose: QUERY_SINGLE) - """ - ✨ List `Actor` objects in the table, optionally filtered by `where` conditions. - """ - actors( - """ - Filter condition to narrow down the query results. - """ - where: Actor_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [Actor_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Actor!]! @fdc_generated(from: "Actor", purpose: QUERY_MULTIPLE) - """ - ✨ List `FavoriteActor` objects in the table, optionally filtered by `where` conditions. - """ - favorite_actors( - """ - Filter condition to narrow down the query results. - """ - where: FavoriteActor_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [FavoriteActor_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [FavoriteActor!]! @fdc_generated(from: "FavoriteActor", purpose: QUERY_MULTIPLE) - """ - ✨ List `FavoriteMovie` objects in the table, optionally filtered by `where` conditions. - """ - favorite_movies( - """ - Filter condition to narrow down the query results. - """ - where: FavoriteMovie_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [FavoriteMovie_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [FavoriteMovie!]! @fdc_generated(from: "FavoriteMovie", purpose: QUERY_MULTIPLE) - """ - ✨ List `Genre` objects in the table, optionally filtered by `where` conditions. - """ - genres( - """ - Filter condition to narrow down the query results. - """ - where: Genre_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [Genre_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Genre!]! @fdc_generated(from: "Genre", purpose: QUERY_MULTIPLE) - """ - ✨ List `Movie` objects in the table, optionally filtered by `where` conditions. - """ - movies( - """ - Filter condition to narrow down the query results. - """ - where: Movie_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [Movie_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Movie!]! @fdc_generated(from: "Movie", purpose: QUERY_MULTIPLE) - """ - ✨ List `MovieActor` objects in the table, optionally filtered by `where` conditions. - """ - movieActors( - """ - Filter condition to narrow down the query results. - """ - where: MovieActor_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [MovieActor_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [MovieActor!]! @fdc_generated(from: "MovieActor", purpose: QUERY_MULTIPLE) - """ - ✨ List `MovieMetadata` objects in the table, optionally filtered by `where` conditions. - """ - movieMetadatas( - """ - Filter condition to narrow down the query results. - """ - where: MovieMetadata_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [MovieMetadata_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [MovieMetadata!]! @fdc_generated(from: "MovieMetadata", purpose: QUERY_MULTIPLE) - """ - ✨ List `Review` objects in the table, optionally filtered by `where` conditions. - """ - reviews( - """ - Filter condition to narrow down the query results. - """ - where: Review_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [Review_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Review!]! @fdc_generated(from: "Review", purpose: QUERY_MULTIPLE) - """ - ✨ List `User` objects in the table, optionally filtered by `where` conditions. - """ - users( - """ - Filter condition to narrow down the query results. - """ - where: User_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [User_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [User!]! @fdc_generated(from: "User", purpose: QUERY_MULTIPLE) - """ - ✨ List `WatchedMovie` objects in the table, optionally filtered by `where` conditions. - """ - watched_movies( - """ - Filter condition to narrow down the query results. - """ - where: WatchedMovie_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [WatchedMovie_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [WatchedMovie!]! @fdc_generated(from: "WatchedMovie", purpose: QUERY_MULTIPLE) -} diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql deleted file mode 100644 index 9f73ee86..00000000 --- a/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql +++ /dev/null @@ -1,510 +0,0 @@ -extend type Actor { - """ - ✨ List `FavoriteActor` objects in a one-to-many relationship (where `FavoriteActor`.`actor` is this object). - """ - favorite_actors_on_actor( - """ - Filter condition to narrow down the query results. - """ - where: FavoriteActor_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [FavoriteActor_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [FavoriteActor!]! @fdc_generated(from: "FavoriteActor.actor", purpose: QUERY_MULTIPLE_ONE_TO_MANY) - """ - ✨ List `MovieActor` objects in a one-to-many relationship (where `MovieActor`.`actor` is this object). - """ - movieActors_on_actor( - """ - Filter condition to narrow down the query results. - """ - where: MovieActor_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [MovieActor_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [MovieActor!]! @fdc_generated(from: "MovieActor.actor", purpose: QUERY_MULTIPLE_ONE_TO_MANY) - """ - ✨ List `Movie` objects using `MovieActor` as the join table (a `MovieActor` object exists where its `actor` is this and its `movie` is that). - """ - movies_via_MovieActor( - """ - Filter condition to narrow down the query results. - """ - where: MovieActor_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [MovieActor_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Movie!]! @fdc_generated(from: "MovieActor", purpose: QUERY_MULTIPLE_MANY_TO_MANY) - """ - ✨ List `User` objects using `FavoriteActor` as the join table (a `FavoriteActor` object exists where its `actor` is this and its `user` is that). - """ - users_via_FavoriteActor( - """ - Filter condition to narrow down the query results. - """ - where: FavoriteActor_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [FavoriteActor_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [User!]! @fdc_generated(from: "FavoriteActor", purpose: QUERY_MULTIPLE_MANY_TO_MANY) -} -extend type Movie { - """ - ✨ List `FavoriteMovie` objects in a one-to-many relationship (where `FavoriteMovie`.`movie` is this object). - """ - favorite_movies_on_movie( - """ - Filter condition to narrow down the query results. - """ - where: FavoriteMovie_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [FavoriteMovie_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [FavoriteMovie!]! @fdc_generated(from: "FavoriteMovie.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY) - """ - ✨ List `MovieActor` objects in a one-to-many relationship (where `MovieActor`.`movie` is this object). - """ - movieActors_on_movie( - """ - Filter condition to narrow down the query results. - """ - where: MovieActor_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [MovieActor_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [MovieActor!]! @fdc_generated(from: "MovieActor.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY) - """ - ✨ List `MovieMetadata` objects in a one-to-many relationship (where `MovieMetadata`.`movie` is this object). - """ - movieMetadatas_on_movie( - """ - Filter condition to narrow down the query results. - """ - where: MovieMetadata_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [MovieMetadata_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [MovieMetadata!]! @fdc_generated(from: "MovieMetadata.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY) - """ - ✨ List `Review` objects in a one-to-many relationship (where `Review`.`movie` is this object). - """ - reviews_on_movie( - """ - Filter condition to narrow down the query results. - """ - where: Review_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [Review_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Review!]! @fdc_generated(from: "Review.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY) - """ - ✨ List `WatchedMovie` objects in a one-to-many relationship (where `WatchedMovie`.`movie` is this object). - """ - watched_movies_on_movie( - """ - Filter condition to narrow down the query results. - """ - where: WatchedMovie_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [WatchedMovie_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [WatchedMovie!]! @fdc_generated(from: "WatchedMovie.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY) - """ - ✨ List `Actor` objects using `MovieActor` as the join table (a `MovieActor` object exists where its `movie` is this and its `actor` is that). - """ - actors_via_MovieActor( - """ - Filter condition to narrow down the query results. - """ - where: MovieActor_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [MovieActor_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Actor!]! @fdc_generated(from: "MovieActor", purpose: QUERY_MULTIPLE_MANY_TO_MANY) - """ - ✨ List `User` objects using `FavoriteMovie` as the join table (a `FavoriteMovie` object exists where its `movie` is this and its `user` is that). - """ - users_via_FavoriteMovie( - """ - Filter condition to narrow down the query results. - """ - where: FavoriteMovie_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [FavoriteMovie_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [User!]! @fdc_generated(from: "FavoriteMovie", purpose: QUERY_MULTIPLE_MANY_TO_MANY) - """ - ✨ List `User` objects using `Review` as the join table (a `Review` object exists where its `movie` is this and its `user` is that). - """ - users_via_Review( - """ - Filter condition to narrow down the query results. - """ - where: Review_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [Review_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [User!]! @fdc_generated(from: "Review", purpose: QUERY_MULTIPLE_MANY_TO_MANY) - """ - ✨ List `User` objects using `WatchedMovie` as the join table (a `WatchedMovie` object exists where its `movie` is this and its `user` is that). - """ - users_via_WatchedMovie( - """ - Filter condition to narrow down the query results. - """ - where: WatchedMovie_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [WatchedMovie_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [User!]! @fdc_generated(from: "WatchedMovie", purpose: QUERY_MULTIPLE_MANY_TO_MANY) -} -extend type User { - """ - ✨ List `FavoriteActor` objects in a one-to-many relationship (where `FavoriteActor`.`user` is this object). - """ - favorite_actors_on_user( - """ - Filter condition to narrow down the query results. - """ - where: FavoriteActor_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [FavoriteActor_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [FavoriteActor!]! @fdc_generated(from: "FavoriteActor.user", purpose: QUERY_MULTIPLE_ONE_TO_MANY) - """ - ✨ List `FavoriteMovie` objects in a one-to-many relationship (where `FavoriteMovie`.`user` is this object). - """ - favorite_movies_on_user( - """ - Filter condition to narrow down the query results. - """ - where: FavoriteMovie_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [FavoriteMovie_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [FavoriteMovie!]! @fdc_generated(from: "FavoriteMovie.user", purpose: QUERY_MULTIPLE_ONE_TO_MANY) - """ - ✨ List `Review` objects in a one-to-many relationship (where `Review`.`user` is this object). - """ - reviews_on_user( - """ - Filter condition to narrow down the query results. - """ - where: Review_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [Review_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Review!]! @fdc_generated(from: "Review.user", purpose: QUERY_MULTIPLE_ONE_TO_MANY) - """ - ✨ List `WatchedMovie` objects in a one-to-many relationship (where `WatchedMovie`.`user` is this object). - """ - watched_movies_on_user( - """ - Filter condition to narrow down the query results. - """ - where: WatchedMovie_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [WatchedMovie_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [WatchedMovie!]! @fdc_generated(from: "WatchedMovie.user", purpose: QUERY_MULTIPLE_ONE_TO_MANY) - """ - ✨ List `Actor` objects using `FavoriteActor` as the join table (a `FavoriteActor` object exists where its `user` is this and its `actor` is that). - """ - actors_via_FavoriteActor( - """ - Filter condition to narrow down the query results. - """ - where: FavoriteActor_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [FavoriteActor_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Actor!]! @fdc_generated(from: "FavoriteActor", purpose: QUERY_MULTIPLE_MANY_TO_MANY) - """ - ✨ List `Movie` objects using `FavoriteMovie` as the join table (a `FavoriteMovie` object exists where its `user` is this and its `movie` is that). - """ - movies_via_FavoriteMovie( - """ - Filter condition to narrow down the query results. - """ - where: FavoriteMovie_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [FavoriteMovie_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Movie!]! @fdc_generated(from: "FavoriteMovie", purpose: QUERY_MULTIPLE_MANY_TO_MANY) - """ - ✨ List `Movie` objects using `Review` as the join table (a `Review` object exists where its `user` is this and its `movie` is that). - """ - movies_via_Review( - """ - Filter condition to narrow down the query results. - """ - where: Review_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [Review_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Movie!]! @fdc_generated(from: "Review", purpose: QUERY_MULTIPLE_MANY_TO_MANY) - """ - ✨ List `Movie` objects using `WatchedMovie` as the join table (a `WatchedMovie` object exists where its `user` is this and its `movie` is that). - """ - movies_via_WatchedMovie( - """ - Filter condition to narrow down the query results. - """ - where: WatchedMovie_Filter - - """ - Order the query results by specific fields. - """ - orderBy: [WatchedMovie_Order!] - - """ - Number of rows to skip before starting to return the results. - """ - offset: Int - - """ - Maximum number of rows to return (defaults to 100 rows). - """ - limit: Int = 100 - ): [Movie!]! @fdc_generated(from: "WatchedMovie", purpose: QUERY_MULTIPLE_MANY_TO_MANY) -} diff --git a/dataconnect/dataconnect/.dataconnect/schema/prelude.gql b/dataconnect/dataconnect/.dataconnect/schema/prelude.gql deleted file mode 100644 index 7fac870c..00000000 --- a/dataconnect/dataconnect/.dataconnect/schema/prelude.gql +++ /dev/null @@ -1,2026 +0,0 @@ -"AccessLevel specifies coarse access policies for common situations." -enum AccessLevel { - """ - This operation is accessible to anyone, with or without authentication. - Equivalent to: `@auth(expr: "true")` - """ - PUBLIC - - """ - This operation can be executed only with a valid Firebase Auth ID token. - **Note:** This access level allows anonymous and unverified accounts, - which may present security and abuse risks. - Equivalent to: `@auth(expr: "auth.uid != nil")` - """ - USER_ANON - - """ - This operation is restricted to non-anonymous Firebase Auth accounts. - Equivalent to: `@auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")` - """ - USER - - """ - This operation is restricted to Firebase Auth accounts with verified email addresses. - Equivalent to: `@auth(expr: "auth.uid != nil && auth.token.email_verified")` - """ - USER_EMAIL_VERIFIED - - """ - This operation cannot be executed by anyone. The operation can only be performed - by using the Admin SDK from a privileged environment. - Equivalent to: `@auth(expr: "false")` - """ - NO_ACCESS -} - -""" -The `@auth` directive defines the authentication policy for a query or mutation. - -It must be added to any operation that you wish to be accessible from a client -application. If not specified, the operation defaults to `@auth(level: NO_ACCESS)`. - -Refer to [Data Connect Auth Guide](https://firebase.google.com/docs/data-connect/authorization-and-security) for the best practices. -""" -directive @auth( - """ - The minimal level of access required to perform this operation. - Exactly one of `level` and `expr` should be specified. - """ - level: AccessLevel @fdc_oneOf(required: true) - """ - A CEL expression that grants access to this operation if the expression - evaluates to `true`. - Exactly one of `level` and `expr` should be specified. - """ - expr: Boolean_Expr @fdc_oneOf(required: true) -) on QUERY | MUTATION - - -""" -Require that this mutation always run in a DB transaction. - -Mutations with `@transaction` are guaranteed to either fully succeed or fully -fail. If any of the fields within the transaction fails, the entire transaction -is rolled back. From a client standpoint, any failure behaves as if the entire -request had failed with a request error and execution had not begun. - -Mutations without `@transaction` would execute each root field one after -another in sequence. It surfaces any errors as partial [field errors](https://spec.graphql.org/October2021/#sec-Errors.Field-errors), -but not impacts the subsequent executions. - -The `@transaction` directive cannot be added to queries for now. -Currently, queries cannot fail partially, the response data is not guaranteed -to be a consistent snapshot. -""" -directive @transaction on MUTATION - -"Query filter criteria for `String` scalar fields." -input String_Filter { - "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." - isNull: Boolean - "Match if field is exactly equal to provided value." - eq: String @fdc_oneOf(group: "eq") - """ - Match if field is exactly equal to the result of the provided server value - expression. Currently only `auth.uid` is supported as an expression. - """ - eq_expr: String_Expr @fdc_oneOf(group: "eq") - "Match if field is not equal to provided value." - ne: String @fdc_oneOf(group: "ne") - """ - Match if field is not equal to the result of the provided server value - expression. Currently only `auth.uid` is supported as an expression. - """ - ne_expr: String_Expr @fdc_oneOf(group: "ne") - "Match if field value is among the provided list of values." - in: [String!] - "Match if field value is not among the provided list of values." - nin: [String!] - "Match if field value is greater than the provided value." - gt: String - "Match if field value is greater than or equal to the provided value." - ge: String - "Match if field value is less than the provided value." - lt: String - "Match if field value is less than or equal to the provided value." - le: String - """ - Match if field value contains the provided value as a substring. Equivalent - to `LIKE '%value%'` - """ - contains: String - """ - Match if field value starts with the provided value. Equivalent to - `LIKE 'value%'` - """ - startsWith: String - """ - Match if field value ends with the provided value. Equivalent to - `LIKE '%value'` - """ - endsWith: String - """ - Match if field value matches the provided pattern. See `String_Pattern` for - more details. - """ - 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 { - "Match using the provided `LIKE` expression." - like: String - "Match using the provided POSIX regular expression." - regex: String - "When true, ignore case when matching." - ignoreCase: Boolean - "When true, invert the match result. Equivalent to `NOT LIKE` or `!~`." - invert: Boolean -} - -"Query filter criteris for `[String!]` scalar fields." -input String_ListFilter { - "Match if list field contains the provided value as a member." - includes: String - "Match if list field does not contain the provided value as a member." - excludes: String - "Match if list field contains all of the provided values as members." - includesAll: [String!] - "Match if list field does not contain any of the provided values as members." - excludesAll: [String!] -} - -"Query filter criteria for `UUID` scalar fields." -input UUID_Filter { - "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." - isNull: Boolean - "Match if field is exactly equal to provided value." - eq: UUID - "Match if field is not equal to provided value." - ne: UUID - "Match if field value is among the provided list of values." - in: [UUID!] - "Match if field value is not among the provided list of values." - nin: [UUID!] -} - -"Query filter criteris for `[UUID!]` scalar fields." -input UUID_ListFilter { - "Match if list field contains the provided value as a member." - includes: UUID - "Match if list field does not contain the provided value as a member." - excludes: UUID - "Match if list field contains all of the provided values as members." - includesAll: [UUID!] - "Match if list field does not contain any of the provided values as members." - excludesAll: [UUID!] -} - -"Query filter criteria for `Int` scalar fields." -input Int_Filter { - "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." - isNull: Boolean - "Match if field is exactly equal to provided value." - eq: Int - "Match if field is not equal to provided value." - ne: Int - "Match if field value is among the provided list of values." - in: [Int!] - "Match if field value is not among the provided list of values." - nin: [Int!] - "Match if field value is greater than the provided value." - gt: Int - "Match if field value is greater than or equal to the provided value." - ge: Int - "Match if field value is less than the provided value." - lt: Int - "Match if field value is less than or equal to the provided value." - le: Int -} - -"Query filter criteris for `[Int!]` scalar fields." -input Int_ListFilter { - "Match if list field contains the provided value as a member." - includes: Int - "Match if list field does not contain the provided value as a member." - excludes: Int - "Match if list field contains all of the provided values as members." - includesAll: [Int!] - "Match if list field does not contain any of the provided values as members." - excludesAll: [Int!] -} - -"Query filter criteria for `Int64` scalar fields." -input Int64_Filter { - "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." - isNull: Boolean - "Match if field is exactly equal to provided value." - eq: Int64 - "Match if field is not equal to provided value." - ne: Int64 - "Match if field value is among the provided list of values." - in: [Int64!] - "Match if field value is not among the provided list of values." - nin: [Int64!] - "Match if field value is greater than the provided value." - gt: Int64 - "Match if field value is greater than or equal to the provided value." - ge: Int64 - "Match if field value is less than the provided value." - lt: Int64 - "Match if field value is less than or equal to the provided value." - le: Int64 -} - -"Query filter criteria for `[Int64!]` scalar fields." -input Int64_ListFilter { - "Match if list field contains the provided value as a member." - includes: Int64 - "Match if list field does not contain the provided value as a member." - excludes: Int64 - "Match if list field contains all of the provided values as members." - includesAll: [Int64!] - "Match if list field does not contain any of the provided values as members." - excludesAll: [Int64!] -} - -"Query filter criteria for `Float` scalar fields." -input Float_Filter { - "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." - isNull: Boolean - "Match if field is exactly equal to provided value." - eq: Float - "Match if field is not equal to provided value." - ne: Float - "Match if field value is among the provided list of values." - in: [Float!] - "Match if field value is not among the provided list of values." - nin: [Float!] - "Match if field value is greater than the provided value." - gt: Float - "Match if field value is greater than or equal to the provided value." - ge: Float - "Match if field value is less than the provided value." - lt: Float - "Match if field value is less than or equal to the provided value." - le: Float -} - -"Query filter criteria for `[Float!]` scalar fields." -input Float_ListFilter { - "Match if list field contains the provided value as a member." - includes: Float - "Match if list field does not contain the provided value as a member." - excludes: Float - "Match if list field contains all of the provided values as members." - includesAll: [Float!] - "Match if list field does not contain any of the provided values as members." - excludesAll: [Float!] -} - -"Query filter criteria for `Boolean` scalar fields." -input Boolean_Filter { - "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." - isNull: Boolean - "Match if field is exactly equal to provided value." - eq: Boolean - "Match if field is not equal to provided value." - ne: Boolean - "Match if field value is among the provided list of values." - in: [Boolean!] - "Match if field value is not among the provided list of values." - nin: [Boolean!] -} - -"Query filter criteria for `[Boolean!]` scalar fields." -input Boolean_ListFilter { - "Match if list field contains the provided value as a member." - includes: Boolean - "Match if list field does not contain the provided value as a member." - excludes: Boolean - "Match if list field contains all of the provided values as members." - includesAll: [Boolean!] - "Match if list field does not contain any of the provided values as members." - excludesAll: [Boolean!] -} - -"Query filter criteria for `Any` scalar fields." -input Any_Filter { - "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`." - isNull: Boolean - "Match if field is exactly equal to provided value." - eq: Any - "Match if field is not equal to provided value." - ne: Any - "Match if field value is among the provided list of values." - in: [Any!] - "Match if field value is not among the provided list of values." - nin: [Any!] -} - -"Query filter criteria for `[Any!]` scalar fields." -input Any_ListFilter { - "Match if list field contains the provided value as a member." - includes: Any - "Match if list field does not contain the provided value as a member." - excludes: Any - "Match if list field contains all of the provided values as members." - includesAll: [Any!] - "Match if list field does not contain any of the provided values as members." - excludesAll: [Any!] -} - -""" -(Internal) A string that uniquely identifies a type, field, and so on. - -The most common usage in FDC is `SomeType` or `SomeType.someField`. See the -linked page in the @specifiedBy directive for the GraphQL RFC with more details. -""" -scalar SchemaCoordinate - @specifiedBy(url: "https://github.com/graphql/graphql-wg/blob/6d02705dea034fb65ebc6799632adb7bd550d0aa/rfcs/SchemaCoordinates.md") - @fdc_forbiddenAsFieldType - @fdc_forbiddenAsVariableType - -"(Internal) The purpose of a generated type or field." -enum GeneratedPurpose { - # Implicit fields added to the table types as columns. - IMPLICIT_KEY_FIELD - IMPLICIT_REF_FIELD - - # Relational non-column fields extended to table types. - QUERY_MULTIPLE_ONE_TO_MANY - QUERY_MULTIPLE_MANY_TO_MANY - - # Top-level Query fields. - QUERY_SINGLE - QUERY_MULTIPLE - QUERY_MULTIPLE_BY_SIMILARITY - - # Top-level Mutation fields. - INSERT_SINGLE - INSERT_MULTIPLE - UPSERT_SINGLE - UPSERT_MULTIPLE - UPDATE_SINGLE - UPDATE_MULTIPLE - DELETE_SINGLE - DELETE_MULTIPLE -} - -"(Internal) Added to definitions generated by FDC." -directive @fdc_generated( - "The source type or field that causes this definition to be generated." - from: SchemaCoordinate! - "The reason why this definition is generated, such as the intended use case." - purpose: GeneratedPurpose! -) on - | SCALAR - | OBJECT - | FIELD_DEFINITION - | ARGUMENT_DEFINITION - | INTERFACE - | UNION - | ENUM - | ENUM_VALUE - | INPUT_OBJECT - | INPUT_FIELD_DEFINITION - -type _Service { - "Full Service Definition Language of the Frebase Data Connect Schema, including normalized schema, predefined and generated types." - sdl( - """ - Whether or not to omit Data Connect builtin GraphQL preludes. - They are static GraphQL publically available in the docsite. - """ - omitBuiltin: Boolean = false - """ - Whether or not to omit GQL description in the SDL. - We generate description to document generated schema. - It may bloat the size of SDL. - """ - omitDescription: Boolean = false - ): String! - "Orignal Schema Sources in the service." - schema: String! - "Generated documentation from the schema of the Firebase Data Connect Service." - docs: [_Doc!]! -} - -type _Doc { - "Name of the Doc Page." - page: String! - "The markdown content of the doc page." - markdown: 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 of hexadecimal digits representing an RFC4122-compliant UUID. - -UUIDs are always output as 32 lowercase hexadecimal digits without 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}` - -In the PostgreSQL table, it's stored as [`uuid`](https://www.postgresql.org/docs/current/datatype-uuid.html). -""" -scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122") - -""" -`Int64` is a scalar that represents a 64-bit signed integer. - -In the PostgreSQL table, it's stored as [`bigint`](https://www.postgresql.org/docs/current/datatype-numeric.html). - -On the wire, it's encoded as string because 64-bit integer exceeds the range of JSON number. -""" -scalar Int64 - -""" -The `Any` scalar type accommodates any valid [JSON value](https://www.json.org/json-en.html) -(e.g., numbers, strings, booleans, arrays, objects). PostgreSQL efficiently -stores this data as jsonb, providing flexibility for schemas with evolving structures. - -Caution: JSON doesn't distinguish Int and Float. - -##### Example: - -#### Schema - -```graphql -type Movie @table { - name: String! - metadata: Any! -} -``` - -#### Mutation - -Insert a movie with name and metadata from JSON literal. - -```graphql -mutation InsertMovie { - movie_insert( - data: { - name: "The Dark Knight" - metadata: { - release_year: 2008 - genre: ["Action", "Adventure", "Superhero"] - cast: [ - { name: "Christopher Bale", age: 31 } - { name: "Heath Ledger", age: 28 } - ] - director: "Christopher Nolan" - } - } - ) -} -``` - -Insert a movie with name and metadata that's constructed from a few GQL variables. - -```graphql -mutation InsertMovie($name: String!, $releaseDate: Date!, $genre: [String], $cast: [Any], $director: String!, $boxOfficeInUSD: Int) { - movie_insert(data: { - name: $name, - release_date: $releaseDate, - genre: $genre, - cast: $cast, - director: $director, - box_office: $boxOfficeInUSD - }) -} -``` -**Note**: - - - A mix of non-null and nullable variables can be provided. - - - `Date!` can be passed into scalar `Any` as well! It's stored as string. - - - `$cast` is a nested array. `[Any]` can represent an array of arbitrary types, but it won't enforce the input shape. - -#### Query - -Since `metadata` field has scalar `Any` type, it would return the full JSON in the response. - -**Note**: You can't define selection set to scalar based on [GraphQL spec](https://spec.graphql.org/October2021/#sec-Field-Selections). - -```graphql -query GetAllMovies { - movies { - name - metadata - } -} -``` - -""" -scalar Any @specifiedBy(url: "https://www.json.org/json-en.html") - -""" -The `Void` scalar type represents the absence of any value. It is typically used -in operations where no value is expected in return. -""" -scalar Void - -""" -The `True` scalar type only accepts the boolean value `true`. - -An optional field/argument typed as `True` may either be set -to `true` or omitted (not provided at all). The values `false` or `null` are not -accepted. -""" -scalar True - @fdc_forbiddenAsFieldType - @fdc_forbiddenAsVariableType - @fdc_example(value: true, description: "The only allowed value.") - -""" -A Common Expression Language (CEL) expression that returns a boolean at runtime. - -This expression can reference the `auth` variable, which is null when Firebase -Auth is not used. When Firebase Auth is used, the following fields are available: - - - `auth.uid`: The current user ID. - - `auth.token`: A map containing all token fields (e.g., 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**: Currently, only a limited set of expressions are supported. -""" -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**: Currently, only a limited set of expressions are supported. -""" -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 currently supported for each -type. -""" -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. - -In this example, we defined one table with a field named `myField`. - -```graphql -type TableName @table { - myField: String -} -``` -Data Connect adds an implicit `id` primary key column. So the above schema is equivalent to: - -```graphql -type TableName @table(key: "id") { - id: String @default(expr: "uuidV4()") - myField: String -} -``` - -Data Connect generates the following SQL table and CRUD operations to use it. - -```sql -CREATE TABLE "public"."table_name" ( - "id" uuid NOT NULL DEFAULT uuid_generate_v4(), - "my_field" text NULL, - PRIMARY KEY ("id") -) -``` - - * You can lookup a row: `query ($id: UUID!) { tableName(id: $id) { myField } } ` - * You can find rows using: `query tableNames(limit: 20) { myField }` - * You can insert a row: `mutation { tableName_insert(data: {myField: "foo"}) }` - * You can update a row: `mutation ($id: UUID!) { tableName_update(id: $id, data: {myField: "bar"}) }` - * You can delete a row: `mutation ($id: UUID!) { tableName_delete(id: $id) }` - -##### Customizations - -- `@table(singular)` and `@table(plural)` can customize the singular and plural name. -- `@table(name)` can customize the Postgres table name. -- `@table(key)` can customize the primary key field name and type. - -For example, the `User` table often has a `uid` as its primary key. - -```graphql -type User @table(key: "uid") { - uid: String! - name: String -} -``` - - * You can securely lookup a row: `query { user(key: {uid_expr: "auth.uid"}) { name } } ` - * You can securely insert a row: `mutation { user_insert(data: {uid_expr: "auth.uid" name: "Fred"}) }` - * You can securely update a row: `mutation { user_update(key: {uid_expr: "auth.uid"}, data: {name: "New Name"}) }` - * You can securely delete a row: `mutation { user_delete(key: {uid_expr: "auth.uid"}) }` - -`@table` type can be configured further with: - - - Custom SQL data types for columns. See `@col`. - - Add SQL indexes. See `@index`. - - Add SQL unique constraints. See `@unique`. - - Add foreign key constraints to define relations. See `@ref`. - -""" -directive @table( - """ - Configures the SQL database table name. Defaults to snake_case like `table_name`. - """ - name: String - """ - Configures the singular name. Defaults to the camelCase like `tableName`. - """ - singular: String - """ - Configures the plural name. Defaults to infer based on English plural pattern like `tableNames`. - """ - plural: String - """ - Defines the primary key of the table. Defaults to a single field named `id`. - If not present already, Data Connect adds an implicit field `id: UUID! @default(expr: "uuidV4()")`. - """ - key: [String!] -) on OBJECT - -""" -Defines a relational database Raw SQLview. - -Data Connect generates GraphQL queries with WHERE and ORDER BY clauses. -However, not all SQL features has native GraphQL equivalent. - -You can write **an arbitrary SQL SELECT statement**. Data Connect -would map Graphql fields on `@view` type to columns in your SELECT statement. - -* Scalar GQL fields (camelCase) should match a SQL column (snake_case) - in the SQL SELECT statement. -* Reference GQL field can point to another `@table` type. Similar to foreign key - defined with `@ref` on a `@table` type, a `@view` type establishes a relation - when `@ref(fields)` match `@ref(references)` on the target table. - -In this example, you can use `@view(sql)` to define an aggregation view on existing -table. - -```graphql -type User @table { - name: String - score: Int -} -type UserAggregation @view(sql: ''' - SELECT - COUNT(*) as count, - SUM(score) as sum, - AVG(score) as average, - PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY score) AS median, - (SELECT id FROM "user" LIMIT 1) as example_id - FROM "user" -''') { - count: Int - sum: Int - average: Float - median: Float - example: User - exampleId: UUID -} -``` - -###### Example: Query Raw SQL View - -```graphql -query { - userAggregations { - count sum average median - exampleId example { id } - } -} -``` - -##### One-to-One View - -An one-to-one companion `@view` can be handy if you want to argument a `@table` -with additional implied content. - -```graphql -type Restaurant @table { - name: String! -} -type Review @table { - restaurant: Restaurant! - rating: Int! -} -type RestaurantStats @view(sql: ''' - SELECT - restaurant_id, - COUNT(*) AS review_count, - AVG(rating) AS average_rating - FROM review - GROUP BY restaurant_id -''') { - restaurant: Restaurant @unique - reviewCount: Int - averageRating: Float -} -``` - -In this example, `@unique` convey the assumption that each `Restaurant` should -have only one `RestaurantStats` object. - -###### Example: Query One-to-One View - -```graphql -query ListRestaurants { - restaurants { - name - stats: restaurantStats_on_restaurant { - reviewCount - averageRating - } - } -} -``` - -###### Example: Filter based on One-to-One View - -```graphql -query BestRestaurants($minAvgRating: Float, $minReviewCount: Int) { - restaurants(where: { - restaurantStats_on_restaurant: { - averageRating: {ge: $minAvgRating} - reviewCount: {ge: $minReviewCount} - } - }) { name } -} -``` - -##### Customizations - -- One of `@view(sql)` or `@view(name)` should be defined. - `@view(name)` can refer to a persisted SQL view in the Postgres schema. -- `@view(singular)` and `@view(plural)` can customize the singular and plural name. - -`@view` type can be configured further: - - - `@unique` lets you define one-to-one relation. - - `@col` lets you customize SQL column mapping. For example, `@col(name: "column_in_select")`. - -##### Limitations - -Raw SQL view doesn't have a primary key, so it doesn't support lookup. Other -`@table` or `@view` cannot have `@ref` to a view either. - -View cannot be mutated. You can perform CRUD operations on the underlying -table to alter its content. - -**Important: Data Connect doesn't parse and validate SQL** - -- If the SQL view is invalid or undefined, related requests may fail. -- If the SQL view return incompatible types. Firebase Data Connect may surface - errors. -- If a field doesn't have a corresponding column in the SQL SELECT statement, - it will always be `null`. -- There is no way to ensure VIEW to TABLE `@ref` constraint. -- All fields must be nullable in case they aren't found in the SELECT statement - or in the referenced table. - -**Important: You should always test `@view`!** - -""" -directive @view( - """ - The SQL view name. If neither `name` nor `sql` are provided, defaults to the - snake_case of the singular type name. - `name` and `sql` cannot be specified at the same time. - """ - name: String @fdc_oneOf - """ - SQL `SELECT` statement used as the basis for this type. - SQL SELECT columns should use snake_case. GraphQL fields should use camelCase. - `name` and `sql` cannot be specified at the same time. - """ - sql: String @fdc_oneOf - """ - Configures the singular name. Defaults to the camelCase like `viewName`. - """ - singular: String - """ - Configures the plural name. Defaults to infer based on English plural pattern like `viewNames`. - """ - plural: String -) on OBJECT - -""" -Customizes a field that represents a SQL database table column. - -Data Connect maps scalar Fields on `@table` type to a SQL column of -corresponding data type. - -- scalar `UUID` maps to [`uuid`](https://www.postgresql.org/docs/current/datatype-uuid.html). -- scalar `String` maps to [`text`](https://www.postgresql.org/docs/current/datatype-character.html). -- scalar `Int` maps to [`int`](https://www.postgresql.org/docs/current/datatype-numeric.html). -- scalar `Int64` maps to [`bigint`](https://www.postgresql.org/docs/current/datatype-numeric.html). -- scalar `Float` maps to [`double precision`](https://www.postgresql.org/docs/current/datatype-numeric.html). -- scalar `Boolean` maps to [`boolean`](https://www.postgresql.org/docs/current/datatype-boolean.html). -- scalar `Date` maps to [`date`](https://www.postgresql.org/docs/current/datatype-datetime.html). -- scalar `Timestamp` maps to [`timestamptz`](https://www.postgresql.org/docs/current/datatype-datetime.html). -- scalar `Any` maps to [`jsonb`](https://www.postgresql.org/docs/current/datatype-json.html). -- scalar `Vector` maps to [`pgvector`](https://github.com/pgvector/pgvector). - -Array scalar fields are mapped to [Postgres arrays](https://www.postgresql.org/docs/current/arrays.html). - -###### Example: Serial Primary Key - -For example, you can define auto-increment primary key. - -```graphql -type Post @table { - id: Int! @col(name: "post_id", dataType: "serial") -} -``` - -Data Connect converts it to the following SQL table schema. - -```sql -CREATE TABLE "public"."post" ( - "post_id" serial NOT NULL, - PRIMARY KEY ("id") -) -``` - -###### Example: Vector - -```graphql -type Post @table { - content: String! @col(name: "post_content") - contentEmbedding: Vector! @col(size:768) -} -``` - -""" -directive @col( - """ - The SQL database column name. Defaults to snake_case of the field name. - """ - name: String - """ - Configures the custom SQL data type. - - Each GraphQL type can map to multiple SQL data types. - Refer to [Postgres supported data types](https://www.postgresql.org/docs/current/datatype.html). - - Incompatible SQL data type will lead to undefined behavior. - """ - dataType: String - """ - Required on `Vector` columns. It specifies the length of the Vector. - `textembedding-gecko@003` model generates `Vector` of `@col(size:768)`. - """ - size: Int -) on FIELD_DEFINITION - - -""" -Defines a foreign key reference to another table. - -For example, we can define a many-to-one relation. - -```graphql -type ManyTable @table { - refField: OneTable! -} -type OneTable @table { - someField: String! -} -``` -Data Connect adds implicit foreign key column and relation query field. So the -above schema is equivalent to the following schema. - -```graphql -type ManyTable @table { - id: UUID! @default(expr: "uuidV4()") - refField: OneTable! @ref(fields: "refFieldId", references: "id") - refFieldId: UUID! -} -type OneTable @table { - id: UUID! @default(expr: "uuidV4()") - someField: UUID! - # Generated Fields: - # manyTables_on_refField: [ManyTable!]! -} -``` -Data Connect generates the necessary foreign key constraint. - -```graphql -CREATE TABLE "public"."many_table" ( - "id" uuid NOT NULL DEFAULT uuid_generate_v4(), - "ref_field_id" uuid NOT NULL, - PRIMARY KEY ("id"), - CONSTRAINT "many_table_ref_field_id_fkey" FOREIGN KEY ("ref_field_id") REFERENCES "public"."one_table" ("id") ON DELETE CASCADE -) -``` - -###### Example: Traverse the Reference Field - -```graphql -query ($id: UUID!) { - manyTable(id: $id) { - refField { id } - } -} -``` - -###### Example: Reverse Traverse the Reference field - -```graphql -query ($id: UUID!) { - oneTable(id: $id) { - manyTables_on_refField { id } - } -} -``` - -##### Optional Many-to-One Relation - -An optional foreign key reference will be set to null if the referenced row is deleted. - -In this example, if a `User` is deleted, the `assignee` and `reporter` -references will be set to null. - -```graphql -type Bug @table { - title: String! - assignee: User - reproter: User -} - -type User @table { name: String! } -``` - -##### Required Many-to-One Relation - -A required foreign key reference will cascade delete if the referenced row is -deleted. - -In this example, if a `Post` is deleted, associated comments will also be -deleted. - -```graphql -type Comment @table { - post: Post! - content: String! -} - -type Post @table { title: String! } -``` - -##### Many To Many Relation - -You can define a many-to-many relation with a join table. - -```graphql -type Membership @table(key: ["group", "user"]) { - group: Group! - user: User! - role: String! @default(value: "member") -} - -type Group @table { name: String! } -type User @table { name: String! } -``` - -When Data Connect sees a table with two reference field as its primary key, it -knows this is a join table, so expands the many-to-many query field. - -```graphql -type Group @table { - name: String! - # Generated Fields: - # users_via_Membership: [User!]! - # memberships_on_group: [Membership!]! -} -type User @table { - name: String! - # Generated Fields: - # groups_via_Membership: [Group!]! - # memberships_on_user: [Membership!]! -} -``` - -###### Example: Traverse the Many-To-Many Relation - -```graphql -query ($id: UUID!) { - group(id: $id) { - users: users_via_Membership { - name - } - } -} -``` - -###### Example: Traverse to the Join Table - -```graphql -query ($id: UUID!) { - group(id: $id) { - memberships: memberships_on_group { - user { name } - role - } - } -} -``` - -##### One To One Relation - -You can even define a one-to-one relation with the help of `@unique` or `@table(key)`. - -```graphql -type User @table { - name: String -} -type Account @table { - user: User! @unique -} -# Alternatively, use primary key constraint. -# type Account @table(key: "user") { -# user: User! -# } -``` - -###### Example: Transerse the Reference Field - -```graphql -query ($id: UUID!) { - account(id: $id) { - user { id } - } -} -``` - -###### Example: Reverse Traverse the Reference field - -```graphql -query ($id: UUID!) { - user(id: $id) { - account_on_user { id } - } -} -``` - -##### Customizations - -- `@ref(constraintName)` can customize the SQL foreign key constraint name (`table_name_ref_field_fkey` above). -- `@ref(fields)` can customize the foreign key field names. -- `@ref(references)` can customize the constraint to reference other columns. - By default, `@ref(references)` is the primary key of the `@ref` table. - Other fields with `@unique` may also be referred in the foreign key constraint. - -""" -directive @ref( - "The SQL database foreign key constraint name. Defaults to snake_case `{table_name}_{field_name}_fkey`." - constraintName: String - """ - Foreign key fields. Defaults to `{tableName}{PrimaryIdName}`. - """ - fields: [String!] - "The fields that the foreign key references in the other table. Defaults to its primary key." - references: [String!] -) on FIELD_DEFINITION - -"Defines the orderBy direction in a query." -enum OrderDirection { -"Results are ordered in ascending order." - ASC -"Results are ordered in descending order." - DESC -} - -""" -Specifies the default value for a column field. - -For example: - -```graphql -type User @table(key: "uid") { - uid: String! @default(expr: "auth.uid") - number: Int! @col(dataType: "serial") - createdAt: Date! @default(expr: "request.time") - role: String! @default(value: "Member") - credit: Int! @default(value: 100) -} -``` - -The supported arguments vary based on the field type. -""" -directive @default( - "A constant value validated against the field's GraphQL type during compilation." - value: Any @fdc_oneOf(required: true) - "A CEL expression whose return value must match the field's 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. - See [PostgreSQL defaults](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-DEFAULT) - for more details. - """ - sql: Any_SQL @fdc_oneOf(required: true) -) on FIELD_DEFINITION - -""" -Defines a database index to optimize query performance. - -```graphql -type User @table @index(fields: ["name", "phoneNumber"], order: [ASC, DESC]) { - name: String @index - phoneNumber: Int64 @index - tags: [String] @index # GIN Index -} -``` - -##### Single Field Index - -You can put `@index` on a `@col` field to create a SQL index. - -`@index(order)` matters little for single field indexes, as they can be scanned -in both directions. - -##### Composite Index - -You can put `@index(fields: [...])` on `@table` type to define composite indexes. - -`@index(order: [...])` can customize the index order to satisfy particular -filter and order requirement. - -""" -directive @index( - """ - Configure the SQL database index id. - - If not overridden, Data Connect generates the index name: - - `{table_name}_{first_field}_{second_field}_aa_idx` - - `{table_name}_{field_name}_idx` - """ - name: String - """ - Only allowed and required when used on a `@table` type. - Specifies the fields to create the index on. - """ - fields: [String!] - """ - Only allowed for `BTREE` `@index` on `@table` type. - Specifies the order for each indexed column. Defaults to all `ASC`. - """ - order: [IndexFieldOrder!] - """ - Customize the index type. - - For most index, it defaults to `BTREE`. - For array fields, only allowed `IndexType` is `GIN`. - For `Vector` fields, defaults to `HNSW`, may configure to `IVFFLAT`. - """ - type: IndexType - """ - Only allowed when used on vector field. - Defines the vector similarity method. Defaults to `INNER_PRODUCT`. - """ - vector_method: VectorSimilarityMethod -) repeatable on FIELD_DEFINITION | OBJECT - -"Specifies the sorting order for database indexes." -enum IndexFieldOrder { - "Sorts the field in ascending order (from lowest to highest)." - ASC - "Sorts the field in descending order (from highest to lowest)." - DESC -} - -"Defines the type of index to be used in the database." -enum IndexType { - "A general-purpose index type commonly used for sorting and searching." - BTREE - "Generalized Inverted Index, optimized for indexing composite values such as arrays." - GIN - "Hierarchical Navigable Small World graph, used for nearest-neighbor searches on vector fields." - HNSW - "Inverted File Index, optimized for approximate nearest-neighbor searches in vector databases." - IVFFLAT -} - -""" -Defines unique constraints on `@table`. - -For example, - -```graphql -type User @table { - phoneNumber: Int64 @unique -} -type UserProfile @table { - user: User! @unique - address: String @unique -} -``` - -- `@unique` on a `@col` field adds a single-column unique constraint. -- `@unique` on a `@table` type adds a composite unique constraint. -- `@unique` on a `@ref` defines a one-to-one relation. It adds unique constraint - on `@ref(fields)`. - -`@unique` ensures those fields can uniquely identify a row, so other `@table` -type may define `@ref(references)` to refer to fields that has a unique constraint. - -""" -directive @unique( - """ - Configures the SQL database unique constraint name. - - If not overridden, Data Connect generates the unique constraint name: - - `table_name_first_field_second_field_uidx` - - `table_name_only_field_name_uidx` - """ - indexName: String - """ - Only allowed and required when used on OBJECT, - this specifies the fields to create a unique constraint on. - """ - fields: [String!] -) repeatable on FIELD_DEFINITION | OBJECT - -""" -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. - -In the PostgreSQL table, it's stored as [`date`](https://www.postgresql.org/docs/current/datatype-datetime.html). -""" -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. - -In the PostgreSQL table, it's stored as [`timestamptz`](https://www.postgresql.org/docs/current/datatype-datetime.html). -""" -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. -""" -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. -""" -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 { - "Match if the field `IS NULL`." - isNull: Boolean - "Match if the field is exactly equal to the provided value." - eq: Date @fdc_oneOf(group: "eq") - "Match if the field equals the provided CEL expression." - eq_expr: Date_Expr @fdc_oneOf(group: "eq") - "Match if the field equals the provided relative date." - eq_date: Date_Relative @fdc_oneOf(group: "eq") - "Match if the field is not equal to the provided value." - ne: Date @fdc_oneOf(group: "ne") - "Match if the field is not equal to the provided CEL expression." - ne_expr: Date_Expr @fdc_oneOf(group: "ne") - "Match if the field is not equal to the provided relative date." - ne_date: Date_Relative @fdc_oneOf(group: "ne") - "Match if the field value is among the provided list of values." - in: [Date!] - "Match if the field value is not among the provided list of values." - nin: [Date!] - "Match if the field value is greater than the provided value." - gt: Date @fdc_oneOf(group: "gt") - "Match if the field value is greater than the provided CEL expression." - gt_expr: Date_Expr @fdc_oneOf(group: "gt") - "Match if the field value is greater than the provided relative date." - gt_date: Date_Relative @fdc_oneOf(group: "gt") - "Match if the field value is greater than or equal to the provided value." - ge: Date @fdc_oneOf(group: "ge") - "Match if the field value is greater than or equal to the provided CEL expression." - ge_expr: Date_Expr @fdc_oneOf(group: "ge") - "Match if the field value is greater than or equal to the provided relative date." - ge_date: Date_Relative @fdc_oneOf(group: "ge") - "Match if the field value is less than the provided value." - lt: Date @fdc_oneOf(group: "lt") - "Match if the field value is less than the provided CEL expression." - lt_expr: Date_Expr @fdc_oneOf(group: "lt") - "Match if the field value is less than the provided relative date." - lt_date: Date_Relative @fdc_oneOf(group: "lt") - "Match if the field value is less than or equal to the provided value." - le: Date @fdc_oneOf(group: "le") - "Match if the field value is less than or equal to the provided CEL expression." - le_expr: Date_Expr @fdc_oneOf(group: "le") - "Match if the field value is less than or equal to the provided relative date." - le_date: Date_Relative @fdc_oneOf(group: "le") -} - -"Conditions on a`Date` list." -input Date_ListFilter { - "Match if the list contains the provided date." - includes: Date @fdc_oneOf(group: "includes") - "Match if the list contains the provided date CEL expression." - includes_expr: Date_Expr @fdc_oneOf(group: "includes") - "Match if the list contains the provided relative date." - includes_date: Date_Relative @fdc_oneOf(group: "includes") - "Match if the list does not contain the provided date." - excludes: Date @fdc_oneOf(group: "excludes") - "Match if the list does not contain the provided date CEL expression." - excludes_expr: Date_Expr @fdc_oneOf(group: "excludes") - "Match if the list does not contain the provided relative date." - excludes_date: Date_Relative @fdc_oneOf(group: "excludes") - "Match if the list contains all the provided dates." - includesAll: [Date!] - "Match if the list contains none of the provided dates." - excludesAll: [Date!] -} - -"Conditions on a `Timestamp` value." -input Timestamp_Filter { - "Match if the field `IS NULL`." - isNull: Boolean - "Match if the field is exactly equal to the provided value." - eq: Timestamp @fdc_oneOf(group: "eq") - "Match if the field equals the provided CEL expression." - eq_expr: Timestamp_Expr @fdc_oneOf(group: "eq") - "Match if the field equals the provided relative time." - eq_time: Timestamp_Relative @fdc_oneOf(group: "eq") - "Match if the field is not equal to the provided value." - ne: Timestamp @fdc_oneOf(group: "ne") - "Match if the field is not equal to the provided CEL expression." - ne_expr: Timestamp_Expr @fdc_oneOf(group: "ne") - "Match if the field is not equal to the provided relative time." - ne_time: Timestamp_Relative @fdc_oneOf(group: "ne") - "Match if the field value is among the provided list of values." - in: [Timestamp!] - "Match if the field value is not among the provided list of values." - nin: [Timestamp!] - "Match if the field value is greater than the provided value." - gt: Timestamp @fdc_oneOf(group: "gt") - "Match if the field value is greater than the provided CEL expression." - gt_expr: Timestamp_Expr @fdc_oneOf(group: "gt") - "Match if the field value is greater than the provided relative time." - gt_time: Timestamp_Relative @fdc_oneOf(group: "gt") - "Match if the field value is greater than or equal to the provided value." - ge: Timestamp @fdc_oneOf(group: "ge") - "Match if the field value is greater than or equal to the provided CEL expression." - ge_expr: Timestamp_Expr @fdc_oneOf(group: "ge") - "Match if the field value is greater than or equal to the provided relative time." - ge_time: Timestamp_Relative @fdc_oneOf(group: "ge") - "Match if the field value is less than the provided value." - lt: Timestamp @fdc_oneOf(group: "lt") - "Match if the field value is less than the provided CEL expression." - lt_expr: Timestamp_Expr @fdc_oneOf(group: "lt") - "Match if the field value is less than the provided relative time." - lt_time: Timestamp_Relative @fdc_oneOf(group: "lt") - "Match if the field value is less than or equal to the provided value." - le: Timestamp @fdc_oneOf(group: "le") - "Match if the field value is less than or equal to the provided CEL expression." - le_expr: Timestamp_Expr @fdc_oneOf(group: "le") - "Match if the field value is less than or equal to the provided relative time." - le_time: Timestamp_Relative @fdc_oneOf(group: "le") -} - -"Conditions on a `Timestamp` list." -input Timestamp_ListFilter { - "Match if the list contains the provided timestamp." - includes: Timestamp @fdc_oneOf(group: "includes") - "Match if the list contains the provided timestamp CEL expression." - includes_expr: Timestamp_Expr @fdc_oneOf(group: "includes") - "Match if the list contains the provided relative timestamp." - includes_time: Timestamp_Relative @fdc_oneOf(group: "includes") - "Match if the list does not contain the provided timestamp." - excludes: Timestamp @fdc_oneOf(group: "excludes") - "Match if the list does not contain the provided timestamp CEL expression." - excludes_expr: Timestamp_Expr @fdc_oneOf(group: "excludes") - "Match if the list does not contain the provided relative timestamp." - excludes_time: Timestamp_Relative @fdc_oneOf(group: "excludes") - "Match if the list contains all the provided timestamps." - includesAll: [Timestamp!] - "Match if the list contains none of the provided timestamps." - excludesAll: [Timestamp!] -} - -"Update input of a `Date` value." -input Date_Update { - "Set the field to the provided date." - set: Date @fdc_oneOf(group: "set") - "Set the field to the provided date CEL expression." - set_expr: Date_Expr @fdc_oneOf(group: "set") - "Set the field to the provided relative date." - set_date: Date_Relative @fdc_oneOf(group: "set") -} - -"Update input of a `Date` list value." -input Date_ListUpdate { - "Replace the current list with the provided list of `Date` values." - set: [Date!] - "Append the provided `Date` values to the existing list." - append: [Date!] - "Prepend the provided `Date` values to the existing list." - prepend: [Date!] - "Remove the date value at the specified index." - delete: Int - "The index of the list to perform updates." - i: Int - "Update the date value at the specified index." - update: Date -} - -"Update input of a `Timestamp` value." -input Timestamp_Update { - "Set the field to the provided timestamp." - set: Timestamp @fdc_oneOf(group: "set") - "Set the field to the provided timestamp CEL expression." - set_expr: Timestamp_Expr @fdc_oneOf(group: "set") - "Set the field to the provided relative timestamp." - set_time: Timestamp_Relative @fdc_oneOf(group: "set") -} - -"Update input of an `Timestamp` list value." -input Timestamp_ListUpdate { - "Replace the current list with the provided list of `Timestamp` values." - set: [Timestamp!] - "Append the provided `Timestamp` values to the existing list." - append: [Timestamp!] - "Prepend the provided `Timestamp` values to the existing list." - prepend: [Timestamp!] - "Remove the timestamp value at the specified index." - delete: Int - "The index of the list to perform updates." - i: Int - "Update the timestamp value at the specified index." - update: Timestamp -} - - -"A runtime-calculated `Timestamp` value relative to `now` or `at`." -input Timestamp_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { - "Match for the current time." - now: True @fdc_oneOf(group: "from", required: true) - "A specific timestamp for matching." - at: Timestamp @fdc_oneOf(group: "from", required: true) - "Add the provided duration to the base timestamp." - add: Timestamp_Duration - "Subtract the provided duration from the base timestamp." - sub: Timestamp_Duration - "Truncate the timestamp to the provided interval." - truncateTo: Timestamp_Interval -} - -input Timestamp_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { - "The number of milliseconds for the duration." - milliseconds: Int! = 0 - "The number of seconds for the duration." - seconds: Int! = 0 - "The number of minutes for the duration." - minutes: Int! = 0 - "The number of hours for the duration." - hours: Int! = 0 - "The number of days for the duration." - days: Int! = 0 - "The number of weeks for the duration." - weeks: Int! = 0 - "The number of months for the duration." - months: Int! = 0 - "The number of years for the duration." - years: Int! = 0 -} - -enum Timestamp_Interval @fdc_forbiddenAsFieldType { - "Represents a time interval of one second." - SECOND - "Represents a time interval of one minute." - MINUTE - "Represents a time interval of one hour." - HOUR - "Represents a time interval of one day." - DAY - "Represents a time interval of one week." - WEEK - "Represents a time interval of one month." - MONTH - "Represents a time interval of one year." - YEAR -} - -"A runtime-calculated Date value relative to `today` or `on`." -input Date_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { - "Match for today’s date." - today: True @fdc_oneOf(group: "from", required: true) - "A specific date for matching." - on: Date @fdc_oneOf(group: "from", required: true) - "Add the provided duration to the base date." - add: Date_Duration - "Subtract the provided duration from the base date." - sub: Date_Duration - "Truncate the date to the provided interval." - truncateTo: Date_Interval -} - -input Date_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType { - "The number of days for the duration." - days: Int! = 0 - "The number of weeks for the duration." - weeks: Int! = 0 - "The number of months for the duration." - months: Int! = 0 - "The number of years for the duration." - years: Int! = 0 -} - -enum Date_Interval @fdc_forbiddenAsFieldType { - "Represents a time interval of one week." - WEEK - "Represents a time interval of one month." - MONTH - "Represents a time interval of one year." - YEAR -} - -"Update input of a `String` value." -input String_Update { - "Set the field to a provided value." - set: String @fdc_oneOf(group: "set") - "Set the field to a provided server value expression." - set_expr: String_Expr @fdc_oneOf(group: "set") -} - -"Update input of a `String` list value." -input String_ListUpdate { - "Set the list with the provided values." - set: [String!] - "Append the provided values to the existing list." - append: [String!] - "Prepend the provided values to the existing list." - prepend: [String!] -} - -"Update input of a `UUID` value." -input UUID_Update { - "Set the field to a provided UUID." - set: UUID @fdc_oneOf(group: "set") - "Set the field to a provided UUID expression." - set_expr: UUID_Expr @fdc_oneOf(group: "set") -} - -"Update input of an `ID` list value." -input UUID_ListUpdate { - "Set the list with the provided list of UUIDs." - set: [UUID!] - "Append the provided UUIDs to the existing list." - append: [UUID!] - "Prepend the provided UUIDs to the existing list." - prepend: [UUID!] -} - -"Update input of an `Int` value." -input Int_Update { - "Set the field to a provided value." - set: Int - "Increment the field by a provided value." - inc: Int - "Decrement the field by a provided value." - dec: Int -} - -"Update input of an `Int` list value." -input Int_ListUpdate { - "Set the list with the provided values." - set: [Int!] - "Append the provided list of values to the existing list." - append: [Int!] - "Prepend the provided list of values to the existing list." - prepend: [Int!] -} - -"Update input of an `Int64` value." -input Int64_Update { - "Set the field to a provided value." - set: Int64 - "Increment the field by a provided value." - inc: Int64 - "Decrement the field by a provided value." - dec: Int64 -} - -"Update input of an `Int64` list value." -input Int64_ListUpdate { - "Replace the list with the provided values." - set: [Int64!] - "Append the provided list of values to the existing list." - append: [Int64!] - "Prepend the provided list of values to the existing list." - prepend: [Int64!] -} - -"Update input of a `Float` value." -input Float_Update { - "Set the field to a provided value." - set: Float - "Increment the field by a provided value." - inc: Float - "Decrement the field by a provided value." - dec: Float -} - -"Update input of a `Float` list value." -input Float_ListUpdate { - "Set the list with the provided values." - set: [Float!] - "Append the provided list of values to the existing list." - append: [Float!] - "Prepend the provided list of values to the existing list." - prepend: [Float!] -} - -"Update input of a `Boolean` value." -input Boolean_Update { - "Set the field to a provided value." - set: Boolean -} - -"Update input of a `Boolean` list value." -input Boolean_ListUpdate { - "Set the list with the provided values." - set: [Boolean!] - "Append the provided list of values to the existing list." - append: [Boolean!] - "Prepend the provided list of values to the existing list." - prepend: [Boolean!] -} - -"Update input of an `Any` value." -input Any_Update { - "Set the field to a provided value." - set: Any -} - -"Update input of an `Any` list value." -input Any_ListUpdate { - "Set the list with the provided values." - set: [Any!] - "Append the provided list of values to the existing list." - append: [Any!] - "Prepend the provided list of values to the existing list." - prepend: [Any!] -} - -type Query { - """ - _service provides customized introspection on Firebase Data Connect Sevice. - """ - _service: _Service! -} - -""" -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] - -In the PostgreSQL table, it's stored as [`pgvector`](https://github.com/pgvector/pgvector). - -See `Vector_Embed` for how to generate text embeddings in query and mutations. -""" -scalar Vector - -""" -Defines the similarity function to use when comparing vectors in queries. - -Defaults to `INNER_PRODUCT`. - -View [all vector functions](https://github.com/pgvector/pgvector?tab=readme-ov-file#vector-functions). -""" -enum VectorSimilarityMethod { - "Measures the Euclidean (L2) distance between two vectors." - L2 - "Measures the cosine similarity between two vectors." - COSINE - "Measures the inner product(dot product) between two vectors." - INNER_PRODUCT -} - -"Conditions on a Vector value." -input Vector_Filter { - "Match if the field is exactly equal to the provided vector." - eq: Vector - "Match if the field is not equal to the provided vector." - ne: Vector - "Match if the field value is among the provided list of vectors." - in: [Vector!] - "Match if the field value is not among the provided list of vectors." - nin: [Vector!] - "Match if the field is `NULL`." - isNull: Boolean -} - -input Vector_ListFilter { - "Match if the list includes the supplied vector." - includes: Vector - "Match if the list does not include the supplied vector." - excludes: Vector - "Match if the list contains all the provided vectors." - includesAll: [Vector!] - "Match if the list contains none of the provided vectors." - excludesAll: [Vector!] -} - -"Update input of a Vector value." -input Vector_Update { - "Set the field to the provided vector value." - set: Vector @fdc_oneOf(group: "set") - "Set the field to the vector embedding result from a text input." - set_embed: Vector_Embed @fdc_oneOf(group: "set") -} - - -"Update input of a Vector list value." -input Vector_ListUpdate { - "Replace the current list with the provided list of Vector values." - set: [Vector] - "Append the provided Vector values to the existing list." - append: [Vector] - "Prepend the provided Vector values to the existing list." - prepend: [Vector] - "Delete the vector at the specified index." - delete: Int - "The index of the vector to be updated." - i: Int - "Update the vector at the specified index." - update: Vector -} - -""" -Create a vector embedding of text using the given model on Vertex AI. - -Cloud SQL for Postgresql natively integrates with [Vertex AI Text embeddings API](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text-embeddings-api) -to effectively generate text embeddings. - -If you uses [`Vector`](scalar.md#Vector) in your schema, Firebase Data Connect automatically installs -[`pgvector`](https://github.com/pgvector/pgvector) and [`google_ml_integration`](https://cloud.google.com/sql/docs/postgres/integrate-cloud-sql-with-vertex-ai) -Postgres extensions in your Cloud SQL database. - -Given a Post table with a `Vector` embedding field. - -```graphql -type Post @table { - content: String! - contentEmbedding: Vector @col(size:768) -} -``` - -NOTE: All natively supported `Vector_Embed_Model` generates vector of length `768`. - -###### Example: Insert embedding - -```graphql -mutation CreatePost($content: String!) { - post_insert(data: { - content: $content, - contentEmbedding_embed: {model: "textembedding-gecko@003", text: $content}, - }) -} -``` - -###### Example: Vector similarity Search - -```graphql -query SearchPost($query: String!) { - posts_contentEmbedding_similarity(compare_embed: {model: "textembedding-gecko@003", text: $query}) { - id - content - } -} -``` -""" -input Vector_Embed @fdc_forbiddenAsVariableType { - """ - The model to use for vector embedding. - Recommend the latest stable model: `textembedding-gecko@003`. - """ - model: Vector_Embed_Model! - "The text to generate the vector embedding from." - text: String! -} - -""" -The Vertex AI model version that is required in input `Vector_Embed`. - -It is recommended to use the latest stable model version: `textembedding-gecko@003`. - -View all supported [Vertex AI Text embeddings APIs](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text-embeddings-api). -""" -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") - @fdc_example(value: "textembedding-gecko@001", description: "An older version of the textembedding-gecko model") - @fdc_example(value: "text-embedding-004", description: "Another text embedding model") - -""" -Redact a part of the response from the client. - -Redacted fields are still evaluated for side effects (including data changes and -`@check`) and the results are still available to later steps in CEL expressions -(via `response.fieldName`). -""" -directive @redact on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -""" -Ensure this field is present and is not null or `[]`, or abort the request / transaction. - -A CEL expression, `expr` is used to test the field value. It defaults to -rejecting null and `[]` but a custom expression can be provided instead. - -If the field occurs multiple times (i.e. directly or indirectly nested under a -list), `expr` will be executed once for each occurrence and `@check` succeeds if -all values succeed. `@check` fails when the field is not present at all (i.e. -all ancestor paths contain `null` or `[]`), unless `optional` is true. - -If a `@check` fails in a mutation, the top-level field containing it will be -replaced with a partial error, whose message can be customzied via the `message` -argument. Each subsequent top-level fields will return an aborted error (i.e. -not executed). To rollback previous steps, see `@transaction`. -""" -directive @check( - """ - The CEL expression to test the field value (or values if nested under a list). - - Within the CEL expression, a special value `this` evaluates to the field that - this directive is attached to. If this field occurs multiple times because - any ancestor is a list, each occurrence is tested with `this` bound to each - value. When the field itself is a list or object, `this` follows the same - structure (including all decendants selected in case of objects). - - For any given path, if an ancestor is `null` or `[]`, the field will not be - reached and the CEL evaluation will be skipped for that path. In other words, - evaluation only takes place when `this` is `null` or non-null, but never - undefined. (See also the `optional` argument.) - """ - expr: Boolean_Expr! = "!(this in [null, []])" - """ - The error message to return to the client if the check fails. - - Defaults to "permission denied" if not specified. - """ - message: String! = "permission denied" - """ - Whether the check should pass or fail (default) when the field is not present. - - A field will not be reached at a given path if its parent or any ancestor is - `[]` or `null`. When this happens to all paths, the field will not be present - anywhere in the response tree. In other words, `expr` is evaluated 0 times. - By default, @check will automatically fail in this case. Set this argument to - `true` to make it pass even if no tests are run (a.k.a. "vacuously true"). - """ - optional: Boolean = false -) repeatable on QUERY | MUTATION | FIELD | FRAGMENT_DEFINITION | FRAGMENT_SPREAD | INLINE_FRAGMENT - -type Mutation { - """ - Run a query during the mutation and add fields into the response. - - Example: foo: query { users { id } } will add a field foo: {users: [{id: "..."}, …]} into the response JSON. - - Note: Data fetched this way can be handy for permission checks. See @check. - """ - query: Query -} - From 19ae2b7a931728d199ed08661d11455a04eb45a6 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 14 Nov 2024 15:24:56 -0800 Subject: [PATCH 06/17] Updated firebase.json --- dataconnect/.gitignore | 2 ++ dataconnect/firebase.json | 52 ++------------------------------------- dataconnect/lib/main.dart | 6 ----- 3 files changed, 4 insertions(+), 56 deletions(-) diff --git a/dataconnect/.gitignore b/dataconnect/.gitignore index 29a3a501..5b1e3843 100644 --- a/dataconnect/.gitignore +++ b/dataconnect/.gitignore @@ -41,3 +41,5 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +/lib/firebase_options.dart diff --git a/dataconnect/firebase.json b/dataconnect/firebase.json index 387ff483..958f35d4 100644 --- a/dataconnect/firebase.json +++ b/dataconnect/firebase.json @@ -1,52 +1,4 @@ { - "flutter": { - "platforms": { - "android": { - "default": { - "projectId": "quickstart-flutter-cc624", - "appId": "1:731568610039:android:2fda8b27330be9447251f2", - "fileOutput": "android/app/google-services.json" - } - }, - "ios": { - "default": { - "projectId": "quickstart-flutter-cc624", - "appId": "1:731568610039:ios:e78b43f1d75a77d87251f2", - "uploadDebugSymbols": false, - "fileOutput": "ios/Runner/GoogleService-Info.plist" - } - }, - "dart": { - "lib/firebase_options.dart": { - "projectId": "quickstart-flutter-cc624", - "configurations": { - "android": "1:731568610039:android:2fda8b27330be9447251f2", - "ios": "1:731568610039:ios:e78b43f1d75a77d87251f2", - "macos": "1:731568610039:ios:e78b43f1d75a77d87251f2", - "web": "1:731568610039:web:2896847d0f5655fb7251f2", - "windows": "1:731568610039:web:3c1e404f955f0b467251f2" - } - } - }, - "macos": { - "default": { - "projectId": "quickstart-flutter-cc624", - "appId": "1:731568610039:ios:e78b43f1d75a77d87251f2", - "uploadDebugSymbols": false, - "fileOutput": "macos/Runner/GoogleService-Info.plist" - } - } - } - }, - "dataconnect": { - "source": "dataconnect" - }, - "emulators": { - "dataconnect": { - "port": 9399 - }, - "auth": { - "port": 9400 - } - } + "dataconnect": { "source": "dataconnect" }, + "emulators": { "dataconnect": { "port": 9399 }, "auth": { "port": 9400 } } } diff --git a/dataconnect/lib/main.dart b/dataconnect/lib/main.dart index eb3e599a..ec7a4c86 100644 --- a/dataconnect/lib/main.dart +++ b/dataconnect/lib/main.dart @@ -79,12 +79,6 @@ class _MyHomePageState extends State { }); } - void _refreshData() { - // Gets the data, then notifies the subscriber(s) of the new data. - // TODO: Uncomment the following line to execute the query - // MoviesConnector.instance.listMovies.ref().build().execute(); - } - @override Widget build(BuildContext context) { return Scaffold( From d168b92094a2cd20f3852f0a70eeb654e7e8d784 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 15 Nov 2024 12:13:08 -0800 Subject: [PATCH 07/17] Cleaned up state --- .../dataconnect/connector/mutations.gql | 9 - dataconnect/dataconnect/connector/queries.gql | 26 - dataconnect/dataconnect/schema/schema.gql | 12 - dataconnect/firebase.json | 39 ++ dataconnect/lib/actor_detail.dart | 45 +- dataconnect/lib/destination.dart | 3 +- dataconnect/lib/extensions.dart | 49 -- dataconnect/lib/genre_list_movies.dart | 133 ----- dataconnect/lib/genre_page.dart | 63 -- dataconnect/lib/main.dart | 111 +--- dataconnect/lib/movie_detail.dart | 106 ++-- .../delete_favorited_actor.dart | 194 ------- .../delete_watched_movie.dart | 194 ------- .../movies_connector/get_current_user.dart | 547 ------------------ .../get_movie_info_for_user.dart | 72 --- .../lib/movies_connector/list_movies.dart | 508 +++++----------- dataconnect/lib/movies_connector/movies.dart | 14 - dataconnect/lib/profile.dart | 120 ++-- dataconnect/lib/router.dart | 38 +- dataconnect/lib/search.dart | 8 +- dataconnect/lib/util/auth.dart | 1 - dataconnect/lib/widgets/list_movies.dart | 7 +- dataconnect/pubspec.lock | 16 + dataconnect/pubspec.yaml | 1 + 24 files changed, 397 insertions(+), 1919 deletions(-) delete mode 100644 dataconnect/lib/extensions.dart delete mode 100644 dataconnect/lib/genre_list_movies.dart delete mode 100644 dataconnect/lib/genre_page.dart delete mode 100644 dataconnect/lib/movies_connector/delete_favorited_actor.dart delete mode 100644 dataconnect/lib/movies_connector/delete_watched_movie.dart diff --git a/dataconnect/dataconnect/connector/mutations.gql b/dataconnect/dataconnect/connector/mutations.gql index 1498eeb4..154aa982 100644 --- a/dataconnect/dataconnect/connector/mutations.gql +++ b/dataconnect/dataconnect/connector/mutations.gql @@ -13,20 +13,11 @@ mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) { favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId }) } - # Remove a movie from the user's favorites list mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) { favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId }) } -# Add a movie to the user's favorites list -mutation DeleteFavoritedActor($actorId: UUID!) @auth(level: USER) { - favorite_actor_delete(key: { userId_expr: "auth.uid", actorId: $actorId }) -} -mutation DeleteWatchedMovie($movieId: UUID!) @auth(level: USER) { - watched_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId }) -} - # Add a review for a movie mutation AddReview($movieId: UUID!, $rating: Int!, $reviewText: String!) @auth(level: USER) { diff --git a/dataconnect/dataconnect/connector/queries.gql b/dataconnect/dataconnect/connector/queries.gql index cd54b43d..af2e834d 100644 --- a/dataconnect/dataconnect/connector/queries.gql +++ b/dataconnect/dataconnect/connector/queries.gql @@ -140,29 +140,6 @@ query GetCurrentUser @auth(level: USER) { } } } - favoriteActors: favorite_actors_on_user { - actor { - id - name - imageUrl - } - } - watchedMovies: watched_movies_on_user { - movie { - id - title - genre - imageUrl - releaseYear - rating - description - tags - metadata: movieMetadatas_on_movie { - director - } - } - } - } } @@ -170,9 +147,6 @@ query GetMovieInfoForUser($movieId: UUID!) @auth(level: USER) { favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) { movieId } - watched_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) { - movieId - } } diff --git a/dataconnect/dataconnect/schema/schema.gql b/dataconnect/dataconnect/schema/schema.gql index 444ccfbb..7558ee21 100644 --- a/dataconnect/dataconnect/schema/schema.gql +++ b/dataconnect/dataconnect/schema/schema.gql @@ -94,15 +94,3 @@ type FavoriteMovie user: User! movie: Movie! } -type FavoriteActor - @table(name: "FavoriteActors", singular: "favorite_actor", plural: "favorite_actors", key: ["user", "actor"]) { - # @ref is implicit - user: User! - actor: Actor! -} -type WatchedMovie - @table(name: "WatchedMovies", singular: "watched_movie", plural: "watched_movies", key: ["user", "movie"]) { - # @ref is implicit - user: User! - movie: Movie! -} \ No newline at end of file diff --git a/dataconnect/firebase.json b/dataconnect/firebase.json index 958f35d4..00106af8 100644 --- a/dataconnect/firebase.json +++ b/dataconnect/firebase.json @@ -1,4 +1,43 @@ { + "flutter": { + "platforms": { + "android": { + "default": { + "projectId": "quickstart-flutter-cc624", + "appId": "1:731568610039:android:2fda8b27330be9447251f2", + "fileOutput": "android/app/google-services.json" + } + }, + "ios": { + "default": { + "projectId": "quickstart-flutter-cc624", + "appId": "1:731568610039:ios:e78b43f1d75a77d87251f2", + "uploadDebugSymbols": false, + "fileOutput": "ios/Runner/GoogleService-Info.plist" + } + }, + "dart": { + "lib/firebase_options.dart": { + "projectId": "quickstart-flutter-cc624", + "configurations": { + "android": "1:731568610039:android:2fda8b27330be9447251f2", + "ios": "1:731568610039:ios:e78b43f1d75a77d87251f2", + "macos": "1:731568610039:ios:e78b43f1d75a77d87251f2", + "web": "1:731568610039:web:2896847d0f5655fb7251f2", + "windows": "1:731568610039:web:3c1e404f955f0b467251f2" + } + } + }, + "macos": { + "default": { + "projectId": "quickstart-flutter-cc624", + "appId": "1:731568610039:ios:e78b43f1d75a77d87251f2", + "uploadDebugSymbols": false, + "fileOutput": "macos/Runner/GoogleService-Info.plist" + } + } + } + }, "dataconnect": { "source": "dataconnect" }, "emulators": { "dataconnect": { "port": 9399 }, "auth": { "port": 9400 } } } diff --git a/dataconnect/lib/actor_detail.dart b/dataconnect/lib/actor_detail.dart index c39837a3..d93a6536 100644 --- a/dataconnect/lib/actor_detail.dart +++ b/dataconnect/lib/actor_detail.dart @@ -1,4 +1,6 @@ +import 'package:dataconnect/movie_state.dart'; import 'package:dataconnect/movies_connector/movies.dart'; +import 'package:dataconnect/widgets/list_movies.dart'; import 'package:flutter/material.dart'; class ActorDetail extends StatefulWidget { @@ -16,10 +18,8 @@ class _ActorDetailState extends State { @override void initState() { super.initState(); - MoviesConnector.instance - .getActorById(id: widget.actorId) - .execute() - .then((value) { + + MovieState.getActorById(widget.actorId).then((value) { setState(() { loading = false; actor = value.data.actor; @@ -50,28 +50,23 @@ class _ActorDetailState extends State { ), ), ), - Expanded( - child: Padding( - padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), - // child: Column(children: [Text(actor!.info!)]), - )) ]), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - // TODO(mtewani): Check if the movie has been watched by the user - OutlinedButton.icon( - onPressed: () { - // TODO(mtewani): Check if user is logged in. - }, - icon: const Icon(Icons.favorite), - label: const Text('Add To Favorites'), - ) - ], - ) ]; } + Widget _buildMainRoles() { + return ListMovies( + movies: MovieState.convertMainActorDetail(actor!.mainActors), + title: "Main Roles"); + } + + Widget _buildSupportingRoles() { + return ListMovies( + movies: + MovieState.convertSupportingActorDetail(actor!.supportingActors), + title: "Supporting Roles"); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -86,7 +81,11 @@ class _ActorDetailState extends State { padding: const EdgeInsets.all(30), child: SingleChildScrollView( child: Column( - children: [..._buildActorInfo()], + children: [ + ..._buildActorInfo(), + _buildMainRoles(), + _buildSupportingRoles() + ], )))), ); } diff --git a/dataconnect/lib/destination.dart b/dataconnect/lib/destination.dart index f3d04d4e..54b60147 100644 --- a/dataconnect/lib/destination.dart +++ b/dataconnect/lib/destination.dart @@ -14,9 +14,8 @@ class Route { } var homePath = Route(path: '/home', label: 'Home', iconData: Icons.home); -var genrePath = Route(path: '/genres', label: 'Genres', iconData: Icons.list); var searchPath = Route(path: '/search', label: 'Search', iconData: Icons.search); var profilePath = Route(path: '/profile', label: 'Profile', iconData: Icons.person); -var paths = [homePath, genrePath, searchPath, profilePath]; +var paths = [homePath, searchPath, profilePath]; diff --git a/dataconnect/lib/extensions.dart b/dataconnect/lib/extensions.dart deleted file mode 100644 index 490ea227..00000000 --- a/dataconnect/lib/extensions.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'movies_connector/movies.dart'; - -extension GetCurrentUserUserFavoriteMoviesMovieExtension - on GetCurrentUserUserFavoriteMoviesMovie { - ListMoviesMovies get toListMoviesMovies => ListMoviesMovies( - id: id, - title: title, - imageUrl: imageUrl, - description: description, - genre: genre, - rating: rating, - releaseYear: releaseYear, - tags: tags); -} - -extension GetCurrentUserUserWatchedMoviesMovieExtension - on GetCurrentUserUserWatchedMoviesMovie { - ListMoviesMovies get toListMoviesMovies => ListMoviesMovies( - id: id, - title: title, - imageUrl: imageUrl, - description: description, - genre: genre, - rating: rating, - releaseYear: releaseYear, - tags: tags); -} - -extension SearchAllMoviesMatchingTitleExtension - on SearchAllMoviesMatchingTitle { - ListMoviesMovies get toListMoviesMovies => ListMoviesMovies( - id: id, - title: title, - imageUrl: imageUrl, - genre: genre, - rating: rating, - ); -} - -extension SearchAllMoviesMatchingDescriptionExtension - on SearchAllMoviesMatchingDescription { - ListMoviesMovies get toListMoviesMovies => ListMoviesMovies( - id: id, - title: title, - imageUrl: imageUrl, - genre: genre, - rating: rating, - ); -} diff --git a/dataconnect/lib/genre_list_movies.dart b/dataconnect/lib/genre_list_movies.dart deleted file mode 100644 index db43fb05..00000000 --- a/dataconnect/lib/genre_list_movies.dart +++ /dev/null @@ -1,133 +0,0 @@ -import 'package:dataconnect/movies_connector/movies.dart'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; - -class GenreListMovies extends StatefulWidget { - const GenreListMovies({super.key, required this.genre}); - final String genre; - - @override - State createState() => _GenreListMoviesState(); -} - -class _GenreListMoviesState extends State { - bool loading = true; - List _mostPopular = []; - List _mostRecent = []; - - void _visitDetail(String id) { - context.push("/movies/$id"); - } - - Widget _buildMovieList(String title, List movies) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - title, - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - ), - SizedBox( - height: 300, // Adjust the height as needed - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: movies.length, - itemBuilder: (context, index) { - return _buildMovieItem(movies[index]); - }, - ), - ), - ], - ); - } - - Widget _buildMovieItem(ListMoviesByGenreMovies movie) { - return Container( - width: 150, // Adjust the width as needed - padding: const EdgeInsets.all(4.0), - child: Card( - child: InkWell( - onTap: () { - _visitDetail(movie.id); - }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: 9 / 16, // 9:16 aspect ratio for the image - child: Image.network( - movie.imageUrl, - fit: BoxFit.cover, - ), - ), - const SizedBox(height: 8), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - movie.title, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ), - ], - )), - ), - ); - } - - @override - void initState() { - super.initState(); - String genre = widget.genre; - MoviesConnector.instance - .listMoviesByGenre(genre: genre) - .orderByRating(OrderDirection.DESC) - .limit(10) - .execute() - .then((res) { - setState(() { - _mostPopular = res.data.movies; - }); - }); - - MoviesConnector.instance - .listMoviesByGenre(genre: genre) - .orderByReleaseYear(OrderDirection.DESC) - .execute() - .then((res) { - setState(() { - _mostRecent = res.data.movies; - }); - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: _mostPopular.isEmpty && _mostRecent.isEmpty - ? const Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [CircularProgressIndicator()], - ) - : SingleChildScrollView( - padding: const EdgeInsets.all(30), - child: Column( - children: [ - Text( - "${widget.genre} Movies", - style: const TextStyle( - fontSize: 20, fontWeight: FontWeight.bold), - ), - _buildMovieList("Most Popular", _mostPopular), - _buildMovieList("Most Recent", _mostRecent) - ], - ), - )), - ); - } -} diff --git a/dataconnect/lib/genre_page.dart b/dataconnect/lib/genre_page.dart deleted file mode 100644 index 7838e404..00000000 --- a/dataconnect/lib/genre_page.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:dataconnect/movies_connector/movies.dart'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; - -class GenrePage extends StatefulWidget { - const GenrePage({super.key}); - - @override - State createState() => _GenrePageState(); -} - -class _GenrePageState extends State { - List genres = []; - bool loading = true; - @override - void initState() { - super.initState(); - MoviesConnector.instance.listGenres().execute().then((genres) { - setState(() { - loading = false; - this.genres = - genres.data.genres.map((genreData) => genreData.genre!).toList(); - }); - }); - } - - Widget _buildGenreList() { - return ListView.builder( - itemBuilder: (context, index) { - String genre = genres[index]; - return ListTile( - title: TextButton( - child: Text(genre, style: TextStyle(fontSize: 30)), - onPressed: () { - context.push('/genres/${genre}'); - }, - ), - ); - }, - itemCount: genres.length, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: loading - ? const Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [CircularProgressIndicator()], - ) - : Padding( - padding: const EdgeInsets.all(30), child: _buildGenreList() - // ..._buildMainDescription(), - // _buildMainActorsList(), - // _buildSupportingActorsList(), - // ..._buildRatings() - )), - ); - } -} diff --git a/dataconnect/lib/main.dart b/dataconnect/lib/main.dart index ec7a4c86..716bbe05 100644 --- a/dataconnect/lib/main.dart +++ b/dataconnect/lib/main.dart @@ -1,8 +1,10 @@ +import 'package:dataconnect/models/movie.dart'; +import 'package:dataconnect/movie_state.dart'; import 'package:dataconnect/router.dart'; +import 'package:dataconnect/widgets/list_movies.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; -import 'package:go_router/go_router.dart'; import 'firebase_options.dart'; import 'movies_connector/movies.dart'; @@ -14,6 +16,7 @@ void main() async { MoviesConnector.instance.dataConnect .useDataConnectEmulator('localhost', 9399); FirebaseAuth.instance.useAuthEmulator('localhost', 9400); + runApp(const MyApp()); } @@ -33,15 +36,6 @@ class MyApp extends StatelessWidget { class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - @override State createState() => _MyHomePageState(); } @@ -54,25 +48,13 @@ class _MyHomePageState extends State { void initState() { super.initState(); - /// TODO: Uncomment the following lines to update the movies state when data - /// comes back from the server. - - MoviesConnector.instance - .listMovies() - .orderByRating(OrderDirection.DESC) - .limit(10) - .execute() - .then((res) { + MovieState.getTopTenMovies().then((res) { setState(() { _topMovies = res.data.movies; }); }); - MoviesConnector.instance - .listMovies() - .orderByReleaseYear(OrderDirection.DESC) - .execute() - .then((res) { + MovieState.getTopTenMovies().then((res) { setState(() { _latestMovies = res.data.movies; }); @@ -86,74 +68,25 @@ class _MyHomePageState extends State { child: SingleChildScrollView( child: Column( children: [ - _buildMovieList('Top 10 Movies', _topMovies), - _buildMovieList('Latest Movies', _latestMovies), + ListMovies( + title: 'Top 10 Movies', + movies: _topMovies + .map( + (e) => + Movie(id: e.id, title: e.title, imageUrl: e.imageUrl), + ) + .toList()), + ListMovies( + title: 'Latest Movies', + movies: _latestMovies + .map( + (e) => + Movie(id: e.id, title: e.title, imageUrl: e.imageUrl), + ) + .toList()), ], ), )), ); } - - Widget _buildMovieList(String title, List movies) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - title, - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - ), - SizedBox( - height: 300, // Adjust the height as needed - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: movies.length, - itemBuilder: (context, index) { - return _buildMovieItem(movies[index]); - }, - ), - ), - ], - ); - } - - void _visitDetail(String id) { - context.push("/movies/$id"); - } - - Widget _buildMovieItem(ListMoviesMovies movie) { - return Container( - width: 150, // Adjust the width as needed - padding: const EdgeInsets.all(4.0), - child: Card( - child: InkWell( - onTap: () { - _visitDetail(movie.id); - }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: 9 / 16, // 9:16 aspect ratio for the image - child: Image.network( - movie.imageUrl, - fit: BoxFit.cover, - ), - ), - const SizedBox(height: 8), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - movie.title, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ), - ], - )), - ), - ); - } } diff --git a/dataconnect/lib/movie_detail.dart b/dataconnect/lib/movie_detail.dart index 8034f80d..097aac1f 100644 --- a/dataconnect/lib/movie_detail.dart +++ b/dataconnect/lib/movie_detail.dart @@ -1,3 +1,4 @@ +import 'package:dataconnect/movie_state.dart'; import 'package:dataconnect/movies_connector/movies.dart'; import 'package:dataconnect/widgets/login_guard.dart'; import 'package:flutter/material.dart'; @@ -15,41 +16,47 @@ class MovieDetail extends StatefulWidget { class _MovieDetailState extends State { double _ratingValue = 0; - String _reviewText = ""; bool loading = true; GetMovieByIdData? data; - bool _watched = false; bool _favorited = false; - TextEditingController _reviewTextController = TextEditingController(); + final TextEditingController _reviewTextController = TextEditingController(); @override void initState() { super.initState(); - MoviesConnector.instance - .getMovieById(id: widget.id) - .ref() - .subscribe() - .listen((value) { - setState(() { - loading = false; - data = value.data; - }); + + MovieState.subscribeToMovieById(widget.id).listen((value) { + if (mounted) { + setState(() { + loading = false; + data = value.data; + }); + } + }); + + MovieState.subscribeToGetMovieInfo(widget.id).listen((value) { + if (mounted) { + setState(() { + _favorited = value.data.favorite_movie != null; + }); + } }); - MoviesConnector.instance - .getMovieInfoForUser(movieId: widget.id) - .ref() - .subscribe() - .listen((value) { + } + + void _refreshData() { + MovieState.refreshMovieDetail(widget.id); + } + + void _toggleFavorite() { + MovieState.toggleFavorite(widget.id, _favorited).then((_) { setState(() { - _watched = value.data.watched_movie != null; - _favorited = value.data.favorite_movie != null; + _favorited = !_favorited; }); }); } - void _refreshData() { - MoviesConnector.instance.getMovieById(id: widget.id).execute(); - MoviesConnector.instance.getMovieInfoForUser(movieId: widget.id).execute(); + String _getFavoriteLabelText() { + return _favorited ? 'Remove From Favorites' : 'Add To Favorites'; } List _buildMainDescription() { @@ -91,7 +98,11 @@ class _MovieDetailState extends State { child: Column(children: [ Row( children: movie.tags!.map((tag) { - return TextButton(onPressed: () {}, child: Text(tag)); + return Chip( + label: Text( + tag, + overflow: TextOverflow.ellipsis, + )); }).toList(), ), Text(movie.description!) @@ -104,41 +115,10 @@ class _MovieDetailState extends State { LoginGuard( widgetToGuard: OutlinedButton.icon( onPressed: () { - (_watched - ? MoviesConnector.instance - .deleteFavoritedMovie(movieId: widget.id) - .execute() - : MoviesConnector.instance - .addFavoritedMovie(movieId: widget.id) - .execute()) - .then( - (value) => setState(() { - _watched = !_watched; - }), - ); - }, - icon: Icon( - _watched ? Icons.check_circle : Icons.check_circle_outline), - label: const Text('Watched'), - )), - LoginGuard( - widgetToGuard: OutlinedButton.icon( - onPressed: () { - (_favorited - ? MoviesConnector.instance - .deleteFavoritedMovie(movieId: widget.id) - .execute() - : MoviesConnector.instance - .addFavoritedMovie(movieId: widget.id) - .execute()) - .then((value) { - setState(() { - _favorited = !_favorited; - }); - }); + _toggleFavorite(); }, icon: Icon(_favorited ? Icons.favorite : Icons.favorite_border), - label: const Text('Add To Favorites'), + label: Text(_getFavoriteLabelText()), )) ], ) @@ -174,8 +154,10 @@ class _MovieDetailState extends State { radius: 30, child: ClipOval(child: Image.network(actor.imageUrl))), - Text(actor - .name) // TODO(mtewani): Clip if there's not enough width + Text( + actor.name, + overflow: TextOverflow.ellipsis, + ) ]); }, itemCount: data!.movie!.mainActors.length, @@ -210,8 +192,10 @@ class _MovieDetailState extends State { radius: 30, child: ClipOval( child: Image.network(actor.imageUrl))), - Text(actor - .name) // TODO(mtewani): Clip if there's not enough width + Text( + actor.name, + overflow: TextOverflow.ellipsis, + ) ]), onTap: () { _visitActorDetail(actor.id); @@ -251,7 +235,6 @@ class _MovieDetailState extends State { LoginGuard( widgetToGuard: OutlinedButton.icon( onPressed: () { - // TODO(mtewani): Check if user is logged in. MoviesConnector.instance .addReview( movieId: widget.id, @@ -261,6 +244,7 @@ class _MovieDetailState extends State { .then((_) { _refreshData(); _reviewTextController.clear(); + MovieState.triggerUpdateFavorite(); }); }, label: const Text('Submit Review'), diff --git a/dataconnect/lib/movies_connector/delete_favorited_actor.dart b/dataconnect/lib/movies_connector/delete_favorited_actor.dart deleted file mode 100644 index ca0d48a8..00000000 --- a/dataconnect/lib/movies_connector/delete_favorited_actor.dart +++ /dev/null @@ -1,194 +0,0 @@ -part of movies_connector; - -class DeleteFavoritedActorVariablesBuilder { - String actorId; - - - FirebaseDataConnect _dataConnect; - - DeleteFavoritedActorVariablesBuilder(this._dataConnect, {required String this.actorId,}); - Deserializer dataDeserializer = (dynamic json) => DeleteFavoritedActorData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (DeleteFavoritedActorVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - MutationRef ref() { - DeleteFavoritedActorVariables vars=DeleteFavoritedActorVariables(actorId: actorId,); - - return _dataConnect.mutation("DeleteFavoritedActor", dataDeserializer, varsSerializer, vars); - } -} - - - class DeleteFavoritedActorFavoriteActorDelete { - - String userId; - - - String actorId; - - - - - - - DeleteFavoritedActorFavoriteActorDelete.fromJson(dynamic json): - userId = - - nativeFromJson(json['userId']) - - - - , - - actorId = - - nativeFromJson(json['actorId']) - - - - - { - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['userId'] = - - nativeToJson(userId) - -; - - - - json['actorId'] = - - nativeToJson(actorId) - -; - - - return json; - } - - DeleteFavoritedActorFavoriteActorDelete({ - - required this.userId, - - required this.actorId, - - }); -} - - - - class DeleteFavoritedActorData { - - DeleteFavoritedActorFavoriteActorDelete? favorite_actor_delete; - - - - - - - DeleteFavoritedActorData.fromJson(dynamic json): - favorite_actor_delete = json['favorite_actor_delete'] == null ? null : - - DeleteFavoritedActorFavoriteActorDelete.fromJson(json['favorite_actor_delete']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (favorite_actor_delete != null) { - json['favorite_actor_delete'] = - - favorite_actor_delete!.toJson() - -; - } - - - return json; - } - - DeleteFavoritedActorData({ - - this.favorite_actor_delete, - - }); -} - - - - class DeleteFavoritedActorVariables { - - String actorId; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - DeleteFavoritedActorVariables.fromJson(Map json): - actorId = - - nativeFromJson(json['actorId']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['actorId'] = - - nativeToJson(actorId) - -; - - - return json; - } - - DeleteFavoritedActorVariables({ - - required this.actorId, - - }); -} - - - - - - - diff --git a/dataconnect/lib/movies_connector/delete_watched_movie.dart b/dataconnect/lib/movies_connector/delete_watched_movie.dart deleted file mode 100644 index 6c9ae830..00000000 --- a/dataconnect/lib/movies_connector/delete_watched_movie.dart +++ /dev/null @@ -1,194 +0,0 @@ -part of movies_connector; - -class DeleteWatchedMovieVariablesBuilder { - String movieId; - - - FirebaseDataConnect _dataConnect; - - DeleteWatchedMovieVariablesBuilder(this._dataConnect, {required String this.movieId,}); - Deserializer dataDeserializer = (dynamic json) => DeleteWatchedMovieData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (DeleteWatchedMovieVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return this.ref().execute(); - } - MutationRef ref() { - DeleteWatchedMovieVariables vars=DeleteWatchedMovieVariables(movieId: movieId,); - - return _dataConnect.mutation("DeleteWatchedMovie", dataDeserializer, varsSerializer, vars); - } -} - - - class DeleteWatchedMovieWatchedMovieDelete { - - String userId; - - - String movieId; - - - - - - - DeleteWatchedMovieWatchedMovieDelete.fromJson(dynamic json): - userId = - - nativeFromJson(json['userId']) - - - - , - - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['userId'] = - - nativeToJson(userId) - -; - - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - DeleteWatchedMovieWatchedMovieDelete({ - - required this.userId, - - required this.movieId, - - }); -} - - - - class DeleteWatchedMovieData { - - DeleteWatchedMovieWatchedMovieDelete? watched_movie_delete; - - - - - - - DeleteWatchedMovieData.fromJson(dynamic json): - watched_movie_delete = json['watched_movie_delete'] == null ? null : - - DeleteWatchedMovieWatchedMovieDelete.fromJson(json['watched_movie_delete']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (watched_movie_delete != null) { - json['watched_movie_delete'] = - - watched_movie_delete!.toJson() - -; - } - - - return json; - } - - DeleteWatchedMovieData({ - - this.watched_movie_delete, - - }); -} - - - - class DeleteWatchedMovieVariables { - - String movieId; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - DeleteWatchedMovieVariables.fromJson(Map json): - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - DeleteWatchedMovieVariables({ - - required this.movieId, - - }); -} - - - - - - - diff --git a/dataconnect/lib/movies_connector/get_current_user.dart b/dataconnect/lib/movies_connector/get_current_user.dart index d319c1f0..ae593861 100644 --- a/dataconnect/lib/movies_connector/get_current_user.dart +++ b/dataconnect/lib/movies_connector/get_current_user.dart @@ -35,12 +35,6 @@ class GetCurrentUserVariablesBuilder { List favoriteMovies; - List favoriteActors; - - - List watchedMovies; - - @@ -92,30 +86,6 @@ class GetCurrentUserVariablesBuilder { - , - - favoriteActors = - - - (json['favoriteActors'] as List) - .map((e) => GetCurrentUserUserFavoriteActors.fromJson(e)) - .toList() - - - - - , - - watchedMovies = - - - (json['watchedMovies'] as List) - .map((e) => GetCurrentUserUserWatchedMovies.fromJson(e)) - .toList() - - - - { @@ -129,10 +99,6 @@ class GetCurrentUserVariablesBuilder { - - - - } @@ -180,26 +146,6 @@ class GetCurrentUserVariablesBuilder { favoriteMovies.map((e) => e.toJson()).toList() -; - - - - json['favoriteActors'] = - - - favoriteActors.map((e) => e.toJson()).toList() - - -; - - - - json['watchedMovies'] = - - - watchedMovies.map((e) => e.toJson()).toList() - - ; @@ -218,10 +164,6 @@ class GetCurrentUserVariablesBuilder { required this.favoriteMovies, - required this.favoriteActors, - - required this.watchedMovies, - }); } @@ -789,495 +731,6 @@ class GetCurrentUserVariablesBuilder { - class GetCurrentUserUserFavoriteActors { - - GetCurrentUserUserFavoriteActorsActor actor; - - - - - - - GetCurrentUserUserFavoriteActors.fromJson(dynamic json): - actor = - - GetCurrentUserUserFavoriteActorsActor.fromJson(json['actor']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['actor'] = - - actor.toJson() - -; - - - return json; - } - - GetCurrentUserUserFavoriteActors({ - - required this.actor, - - }); -} - - - - class GetCurrentUserUserFavoriteActorsActor { - - String id; - - - String name; - - - String imageUrl; - - - - - - - GetCurrentUserUserFavoriteActorsActor.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - name = - - nativeFromJson(json['name']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - - { - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['name'] = - - nativeToJson(name) - -; - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - return json; - } - - GetCurrentUserUserFavoriteActorsActor({ - - required this.id, - - required this.name, - - required this.imageUrl, - - }); -} - - - - class GetCurrentUserUserWatchedMovies { - - GetCurrentUserUserWatchedMoviesMovie movie; - - - - - - - GetCurrentUserUserWatchedMovies.fromJson(dynamic json): - movie = - - GetCurrentUserUserWatchedMoviesMovie.fromJson(json['movie']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['movie'] = - - movie.toJson() - -; - - - return json; - } - - GetCurrentUserUserWatchedMovies({ - - required this.movie, - - }); -} - - - - class GetCurrentUserUserWatchedMoviesMovie { - - String id; - - - String title; - - - String? genre; - - - String imageUrl; - - - int? releaseYear; - - - double? rating; - - - String? description; - - - List? tags; - - - List metadata; - - - - - - - GetCurrentUserUserWatchedMoviesMovie.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - title = - - nativeFromJson(json['title']) - - - - , - - genre = json['genre'] == null ? null : - - nativeFromJson(json['genre']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - , - - releaseYear = json['releaseYear'] == null ? null : - - nativeFromJson(json['releaseYear']) - - - - , - - rating = json['rating'] == null ? null : - - nativeFromJson(json['rating']) - - - - , - - description = json['description'] == null ? null : - - nativeFromJson(json['description']) - - - - , - - tags = json['tags'] == null ? null : - - - (json['tags'] as List) - .map((e) => nativeFromJson(e)) - .toList() - - - - - , - - metadata = - - - (json['metadata'] as List) - .map((e) => GetCurrentUserUserWatchedMoviesMovieMetadata.fromJson(e)) - .toList() - - - - - - { - - - - - - - - - - - - - - - - - - - - } - - - Map toJson() { - Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['title'] = - - nativeToJson(title) - -; - - - - if (genre != null) { - json['genre'] = - - nativeToJson(genre) - -; - } - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - - if (releaseYear != null) { - json['releaseYear'] = - - nativeToJson(releaseYear) - -; - } - - - - if (rating != null) { - json['rating'] = - - nativeToJson(rating) - -; - } - - - - if (description != null) { - json['description'] = - - nativeToJson(description) - -; - } - - - - if (tags != null) { - json['tags'] = - - - tags?.map((e) => nativeToJson(e)).toList() - - -; - } - - - - json['metadata'] = - - - metadata.map((e) => e.toJson()).toList() - - -; - - - return json; - } - - GetCurrentUserUserWatchedMoviesMovie({ - - required this.id, - - required this.title, - - this.genre, - - required this.imageUrl, - - this.releaseYear, - - this.rating, - - this.description, - - this.tags, - - required this.metadata, - - }); -} - - - - class GetCurrentUserUserWatchedMoviesMovieMetadata { - - String? director; - - - - - - - GetCurrentUserUserWatchedMoviesMovieMetadata.fromJson(dynamic json): - director = json['director'] == null ? null : - - nativeFromJson(json['director']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - if (director != null) { - json['director'] = - - nativeToJson(director) - -; - } - - - return json; - } - - GetCurrentUserUserWatchedMoviesMovieMetadata({ - - this.director, - - }); -} - - - class GetCurrentUserData { GetCurrentUserUser? user; diff --git a/dataconnect/lib/movies_connector/get_movie_info_for_user.dart b/dataconnect/lib/movies_connector/get_movie_info_for_user.dart index 272e49ea..753020d4 100644 --- a/dataconnect/lib/movies_connector/get_movie_info_for_user.dart +++ b/dataconnect/lib/movies_connector/get_movie_info_for_user.dart @@ -67,61 +67,11 @@ class GetMovieInfoForUserVariablesBuilder { - class GetMovieInfoForUserWatchedMovie { - - String movieId; - - - - - - - GetMovieInfoForUserWatchedMovie.fromJson(dynamic json): - movieId = - - nativeFromJson(json['movieId']) - - - - - { - - - - } - - - Map toJson() { - Map json = {}; - - - json['movieId'] = - - nativeToJson(movieId) - -; - - - return json; - } - - GetMovieInfoForUserWatchedMovie({ - - required this.movieId, - - }); -} - - - class GetMovieInfoForUserData { GetMovieInfoForUserFavoriteMovie? favorite_movie; - GetMovieInfoForUserWatchedMovie? watched_movie; - - @@ -133,21 +83,11 @@ class GetMovieInfoForUserVariablesBuilder { - , - - watched_movie = json['watched_movie'] == null ? null : - - GetMovieInfoForUserWatchedMovie.fromJson(json['watched_movie']) - - - { - - } @@ -164,16 +104,6 @@ class GetMovieInfoForUserVariablesBuilder { } - - if (watched_movie != null) { - json['watched_movie'] = - - watched_movie!.toJson() - -; - } - - return json; } @@ -181,8 +111,6 @@ class GetMovieInfoForUserVariablesBuilder { this.favorite_movie, - this.watched_movie, - }); } diff --git a/dataconnect/lib/movies_connector/list_movies.dart b/dataconnect/lib/movies_connector/list_movies.dart index 57399267..ae7998e8 100644 --- a/dataconnect/lib/movies_connector/list_movies.dart +++ b/dataconnect/lib/movies_connector/list_movies.dart @@ -1,403 +1,203 @@ part of movies_connector; class ListMoviesVariablesBuilder { - Optional _orderByRating = Optional.optional(orderDirectionDeserializer, enumSerializer); -Optional _orderByReleaseYear = Optional.optional(orderDirectionDeserializer, enumSerializer); -Optional _limit = Optional.optional(nativeFromJson, nativeToJson); + Optional _orderByRating = + Optional.optional(orderDirectionDeserializer, enumSerializer); + Optional _orderByReleaseYear = + Optional.optional(orderDirectionDeserializer, enumSerializer); + Optional _limit = Optional.optional(nativeFromJson, nativeToJson); - FirebaseDataConnect _dataConnect; ListMoviesVariablesBuilder orderByRating(OrderDirection? t) { -this._orderByRating.value = t; -return this; -} -ListMoviesVariablesBuilder orderByReleaseYear(OrderDirection? t) { -this._orderByReleaseYear.value = t; -return this; -} -ListMoviesVariablesBuilder limit(int? t) { -this._limit.value = t; -return this; -} + this._orderByRating.value = t; + return this; + } + + ListMoviesVariablesBuilder orderByReleaseYear(OrderDirection? t) { + this._orderByReleaseYear.value = t; + return this; + } + + ListMoviesVariablesBuilder limit(int? t) { + this._limit.value = t; + return this; + } - ListMoviesVariablesBuilder(this._dataConnect, ); - Deserializer dataDeserializer = (dynamic json) => ListMoviesData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (ListMoviesVariables vars) => jsonEncode(vars.toJson()); + ListMoviesVariablesBuilder( + this._dataConnect, + ); + Deserializer dataDeserializer = + (dynamic json) => ListMoviesData.fromJson(jsonDecode(json)); + Serializer varsSerializer = + (ListMoviesVariables vars) => jsonEncode(vars.toJson()); Future> execute() { return this.ref().execute(); } - QueryRef ref() { - ListMoviesVariables vars=ListMoviesVariables(orderByRating: _orderByRating,orderByReleaseYear: _orderByReleaseYear,limit: _limit,); - return _dataConnect.query("ListMovies", dataDeserializer, varsSerializer, vars); + QueryRef ref() { + ListMoviesVariables vars = ListMoviesVariables( + orderByRating: _orderByRating, + orderByReleaseYear: _orderByReleaseYear, + limit: _limit, + ); + + return _dataConnect.query( + "ListMovies", dataDeserializer, varsSerializer, vars); } } +class ListMoviesMovies { + String id; - class ListMoviesMovies { - - String id; - - - String title; - - - String imageUrl; - - - int? releaseYear; - - - String? genre; - - - double? rating; - - - List? tags; - - - String? description; - - - - - - - ListMoviesMovies.fromJson(dynamic json): - id = - - nativeFromJson(json['id']) - - - - , - - title = - - nativeFromJson(json['title']) - - - - , - - imageUrl = - - nativeFromJson(json['imageUrl']) - - - - , - - releaseYear = json['releaseYear'] == null ? null : - - nativeFromJson(json['releaseYear']) - - - - , - - genre = json['genre'] == null ? null : - - nativeFromJson(json['genre']) - - - - , - - rating = json['rating'] == null ? null : - - nativeFromJson(json['rating']) - - - - , - - tags = json['tags'] == null ? null : - - - (json['tags'] as List) - .map((e) => nativeFromJson(e)) - .toList() - - - - - , - - description = json['description'] == null ? null : - - nativeFromJson(json['description']) - - - - - { - - - - - - - - - - - - - - - - - - } + String title; + + String imageUrl; + + int? releaseYear; + + String? genre; + double? rating; + + List? tags; + + String? description; + + ListMoviesMovies.fromJson(dynamic json) + : id = nativeFromJson(json['id']), + title = nativeFromJson(json['title']), + imageUrl = nativeFromJson(json['imageUrl']), + releaseYear = json['releaseYear'] == null + ? null + : nativeFromJson(json['releaseYear']), + genre = json['genre'] == null + ? null + : nativeFromJson(json['genre']), + rating = json['rating'] == null + ? null + : nativeFromJson(json['rating']), + tags = json['tags'] == null + ? null + : (json['tags'] as List) + .map((e) => nativeFromJson(e)) + .toList(), + description = json['description'] == null + ? null + : nativeFromJson(json['description']) {} Map toJson() { Map json = {}; - - - json['id'] = - - nativeToJson(id) - -; - - - - json['title'] = - - nativeToJson(title) - -; - - - - json['imageUrl'] = - - nativeToJson(imageUrl) - -; - - - - if (releaseYear != null) { - json['releaseYear'] = - - nativeToJson(releaseYear) - -; - } - - - - if (genre != null) { - json['genre'] = - - nativeToJson(genre) - -; - } - - - - if (rating != null) { - json['rating'] = - - nativeToJson(rating) - -; - } - - - - if (tags != null) { - json['tags'] = - - - tags?.map((e) => nativeToJson(e)).toList() - - -; - } - - - - if (description != null) { - json['description'] = - - nativeToJson(description) - -; - } - - + + json['id'] = nativeToJson(id); + + json['title'] = nativeToJson(title); + + json['imageUrl'] = nativeToJson(imageUrl); + + if (releaseYear != null) { + json['releaseYear'] = nativeToJson(releaseYear); + } + + if (genre != null) { + json['genre'] = nativeToJson(genre); + } + + if (rating != null) { + json['rating'] = nativeToJson(rating); + } + + if (tags != null) { + json['tags'] = tags?.map((e) => nativeToJson(e)).toList(); + } + + if (description != null) { + json['description'] = nativeToJson(description); + } + return json; } ListMoviesMovies({ - - required this.id, - - required this.title, - - required this.imageUrl, - - this.releaseYear, - - this.genre, - - this.rating, - - this.tags, - - this.description, - + required this.id, + required this.title, + required this.imageUrl, + this.releaseYear, + this.genre, + this.rating, + this.tags, + this.description, }); } +class ListMoviesData { + List movies; - - class ListMoviesData { - - List movies; - - - - - - - ListMoviesData.fromJson(dynamic json): - movies = - - - (json['movies'] as List) - .map((e) => ListMoviesMovies.fromJson(e)) - .toList() - - - - - - { - - - - } - + ListMoviesData.fromJson(dynamic json) + : movies = (json['movies'] as List) + .map((e) => ListMoviesMovies.fromJson(e)) + .toList() {} Map toJson() { Map json = {}; - - - json['movies'] = - - - movies.map((e) => e.toJson()).toList() - - -; - - + + json['movies'] = movies.map((e) => e.toJson()).toList(); + return json; } ListMoviesData({ - - required this.movies, - + required this.movies, }); } +class ListMoviesVariables { + late Optional orderByRating; + late Optional orderByReleaseYear; - class ListMoviesVariables { - - late OptionalorderByRating; - - - late OptionalorderByReleaseYear; - - - late Optionallimit; - - - - - - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - - - ListMoviesVariables.fromJson(Map json) { - - - orderByRating = Optional.optional(orderDirectionDeserializer, enumSerializer); - orderByRating.value = json['orderByRating'] == null ? null : - - OrderDirection.values.byName(json['orderByRating']) - -; - - - - orderByReleaseYear = Optional.optional(orderDirectionDeserializer, enumSerializer); - orderByReleaseYear.value = json['orderByReleaseYear'] == null ? null : - - OrderDirection.values.byName(json['orderByReleaseYear']) - -; - - - - limit = Optional.optional(nativeFromJson, nativeToJson); - limit.value = json['limit'] == null ? null : - - nativeFromJson(json['limit']) - -; - - - } + late Optional limit; + + @Deprecated( + 'fromJson is deprecated for Variable classes as they are no longer required for deserialization.') + ListMoviesVariables.fromJson(Map json) { + orderByRating = + Optional.optional(orderDirectionDeserializer, enumSerializer); + orderByRating.value = json['orderByRating'] == null + ? null + : OrderDirection.values.byName(json['orderByRating']); + orderByReleaseYear = + Optional.optional(orderDirectionDeserializer, enumSerializer); + orderByReleaseYear.value = json['orderByReleaseYear'] == null + ? null + : OrderDirection.values.byName(json['orderByReleaseYear']); + + limit = Optional.optional(nativeFromJson, nativeToJson); + limit.value = + json['limit'] == null ? null : nativeFromJson(json['limit']); + } Map toJson() { Map json = {}; - - - if(orderByRating.state == OptionalState.set) { - json['orderByRating'] = orderByRating.toJson(); - } - - - - if(orderByReleaseYear.state == OptionalState.set) { - json['orderByReleaseYear'] = orderByReleaseYear.toJson(); - } - - - - if(limit.state == OptionalState.set) { - json['limit'] = limit.toJson(); - } - - + + if (orderByRating.state == OptionalState.set) { + json['orderByRating'] = orderByRating.toJson(); + } + + if (orderByReleaseYear.state == OptionalState.set) { + json['orderByReleaseYear'] = orderByReleaseYear.toJson(); + } + + if (limit.state == OptionalState.set) { + json['limit'] = limit.toJson(); + } + return json; } ListMoviesVariables({ - - required this.orderByRating, - - required this.orderByReleaseYear, - - required this.limit, - + required this.orderByRating, + required this.orderByReleaseYear, + required this.limit, }); } - - - - - - - diff --git a/dataconnect/lib/movies_connector/movies.dart b/dataconnect/lib/movies_connector/movies.dart index d0bbd1ea..efeb927f 100644 --- a/dataconnect/lib/movies_connector/movies.dart +++ b/dataconnect/lib/movies_connector/movies.dart @@ -8,10 +8,6 @@ part 'add_favorited_movie.dart'; part 'delete_favorited_movie.dart'; -part 'delete_favorited_actor.dart'; - -part 'delete_watched_movie.dart'; - part 'add_review.dart'; part 'update_review.dart'; @@ -75,16 +71,6 @@ class MoviesConnector { } - DeleteFavoritedActorVariablesBuilder deleteFavoritedActor ({required String actorId,}) { - return DeleteFavoritedActorVariablesBuilder(dataConnect, actorId: actorId,); - } - - - DeleteWatchedMovieVariablesBuilder deleteWatchedMovie ({required String movieId,}) { - return DeleteWatchedMovieVariablesBuilder(dataConnect, movieId: movieId,); - } - - AddReviewVariablesBuilder addReview ({required String movieId,required int rating,required String reviewText,}) { return AddReviewVariablesBuilder(dataConnect, movieId: movieId,rating: rating,reviewText: reviewText,); } diff --git a/dataconnect/lib/profile.dart b/dataconnect/lib/profile.dart index 14364f78..d7fb3c3e 100644 --- a/dataconnect/lib/profile.dart +++ b/dataconnect/lib/profile.dart @@ -1,11 +1,18 @@ -import 'package:dataconnect/extensions.dart'; -import 'package:dataconnect/main.dart'; +import 'dart:async'; + +import 'package:dataconnect/movie_state.dart'; +import 'package:dataconnect/models/movie.dart'; import 'package:dataconnect/movies_connector/movies.dart'; import 'package:dataconnect/util/auth.dart'; +import 'package:dataconnect/widgets/list_actors.dart'; import 'package:dataconnect/widgets/list_movies.dart'; +import 'package:dataconnect/widgets/list_reviews.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_data_connect/firebase_data_connect.dart'; import 'package:flutter/material.dart'; + import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; class Profile extends StatefulWidget { const Profile({super.key}); @@ -14,37 +21,52 @@ class Profile extends StatefulWidget { State createState() => _ProfileState(); } -class _ProfileState extends State { +class _ProfileState extends State + with WidgetsBindingObserver, RouteAware { User? _currentUser; List _favoriteMovies = []; - List _favoriteActors = []; - List _watchedMovies = []; + List _reviews = []; String? _displayName; + final RouteObserver routeObserver = RouteObserver(); + StreamSubscription>? _listener; + @override void initState() { super.initState(); Auth.getCurrentUser().then((user) { - setState(() { - _currentUser = user; - }); + if (mounted) { + setState(() { + _currentUser = user; + }); + } }); - MoviesConnector.instance.getCurrentUser().execute().then((res) { - setState(() { - _displayName = res.data.user!.name; - _favoriteMovies = - res.data.user!.favoriteMovies.map((e) => e.movie).toList(); - _favoriteActors = res.data.user!.favoriteActors; - _watchedMovies = - res.data.user!.watchedMovies.map((e) => e.movie).toList(); - }); + _listener = MovieState.subscribeToCurrentUser().listen((res) { + if (mounted) { + setState(() { + _displayName = res.data.user!.name; + _favoriteMovies = + res.data.user!.favoriteMovies.map((e) => e.movie).toList(); + _reviews = res.data.user!.reviews; + }); + } }); } + @override + void dispose() { + super.dispose(); + _listener?.cancel(); + } + + _refresh() { + MoviesConnector.instance.getCurrentUser().execute(); + } + Widget _UserInfo() { return Container( child: Column( children: [ - Text('Welcome back ${_currentUser!.displayName ?? ''}!'), + Text('Welcome back ${_displayName ?? ''}!'), TextButton( onPressed: () async { FirebaseAuth.instance.signOut(); @@ -64,30 +86,42 @@ class _ProfileState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [CircularProgressIndicator()], ) - : SingleChildScrollView( - child: Container( - padding: EdgeInsets.all(30), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _UserInfo(), - ListMovies( - title: "Watched Movies", - movies: _watchedMovies - .map( - (e) => e.toListMoviesMovies, - ) - .toList()), - ListMovies( - title: "Favorite Movies", - movies: _favoriteMovies - .map( - (e) => e.toListMoviesMovies, - ) - .toList()) - ], - ), - )); + : RefreshIndicator( + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: Container( + padding: EdgeInsets.all(30), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _UserInfo(), + ListMovies( + title: "Favorite Movies", + movies: _favoriteMovies + .map( + (e) => Movie( + id: e.id, + title: e.title, + imageUrl: e.imageUrl), + ) + .toList()), + ListReviews( + reviews: _reviews + .map( + (e) => Review( + reviewText: e.reviewText!, + rating: e.rating!, + username: _currentUser!.email!, + date: e.reviewDate), + ) + .toList(), + title: "Reviews"), + ], + ), + )), + onRefresh: () async { + await _refresh(); + }); } } diff --git a/dataconnect/lib/router.dart b/dataconnect/lib/router.dart index fbe1d0b1..00615dd7 100644 --- a/dataconnect/lib/router.dart +++ b/dataconnect/lib/router.dart @@ -2,12 +2,9 @@ import 'package:dataconnect/destination.dart'; import 'package:dataconnect/login.dart'; import 'package:dataconnect/profile.dart'; import 'package:dataconnect/search.dart'; -import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'actor_detail.dart'; -import 'genre_list_movies.dart'; -import 'genre_page.dart'; import 'main.dart'; import 'movie_detail.dart'; import 'navigation_shell.dart'; @@ -28,31 +25,18 @@ var router = GoRouter(initialLocation: homePath.path, routes: [ GoRoute( path: '/movies/:movieId', builder: (context, state) => - MovieDetail(id: state.pathParameters['movieId']!)) + MovieDetail(id: state.pathParameters['movieId']!)), + GoRoute( + path: "/actors", + redirect: (context, state) => + '/actors/${state.pathParameters['actorId']}', + routes: [ + GoRoute( + path: ":actorId", + builder: (context, state) => + ActorDetail(actorId: state.pathParameters['actorId']!)) + ]) ]), - StatefulShellBranch( - routes: [ - GoRoute( - path: genrePath.path, - builder: (context, state) => const GenrePage(), - ), - GoRoute( - path: "/genres/:genre", - builder: (context, state) => - GenreListMovies(genre: state.pathParameters['genre']!), - ), - GoRoute( - path: "/actors", - redirect: (context, state) => - '/actors/${state.pathParameters['actorId']}', - routes: [ - GoRoute( - path: ":actorId", - builder: (context, state) => ActorDetail( - actorId: state.pathParameters['actorId']!)) - ]) - ], - ), StatefulShellBranch(routes: [ GoRoute( path: "/search", diff --git a/dataconnect/lib/search.dart b/dataconnect/lib/search.dart index 342b771f..bc2d18c1 100644 --- a/dataconnect/lib/search.dart +++ b/dataconnect/lib/search.dart @@ -1,4 +1,4 @@ -import 'package:dataconnect/extensions.dart'; +import 'package:dataconnect/models/movie.dart'; import 'package:dataconnect/movies_connector/movies.dart'; import 'package:dataconnect/widgets/list_actors.dart'; import 'package:dataconnect/widgets/list_movies.dart'; @@ -226,12 +226,14 @@ class _SearchState extends State { style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30)), ListMovies( movies: _resultsMovieMatchingTitle - .map((e) => e.toListMoviesMovies) + .map((e) => + Movie(id: e.id, title: e.title, imageUrl: e.imageUrl)) .toList(), title: "Movies Matching Title"), ListMovies( movies: _resultsMovieMatchingDescription - .map((e) => e.toListMoviesMovies) + .map((e) => + Movie(id: e.id, title: e.title, imageUrl: e.imageUrl)) .toList(), title: "Movies Matching Description"), const Text('Results matching reviews', diff --git a/dataconnect/lib/util/auth.dart b/dataconnect/lib/util/auth.dart index 5935ce58..8c59b99c 100644 --- a/dataconnect/lib/util/auth.dart +++ b/dataconnect/lib/util/auth.dart @@ -8,7 +8,6 @@ class Auth { } try { String? idToken = await user.getIdToken(); - print(idToken); return idToken != null; } catch (_) { return false; diff --git a/dataconnect/lib/widgets/list_movies.dart b/dataconnect/lib/widgets/list_movies.dart index b9ac39a0..1936e30e 100644 --- a/dataconnect/lib/widgets/list_movies.dart +++ b/dataconnect/lib/widgets/list_movies.dart @@ -1,3 +1,4 @@ +import 'package:dataconnect/models/movie.dart'; import 'package:dataconnect/movies_connector/movies.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -5,14 +6,14 @@ import 'package:go_router/go_router.dart'; class ListMovies extends StatefulWidget { const ListMovies({super.key, required this.movies, required this.title}); - final List movies; + final List movies; final String title; @override State createState() => _ListMoviesState(); } class _ListMoviesState extends State { - Widget _buildMovieList(String title, List movies) { + Widget _buildMovieList(String title, List movies) { return Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -50,7 +51,7 @@ class _ListMoviesState extends State { context.push("/movies/$id"); } - Widget _buildMovieItem(ListMoviesMovies movie) { + Widget _buildMovieItem(Movie movie) { return Container( width: 150, // Adjust the width as needed padding: const EdgeInsets.all(4.0), diff --git a/dataconnect/pubspec.lock b/dataconnect/pubspec.lock index 54938821..593b72cc 100644 --- a/dataconnect/pubspec.lock +++ b/dataconnect/pubspec.lock @@ -328,6 +328,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.15.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" path: dependency: transitive description: @@ -352,6 +360,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" sky_engine: dependency: transitive description: flutter diff --git a/dataconnect/pubspec.yaml b/dataconnect/pubspec.yaml index 04c8f250..1cfcfc4b 100644 --- a/dataconnect/pubspec.yaml +++ b/dataconnect/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: go_router: ^14.5.0 intl: ^0.19.0 firebase_auth: ^5.3.3 + provider: ^6.1.2 dev_dependencies: flutter_test: From c35ca9430a02763cf318b98451c2b6ef16b6d8fc Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 15 Nov 2024 12:13:28 -0800 Subject: [PATCH 08/17] Added models --- dataconnect/lib/models/movie.dart | 6 ++ dataconnect/lib/movie_state.dart | 85 +++++++++++++++++++++++ dataconnect/lib/widgets/list_reviews.dart | 67 ++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 dataconnect/lib/models/movie.dart create mode 100644 dataconnect/lib/movie_state.dart create mode 100644 dataconnect/lib/widgets/list_reviews.dart diff --git a/dataconnect/lib/models/movie.dart b/dataconnect/lib/models/movie.dart new file mode 100644 index 00000000..dde70e72 --- /dev/null +++ b/dataconnect/lib/models/movie.dart @@ -0,0 +1,6 @@ +class Movie { + Movie({required this.id, required this.title, required this.imageUrl}); + String id; + String title; + String imageUrl; +} diff --git a/dataconnect/lib/movie_state.dart b/dataconnect/lib/movie_state.dart new file mode 100644 index 00000000..3be9cfb6 --- /dev/null +++ b/dataconnect/lib/movie_state.dart @@ -0,0 +1,85 @@ +import 'package:dataconnect/movies_connector/movies.dart'; +import 'package:firebase_data_connect/firebase_data_connect.dart'; + +import 'models/movie.dart'; + +class MovieState { + static void triggerUpdateFavorite() { + MoviesConnector.instance.getCurrentUser().execute(); + } + + static Future> + getTopTenMovies() { + return MoviesConnector.instance + .listMovies() + .orderByRating(OrderDirection.DESC) + .limit(10) + .execute(); + } + + static Future> + getLatestMovies() { + return MoviesConnector.instance + .listMovies() + .orderByReleaseYear(OrderDirection.DESC) + .execute(); + } + + static Stream> + subscribeToMovieById(String id) { + return MoviesConnector.instance.getMovieById(id: id).ref().subscribe(); + } + + static void refreshMovieDetail(String id) { + MoviesConnector.instance.getMovieById(id: id).execute(); + MoviesConnector.instance.getMovieInfoForUser(movieId: id).execute(); + } + + static Stream< + QueryResult> + subscribeToGetMovieInfo(String id) { + return MoviesConnector.instance + .getMovieInfoForUser(movieId: id) + .ref() + .subscribe(); + } + + static Future> + getActorById(String actorId) { + return MoviesConnector.instance.getActorById(id: actorId).execute(); + } + + static List convertMainActorDetail( + List actors) { + return actors + .map( + (e) => Movie(imageUrl: e.imageUrl, id: e.id, title: e.title), + ) + .toList(); + } + + static List convertSupportingActorDetail( + List actors) { + return actors + .map( + (e) => Movie(imageUrl: e.imageUrl, id: e.id, title: e.title), + ) + .toList(); + } + + static Stream> + subscribeToCurrentUser() { + return MoviesConnector.instance.getCurrentUser().ref().subscribe(); + } + + static Future toggleFavorite(String id, bool favorited) async { + if (favorited) { + await MoviesConnector.instance + .deleteFavoritedMovie(movieId: id) + .execute(); + } else { + await MoviesConnector.instance.addFavoritedMovie(movieId: id).execute(); + } + triggerUpdateFavorite(); + } +} diff --git a/dataconnect/lib/widgets/list_reviews.dart b/dataconnect/lib/widgets/list_reviews.dart new file mode 100644 index 00000000..41470418 --- /dev/null +++ b/dataconnect/lib/widgets/list_reviews.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class Review { + Review( + {required this.reviewText, + required this.rating, + required this.username, + required this.date}); + String reviewText; + int rating; + String username; + DateTime date; +} + +class ListReviews extends StatefulWidget { + const ListReviews({super.key, required this.reviews, required this.title}); + final List reviews; + final String title; + @override + State createState() => _ListReviewsState(); +} + +class _ListReviewsState extends State { + Widget _buildRatingList() { + List reviews = widget.reviews; + return SizedBox( + height: 125, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + var rating = reviews[index]; + return Card( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(rating.username), + Row( + children: [ + Text(DateFormat.yMMMd().format(rating.date)), + const SizedBox( + width: 10, + ), + Text("Rating ${rating.rating}") + ], + ), + Text(rating.reviewText!) + ], + )), + ); + }, + itemCount: reviews.length, + )); + + // return Expanded(child: Text('abc')); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [Text(widget.title), _buildRatingList()], + ); + } +} From fd4d783b41e4e287db12ee5bd915dff1f1d0f7c5 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 15 Nov 2024 14:02:56 -0800 Subject: [PATCH 09/17] Removed provider requirement --- dataconnect/lib/profile.dart | 6 ++---- dataconnect/pubspec.lock | 16 ---------------- dataconnect/pubspec.yaml | 1 - 3 files changed, 2 insertions(+), 21 deletions(-) diff --git a/dataconnect/lib/profile.dart b/dataconnect/lib/profile.dart index d7fb3c3e..1942d136 100644 --- a/dataconnect/lib/profile.dart +++ b/dataconnect/lib/profile.dart @@ -4,7 +4,6 @@ import 'package:dataconnect/movie_state.dart'; import 'package:dataconnect/models/movie.dart'; import 'package:dataconnect/movies_connector/movies.dart'; import 'package:dataconnect/util/auth.dart'; -import 'package:dataconnect/widgets/list_actors.dart'; import 'package:dataconnect/widgets/list_movies.dart'; import 'package:dataconnect/widgets/list_reviews.dart'; import 'package:firebase_auth/firebase_auth.dart'; @@ -12,7 +11,6 @@ import 'package:firebase_data_connect/firebase_data_connect.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:provider/provider.dart'; class Profile extends StatefulWidget { const Profile({super.key}); @@ -62,7 +60,7 @@ class _ProfileState extends State MoviesConnector.instance.getCurrentUser().execute(); } - Widget _UserInfo() { + Widget _buildUserInfo() { return Container( child: Column( children: [ @@ -95,7 +93,7 @@ class _ProfileState extends State mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - _UserInfo(), + _buildUserInfo(), ListMovies( title: "Favorite Movies", movies: _favoriteMovies diff --git a/dataconnect/pubspec.lock b/dataconnect/pubspec.lock index 593b72cc..54938821 100644 --- a/dataconnect/pubspec.lock +++ b/dataconnect/pubspec.lock @@ -328,14 +328,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.15.0" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" path: dependency: transitive description: @@ -360,14 +352,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" - provider: - dependency: "direct main" - description: - name: provider - sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c - url: "https://pub.dev" - source: hosted - version: "6.1.2" sky_engine: dependency: transitive description: flutter diff --git a/dataconnect/pubspec.yaml b/dataconnect/pubspec.yaml index 1cfcfc4b..04c8f250 100644 --- a/dataconnect/pubspec.yaml +++ b/dataconnect/pubspec.yaml @@ -40,7 +40,6 @@ dependencies: go_router: ^14.5.0 intl: ^0.19.0 firebase_auth: ^5.3.3 - provider: ^6.1.2 dev_dependencies: flutter_test: From 9a52d958cbdeee6b8fb3419049633a50a016a45e Mon Sep 17 00:00:00 2001 From: Rody Davis Date: Fri, 15 Nov 2024 14:57:11 -0800 Subject: [PATCH 10/17] Update list_actors.dart --- dataconnect/lib/widgets/list_actors.dart | 97 ++++++++++++------------ 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/dataconnect/lib/widgets/list_actors.dart b/dataconnect/lib/widgets/list_actors.dart index 47ea5dbd..51251934 100644 --- a/dataconnect/lib/widgets/list_actors.dart +++ b/dataconnect/lib/widgets/list_actors.dart @@ -1,64 +1,63 @@ import 'package:flutter/material.dart'; class Actor { - Actor({required this.imageUrl, required this.name, required this.id}); + Actor({ + required this.imageUrl, + required this.name, + required this.id, + }); String imageUrl; String name; String id; } -class ListActors extends StatefulWidget { - const ListActors({super.key, required this.actors, required this.title}); +class ListActors extends StatelessWidget { + const ListActors({ + super.key, + required this.actors, + required this.title, + }); final List actors; final String title; - @override - State createState() => _ListActorsState(); -} - -class _ListActorsState extends State { - _buildActor(Actor actor) { - return SizedBox( - width: 100, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - CircleAvatar( - radius: 30, - child: ClipOval(child: Image.network(actor.imageUrl))), - Text( - actor.name, - overflow: TextOverflow.ellipsis, - ) - ])); - } - - _buildActorsList() { - return SizedBox( - height: 125, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.title, - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - Expanded( - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - return _buildActor(widget.actors[index]); - }, - itemCount: widget.actors.length, - )) - ], - )); - } - @override Widget build(BuildContext context) { - return _buildActorsList(); + return SizedBox( + height: 125, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + Expanded( + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + final actor = actors[index]; + return SizedBox( + width: 100, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + CircleAvatar( + radius: 30, + child: ClipOval(child: Image.network(actor.imageUrl))), + Text( + actor.name, + overflow: TextOverflow.ellipsis, + ) + ], + ), + ); + }, + itemCount: actors.length, + )) + ], + ), + ); } } From 8ad4ed0f6b65dc10eb3444602b2d634e9f24c293 Mon Sep 17 00:00:00 2001 From: Rody Davis Date: Fri, 15 Nov 2024 15:09:44 -0800 Subject: [PATCH 11/17] updating widgets --- dataconnect/lib/actor_detail.dart | 147 ++++++++++------------ dataconnect/lib/login.dart | 145 ++++++++++----------- dataconnect/lib/main.dart | 40 +++--- dataconnect/lib/widgets/list_movies.dart | 98 +++++++-------- dataconnect/lib/widgets/list_reviews.dart | 94 +++++++------- dataconnect/lib/widgets/login_guard.dart | 49 ++++---- 6 files changed, 276 insertions(+), 297 deletions(-) diff --git a/dataconnect/lib/actor_detail.dart b/dataconnect/lib/actor_detail.dart index d93a6536..5bc6e8c4 100644 --- a/dataconnect/lib/actor_detail.dart +++ b/dataconnect/lib/actor_detail.dart @@ -1,92 +1,77 @@ -import 'package:dataconnect/movie_state.dart'; -import 'package:dataconnect/movies_connector/movies.dart'; -import 'package:dataconnect/widgets/list_movies.dart'; import 'package:flutter/material.dart'; -class ActorDetail extends StatefulWidget { - const ActorDetail({super.key, required this.actorId}); +import 'movie_state.dart'; +import 'widgets/list_movies.dart'; - final String actorId; +class ActorDetail extends StatelessWidget { + const ActorDetail({ + super.key, + required this.actorId, + }); - @override - State createState() => _ActorDetailState(); -} - -class _ActorDetailState extends State { - bool loading = true; - GetActorByIdActor? actor; - @override - void initState() { - super.initState(); - - MovieState.getActorById(widget.actorId).then((value) { - setState(() { - loading = false; - actor = value.data.actor; - }); - }); - } - - _buildActorInfo() { - return [ - Align( - alignment: Alignment.centerLeft, - child: Container( - child: Text( - actor!.name, - style: const TextStyle(fontSize: 30), - ), - )), - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: AspectRatio( - aspectRatio: 9 / 16, // 9:16 aspect ratio for the image - child: Image.network( - actor!.imageUrl, - fit: BoxFit.cover, - ), - ), - ), - ]), - ]; - } - - Widget _buildMainRoles() { - return ListMovies( - movies: MovieState.convertMainActorDetail(actor!.mainActors), - title: "Main Roles"); - } - - Widget _buildSupportingRoles() { - return ListMovies( - movies: - MovieState.convertSupportingActorDetail(actor!.supportingActors), - title: "Supporting Roles"); - } + final String actorId; @override Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: actor == null - ? const Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [CircularProgressIndicator()], - ) - : Padding( + return FutureBuilder( + future: MovieState.getActorById(actorId), + builder: (context, snapshot) { + final actor = snapshot.data?.data.actor; + final loading = snapshot.connectionState == ConnectionState.waiting; + return Scaffold( + body: SafeArea( + child: () { + if (actor == null || loading) { + return const Center( + child: CircularProgressIndicator(), + ); + } + return Padding( padding: const EdgeInsets.all(30), child: SingleChildScrollView( - child: Column( - children: [ - ..._buildActorInfo(), - _buildMainRoles(), - _buildSupportingRoles() - ], - )))), - ); + child: Column( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + actor.name, + style: const TextStyle(fontSize: 30), + )), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: AspectRatio( + aspectRatio: + 9 / 16, // 9:16 aspect ratio for the image + child: Image.network( + actor.imageUrl, + fit: BoxFit.cover, + ), + ), + ), + ], + ), + ListMovies( + movies: MovieState.convertMainActorDetail( + actor.mainActors, + ), + title: "Main Roles", + ), + ListMovies( + movies: MovieState.convertSupportingActorDetail( + actor.supportingActors, + ), + title: "Supporting Roles", + ), + ], + ), + ), + ); + }(), + ), + ); + }); } } diff --git a/dataconnect/lib/login.dart b/dataconnect/lib/login.dart index 97f6b3ba..66d52b05 100644 --- a/dataconnect/lib/login.dart +++ b/dataconnect/lib/login.dart @@ -1,4 +1,3 @@ -import 'package:dataconnect/movies_connector/movies.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -14,75 +13,24 @@ class _LoginState extends State { final _formKey = GlobalKey(); String _username = ''; String _password = ''; - Widget _buildForm() { - return Form( - key: _formKey, - child: Column( - children: [ - TextFormField( - decoration: const InputDecoration( - hintText: "Username", border: OutlineInputBorder()), - onChanged: (value) { - setState(() { - _username = value; - }); - }, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Please enter some text'; - } - return null; - }, - ), - const SizedBox(height: 30), - TextFormField( - obscureText: true, - autocorrect: false, - decoration: const InputDecoration( - hintText: "Password", border: OutlineInputBorder()), - onChanged: (value) { - setState(() { - _password = value; - }); - }, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Please enter a password'; - } - return null; - }, - ), - ElevatedButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - logIn(); - } - }, - child: const Text('Sign In')), - Text('Don\'t have an account?'), - ElevatedButton( - onPressed: () { - context.go('/signup'); - }, - child: const Text('Sign Up')), - ], - )); - } - - logIn() async { - ScaffoldMessenger.of(context) - .showSnackBar(const SnackBar(content: Text('Signing In'))); + Future logIn(BuildContext context) async { + final messenger = ScaffoldMessenger.of(context); + final navigator = GoRouter.of(context); + messenger.showSnackBar(const SnackBar(content: Text('Signing In'))); try { - await FirebaseAuth.instance - .signInWithEmailAndPassword(email: _username, password: _password); + await FirebaseAuth.instance.signInWithEmailAndPassword( + email: _username, + password: _password, + ); if (mounted) { - context.go('/home'); + navigator.go('/home'); } } catch (_) { if (mounted) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('There was an error when creating a user.'))); + messenger.showSnackBar(const SnackBar( + content: Text('There was an error when creating a user.'), + )); } } } @@ -91,13 +39,70 @@ class _LoginState extends State { Widget build(BuildContext context) { return Scaffold( body: SafeArea( - child: Padding( - padding: EdgeInsets.all(30), + child: Padding( + padding: const EdgeInsets.all(30), + child: Center( + child: Form( + key: _formKey, child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [_buildForm()], - ))), + children: [ + TextFormField( + decoration: const InputDecoration( + hintText: "Username", + border: OutlineInputBorder(), + ), + onChanged: (value) { + setState(() { + _username = value; + }); + }, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + return null; + }, + ), + const SizedBox(height: 30), + TextFormField( + obscureText: true, + autocorrect: false, + decoration: const InputDecoration( + hintText: "Password", + border: OutlineInputBorder(), + ), + onChanged: (value) { + setState(() { + _password = value; + }); + }, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter a password'; + } + return null; + }, + ), + ElevatedButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + logIn(context); + } + }, + child: const Text('Sign In')), + const Text("Don't have an account?"), + ElevatedButton( + onPressed: () { + context.go('/signup'); + }, + child: const Text('Sign Up'), + ), + ], + ), + ), + ), + ), + ), ); } } diff --git a/dataconnect/lib/main.dart b/dataconnect/lib/main.dart index 716bbe05..8038f3a7 100644 --- a/dataconnect/lib/main.dart +++ b/dataconnect/lib/main.dart @@ -1,12 +1,12 @@ -import 'package:dataconnect/models/movie.dart'; -import 'package:dataconnect/movie_state.dart'; -import 'package:dataconnect/router.dart'; -import 'package:dataconnect/widgets/list_movies.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'firebase_options.dart'; import 'movies_connector/movies.dart'; +import 'models/movie.dart'; +import 'movie_state.dart'; +import 'router.dart'; +import 'widgets/list_movies.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -69,21 +69,25 @@ class _MyHomePageState extends State { child: Column( children: [ ListMovies( - title: 'Top 10 Movies', - movies: _topMovies - .map( - (e) => - Movie(id: e.id, title: e.title, imageUrl: e.imageUrl), - ) - .toList()), + title: 'Top 10 Movies', + movies: _topMovies + .map((e) => Movie( + id: e.id, + title: e.title, + imageUrl: e.imageUrl, + )) + .toList(), + ), ListMovies( - title: 'Latest Movies', - movies: _latestMovies - .map( - (e) => - Movie(id: e.id, title: e.title, imageUrl: e.imageUrl), - ) - .toList()), + title: 'Latest Movies', + movies: _latestMovies + .map((e) => Movie( + id: e.id, + title: e.title, + imageUrl: e.imageUrl, + )) + .toList(), + ), ], ), )), diff --git a/dataconnect/lib/widgets/list_movies.dart b/dataconnect/lib/widgets/list_movies.dart index 1936e30e..bfa97042 100644 --- a/dataconnect/lib/widgets/list_movies.dart +++ b/dataconnect/lib/widgets/list_movies.dart @@ -1,19 +1,20 @@ -import 'package:dataconnect/models/movie.dart'; -import 'package:dataconnect/movies_connector/movies.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -class ListMovies extends StatefulWidget { - const ListMovies({super.key, required this.movies, required this.title}); +import '/models/movie.dart'; + +class ListMovies extends StatelessWidget { + const ListMovies({ + super.key, + required this.movies, + required this.title, + }); final List movies; final String title; - @override - State createState() => _ListMoviesState(); -} -class _ListMoviesState extends State { - Widget _buildMovieList(String title, List movies) { + @override + Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -39,54 +40,45 @@ class _ListMoviesState extends State { scrollDirection: Axis.horizontal, itemCount: movies.length, itemBuilder: (context, index) { - return _buildMovieItem(movies[index]); + final movie = movies[index]; + return Container( + width: 150, // Adjust the width as needed + padding: const EdgeInsets.all(4.0), + child: Card( + child: InkWell( + onTap: () { + context.push("/movies/${movie.id}"); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: + 9 / 16, // 9:16 aspect ratio for the image + child: Image.network( + movie.imageUrl, + fit: BoxFit.cover, + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + movie.title, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontWeight: FontWeight.bold), + ), + ), + ], + ), + ), + ), + ); }, ), ), ], ); } - - void _visitDetail(String id) { - context.push("/movies/$id"); - } - - Widget _buildMovieItem(Movie movie) { - return Container( - width: 150, // Adjust the width as needed - padding: const EdgeInsets.all(4.0), - child: Card( - child: InkWell( - onTap: () { - _visitDetail(movie.id); - }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: 9 / 16, // 9:16 aspect ratio for the image - child: Image.network( - movie.imageUrl, - fit: BoxFit.cover, - ), - ), - const SizedBox(height: 8), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - movie.title, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ), - ], - )), - ), - ); - } - - @override - Widget build(BuildContext context) { - return _buildMovieList(widget.title, widget.movies); - } } diff --git a/dataconnect/lib/widgets/list_reviews.dart b/dataconnect/lib/widgets/list_reviews.dart index 41470418..8188cbf9 100644 --- a/dataconnect/lib/widgets/list_reviews.dart +++ b/dataconnect/lib/widgets/list_reviews.dart @@ -2,66 +2,64 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; class Review { - Review( - {required this.reviewText, - required this.rating, - required this.username, - required this.date}); + Review({ + required this.reviewText, + required this.rating, + required this.username, + required this.date, + }); String reviewText; int rating; String username; DateTime date; } -class ListReviews extends StatefulWidget { - const ListReviews({super.key, required this.reviews, required this.title}); +class ListReviews extends StatelessWidget { + const ListReviews({ + super.key, + required this.reviews, + required this.title, + }); final List reviews; final String title; - @override - State createState() => _ListReviewsState(); -} - -class _ListReviewsState extends State { - Widget _buildRatingList() { - List reviews = widget.reviews; - return SizedBox( - height: 125, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - var rating = reviews[index]; - return Card( - child: Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(rating.username), - Row( - children: [ - Text(DateFormat.yMMMd().format(rating.date)), - const SizedBox( - width: 10, - ), - Text("Rating ${rating.rating}") - ], - ), - Text(rating.reviewText!) - ], - )), - ); - }, - itemCount: reviews.length, - )); - - // return Expanded(child: Text('abc')); - } @override Widget build(BuildContext context) { return Column( - children: [Text(widget.title), _buildRatingList()], + children: [ + Text(title), + SizedBox( + height: 125, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + var rating = reviews[index]; + return Card( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(rating.username), + Row( + children: [ + Text(DateFormat.yMMMd().format(rating.date)), + const SizedBox( + width: 10, + ), + Text("Rating ${rating.rating}") + ], + ), + Text(rating.reviewText) + ], + )), + ); + }, + itemCount: reviews.length, + ), + ), + ], ); } } diff --git a/dataconnect/lib/widgets/login_guard.dart b/dataconnect/lib/widgets/login_guard.dart index 3072c4c4..27548993 100644 --- a/dataconnect/lib/widgets/login_guard.dart +++ b/dataconnect/lib/widgets/login_guard.dart @@ -1,38 +1,33 @@ import 'package:dataconnect/util/auth.dart'; import 'package:flutter/material.dart'; -class LoginGuard extends StatefulWidget { - const LoginGuard({super.key, required this.widgetToGuard, this.message}); +class LoginGuard extends StatelessWidget { + const LoginGuard({ + super.key, + required this.widgetToGuard, + this.message, + }); final Widget widgetToGuard; - final String? message; - @override - State createState() => _LoginGuardState(); -} - -class _LoginGuardState extends State { - bool isLoggedIn = false; - @override - void initState() { - super.initState(); - Auth.isLoggedIn().then((value) { - setState(() { - isLoggedIn = value; - }); - }); - } - @override Widget build(BuildContext context) { - if (isLoggedIn) { - return widget.widgetToGuard; - } - if (widget.message == null) { - return const SizedBox(); - } - return Text( - 'Please visit the Profile page to log in before ${widget.message}'); + return FutureBuilder( + future: Auth.isLoggedIn(), + builder: (context, state) { + final isLoggedIn = state.data ?? false; + if (!isLoggedIn) { + if (message == null) { + return const SizedBox(); + } + return Text( + 'Please visit the profile page' + 'to log in before $message', + ); + } + return widgetToGuard; + }, + ); } } From b8594b717e46de342b3484ee02800821f3fd389f Mon Sep 17 00:00:00 2001 From: Rody Davis Date: Fri, 15 Nov 2024 15:23:42 -0800 Subject: [PATCH 12/17] update widgets --- dataconnect/lib/destination.dart | 35 +++++++++++------ dataconnect/lib/login.dart | 20 +++------- dataconnect/lib/main.dart | 2 + dataconnect/lib/movie_detail.dart | 44 +++++++++++---------- dataconnect/lib/profile.dart | 7 ---- dataconnect/lib/router.dart | 4 +- dataconnect/lib/util/auth.dart | 50 ++++++++++++++++++------ dataconnect/lib/widgets/login_guard.dart | 14 +++---- 8 files changed, 100 insertions(+), 76 deletions(-) diff --git a/dataconnect/lib/destination.dart b/dataconnect/lib/destination.dart index 54b60147..83aceee2 100644 --- a/dataconnect/lib/destination.dart +++ b/dataconnect/lib/destination.dart @@ -1,21 +1,30 @@ import 'package:flutter/material.dart'; -class Destination { - const Destination({required this.label, required this.icon}); - final String label; - final IconData icon; -} - class Route { - Route({required this.path, required this.label, required this.iconData}); + Route({ + required this.path, + required this.label, + required this.iconData, + }); final String path; final String label; final IconData iconData; } -var homePath = Route(path: '/home', label: 'Home', iconData: Icons.home); -var searchPath = - Route(path: '/search', label: 'Search', iconData: Icons.search); -var profilePath = - Route(path: '/profile', label: 'Profile', iconData: Icons.person); -var paths = [homePath, searchPath, profilePath]; +final homePath = Route( + path: '/home', + label: 'Home', + iconData: Icons.home, +); +final searchPath = Route( + path: '/search', + label: 'Search', + iconData: Icons.search, +); +final profilePath = Route( + path: '/profile', + label: 'Profile', + iconData: Icons.person, +); + +final paths = [homePath, searchPath, profilePath]; diff --git a/dataconnect/lib/login.dart b/dataconnect/lib/login.dart index 66d52b05..1bfa1078 100644 --- a/dataconnect/lib/login.dart +++ b/dataconnect/lib/login.dart @@ -11,8 +11,8 @@ class Login extends StatefulWidget { class _LoginState extends State { final _formKey = GlobalKey(); - String _username = ''; - String _password = ''; + final _username = TextEditingController(); + final _password = TextEditingController(); Future logIn(BuildContext context) async { final messenger = ScaffoldMessenger.of(context); @@ -20,8 +20,8 @@ class _LoginState extends State { messenger.showSnackBar(const SnackBar(content: Text('Signing In'))); try { await FirebaseAuth.instance.signInWithEmailAndPassword( - email: _username, - password: _password, + email: _username.text, + password: _password.text, ); if (mounted) { navigator.go('/home'); @@ -51,11 +51,7 @@ class _LoginState extends State { hintText: "Username", border: OutlineInputBorder(), ), - onChanged: (value) { - setState(() { - _username = value; - }); - }, + controller: _username, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter some text'; @@ -71,11 +67,7 @@ class _LoginState extends State { hintText: "Password", border: OutlineInputBorder(), ), - onChanged: (value) { - setState(() { - _password = value; - }); - }, + controller: _password, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter a password'; diff --git a/dataconnect/lib/main.dart b/dataconnect/lib/main.dart index 8038f3a7..ac6d1720 100644 --- a/dataconnect/lib/main.dart +++ b/dataconnect/lib/main.dart @@ -6,6 +6,7 @@ import 'movies_connector/movies.dart'; import 'models/movie.dart'; import 'movie_state.dart'; import 'router.dart'; +import 'util/auth.dart'; import 'widgets/list_movies.dart'; void main() async { @@ -13,6 +14,7 @@ void main() async { await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); + await Auth.instance.init(); MoviesConnector.instance.dataConnect .useDataConnectEmulator('localhost', 9399); FirebaseAuth.instance.useAuthEmulator('localhost', 9400); diff --git a/dataconnect/lib/movie_detail.dart b/dataconnect/lib/movie_detail.dart index 097aac1f..b2db8ec7 100644 --- a/dataconnect/lib/movie_detail.dart +++ b/dataconnect/lib/movie_detail.dart @@ -113,13 +113,14 @@ class _MovieDetailState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ LoginGuard( - widgetToGuard: OutlinedButton.icon( - onPressed: () { - _toggleFavorite(); - }, - icon: Icon(_favorited ? Icons.favorite : Icons.favorite_border), - label: Text(_getFavoriteLabelText()), - )) + builder: (context) => OutlinedButton.icon( + onPressed: () { + _toggleFavorite(); + }, + icon: Icon(_favorited ? Icons.favorite : Icons.favorite_border), + label: Text(_getFavoriteLabelText()), + ), + ) ], ) ]; @@ -224,16 +225,17 @@ class _MovieDetailState extends State { }, ), LoginGuard( - widgetToGuard: TextField( - decoration: const InputDecoration( - hintText: "Write your review", - border: OutlineInputBorder(), - ), - controller: _reviewTextController, + builder: (context) => TextField( + decoration: const InputDecoration( + hintText: "Write your review", + border: OutlineInputBorder(), ), - message: "writing a review"), + controller: _reviewTextController, + ), + message: "writing a review", + ), LoginGuard( - widgetToGuard: OutlinedButton.icon( + builder: (context) => OutlinedButton.icon( onPressed: () { MoviesConnector.instance .addReview( @@ -241,11 +243,13 @@ class _MovieDetailState extends State { rating: _ratingValue.toInt(), reviewText: _reviewTextController.text) .execute() - .then((_) { - _refreshData(); - _reviewTextController.clear(); - MovieState.triggerUpdateFavorite(); - }); + .then( + (_) { + _refreshData(); + _reviewTextController.clear(); + MovieState.triggerUpdateFavorite(); + }, + ); }, label: const Text('Submit Review'), ), diff --git a/dataconnect/lib/profile.dart b/dataconnect/lib/profile.dart index 1942d136..7b7d57ee 100644 --- a/dataconnect/lib/profile.dart +++ b/dataconnect/lib/profile.dart @@ -31,13 +31,6 @@ class _ProfileState extends State @override void initState() { super.initState(); - Auth.getCurrentUser().then((user) { - if (mounted) { - setState(() { - _currentUser = user; - }); - } - }); _listener = MovieState.subscribeToCurrentUser().listen((res) { if (mounted) { setState(() { diff --git a/dataconnect/lib/router.dart b/dataconnect/lib/router.dart index 00615dd7..63bcc630 100644 --- a/dataconnect/lib/router.dart +++ b/dataconnect/lib/router.dart @@ -47,14 +47,14 @@ var router = GoRouter(initialLocation: homePath.path, routes: [ GoRoute( path: "/profile", redirect: (context, state) async { - return (await Auth.isLoggedIn()) ? null : '/login'; + return Auth.instance.isLoggedIn ? null : '/login'; }, builder: (context, state) => const Profile()), GoRoute( path: "/login", builder: (context, state) => const Login(), redirect: (context, state) async { - return (await Auth.isLoggedIn()) ? '/profile' : null; + return Auth.instance.isLoggedIn ? '/profile' : null; }, ), GoRoute( diff --git a/dataconnect/lib/util/auth.dart b/dataconnect/lib/util/auth.dart index 8c59b99c..2113b806 100644 --- a/dataconnect/lib/util/auth.dart +++ b/dataconnect/lib/util/auth.dart @@ -1,20 +1,44 @@ +import 'dart:async'; + import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/foundation.dart'; -class Auth { - static Future isLoggedIn() async { - User? user = await FirebaseAuth.instance.authStateChanges().first; - if (user == null) { - return false; - } +typedef AuthState = ({User? user, String? token}); + +class Auth extends ValueNotifier { + bool get isLoggedIn => value.user != null && value.token != null; + User? get currentUser => value.user; + String? get token => value.token; + + StreamSubscription? _cleanup; + + Future init() async { + final user = FirebaseAuth.instance.currentUser; + final token = await user?.token; + value = (user: user, token: token); + _cleanup = FirebaseAuth.instance.authStateChanges().listen((user) async { + final token = await user?.token; + value = (user: user, token: token); + }); + } + + @override + void dispose() { + super.dispose(); + _cleanup?.cancel(); + } + + static Auth instance = Auth((user: null, token: null)); + + Auth(super.value); +} + +extension on User { + Future get token async { try { - String? idToken = await user.getIdToken(); - return idToken != null; + return await getIdToken(); } catch (_) { - return false; + return null; } } - - static getCurrentUser() { - return FirebaseAuth.instance.authStateChanges().first; - } } diff --git a/dataconnect/lib/widgets/login_guard.dart b/dataconnect/lib/widgets/login_guard.dart index 27548993..1e3f9d0d 100644 --- a/dataconnect/lib/widgets/login_guard.dart +++ b/dataconnect/lib/widgets/login_guard.dart @@ -4,19 +4,19 @@ import 'package:flutter/material.dart'; class LoginGuard extends StatelessWidget { const LoginGuard({ super.key, - required this.widgetToGuard, + required this.builder, this.message, }); - final Widget widgetToGuard; + final WidgetBuilder builder; final String? message; @override Widget build(BuildContext context) { - return FutureBuilder( - future: Auth.isLoggedIn(), - builder: (context, state) { - final isLoggedIn = state.data ?? false; + return ValueListenableBuilder( + valueListenable: Auth.instance, + builder: (context, state, _) { + final isLoggedIn = Auth.instance.isLoggedIn; if (!isLoggedIn) { if (message == null) { return const SizedBox(); @@ -26,7 +26,7 @@ class LoginGuard extends StatelessWidget { 'to log in before $message', ); } - return widgetToGuard; + return builder(context); }, ); } From 749ce1264520c3213f9f193249815df37d1783df Mon Sep 17 00:00:00 2001 From: Rody Davis Date: Fri, 15 Nov 2024 15:30:47 -0800 Subject: [PATCH 13/17] update widgets --- dataconnect/lib/destination.dart | 7 + dataconnect/lib/movie_detail.dart | 466 +++++++++++++------------- dataconnect/lib/navigation_shell.dart | 14 +- 3 files changed, 244 insertions(+), 243 deletions(-) diff --git a/dataconnect/lib/destination.dart b/dataconnect/lib/destination.dart index 83aceee2..50961c1a 100644 --- a/dataconnect/lib/destination.dart +++ b/dataconnect/lib/destination.dart @@ -9,6 +9,13 @@ class Route { final String path; final String label; final IconData iconData; + + NavigationDestination toDestination() { + return NavigationDestination( + icon: Icon(iconData), + label: label, + ); + } } final homePath = Route( diff --git a/dataconnect/lib/movie_detail.dart b/dataconnect/lib/movie_detail.dart index b2db8ec7..2ee57ece 100644 --- a/dataconnect/lib/movie_detail.dart +++ b/dataconnect/lib/movie_detail.dart @@ -55,253 +55,243 @@ class _MovieDetailState extends State { }); } - String _getFavoriteLabelText() { - return _favorited ? 'Remove From Favorites' : 'Add To Favorites'; - } - - List _buildMainDescription() { - var movie = data!.movie!; - return [ - Align( - alignment: Alignment.centerLeft, - child: Container( - child: Text( - movie.title, - style: const TextStyle(fontSize: 30), - ), - )), - Row( - children: [ - Text(movie.releaseYear.toString()), - const SizedBox(width: 10), - Row( - children: [const Icon(Icons.star), Text(movie.rating.toString())], - ) - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: AspectRatio( - aspectRatio: 9 / 16, // 9:16 aspect ratio for the image - child: Image.network( - movie.imageUrl, - fit: BoxFit.cover, - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), - child: Column(children: [ - Row( - children: movie.tags!.map((tag) { - return Chip( - label: Text( - tag, - overflow: TextOverflow.ellipsis, - )); - }).toList(), - ), - Text(movie.description!) - ]), - )) - ]), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - LoginGuard( - builder: (context) => OutlinedButton.icon( - onPressed: () { - _toggleFavorite(); - }, - icon: Icon(_favorited ? Icons.favorite : Icons.favorite_border), - label: Text(_getFavoriteLabelText()), - ), - ) - ], - ) - ]; - } - - void _visitActorDetail(String id) { - context.push("/actors/$id"); - } - - Widget _buildMainActorsList() { - return Container( - height: 125, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Main Actors", - style: TextStyle(fontSize: 30), - ), - Expanded( - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - GetMovieByIdMovieMainActors actor = - data!.movie!.mainActors[index]; - return Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - CircleAvatar( - radius: 30, - child: - ClipOval(child: Image.network(actor.imageUrl))), - Text( - actor.name, - overflow: TextOverflow.ellipsis, - ) - ]); - }, - itemCount: data!.movie!.mainActors.length, - )) - ], - )); - } - - Widget _buildSupportingActorsList() { - return Container( - height: 125, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Supporting Actors", - style: TextStyle(fontSize: 30), - ), - Expanded( - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - GetMovieByIdMovieSupportingActors actor = - data!.movie!.supportingActors[index]; - return InkWell( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - CircleAvatar( - radius: 30, - child: ClipOval( - child: Image.network(actor.imageUrl))), - Text( - actor.name, - overflow: TextOverflow.ellipsis, - ) - ]), - onTap: () { - _visitActorDetail(actor.id); - }, - ); - }, - itemCount: data!.movie!.mainActors.length, - ), - ) - ], - )); - } - - List _buildRatings() { - return [ - Text("Rating: $_ratingValue"), - Slider( - value: _ratingValue, - max: 10, - divisions: 20, - label: _ratingValue.toString(), - onChanged: (double value) { - setState(() { - _ratingValue = value; - }); - }, - ), - LoginGuard( - builder: (context) => TextField( - decoration: const InputDecoration( - hintText: "Write your review", - border: OutlineInputBorder(), - ), - controller: _reviewTextController, - ), - message: "writing a review", - ), - LoginGuard( - builder: (context) => OutlinedButton.icon( - onPressed: () { - MoviesConnector.instance - .addReview( - movieId: widget.id, - rating: _ratingValue.toInt(), - reviewText: _reviewTextController.text) - .execute() - .then( - (_) { - _refreshData(); - _reviewTextController.clear(); - MovieState.triggerUpdateFavorite(); - }, + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: () { + final movie = data?.movie; + if (movie == null) { + return const Center( + child: CircularProgressIndicator(), ); - }, - label: const Text('Submit Review'), - ), - ), - ...data!.movie!.reviews.map((review) { - return Card( - child: Padding( - padding: const EdgeInsets.all(20.0), + } + return Padding( + padding: const EdgeInsets.all(30), + child: SingleChildScrollView( child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(review.user.username), + Align( + alignment: Alignment.centerLeft, + child: Text( + movie.title, + style: const TextStyle(fontSize: 30), + )), Row( children: [ - Text(DateFormat.yMMMd().format(review.reviewDate)), - const SizedBox( - width: 10, - ), - Text("Rating ${review.rating}") + Text(movie.releaseYear.toString()), + const SizedBox(width: 10), + Row( + children: [ + const Icon(Icons.star), + Text(movie.rating.toString()) + ], + ) ], ), - Text(review.reviewText!) - ], - )), - ); - }) - ]; -/**/ - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: data == null - ? const Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [CircularProgressIndicator()], - ) - : Padding( - padding: const EdgeInsets.all(30), - child: SingleChildScrollView( - child: Column( + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: AspectRatio( + aspectRatio: + 9 / 16, // 9:16 aspect ratio for the image + child: Image.network( + movie.imageUrl, + fit: BoxFit.cover, + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), + child: Column(children: [ + Row( + children: movie.tags!.map((tag) { + return Chip( + label: Text( + tag, + overflow: TextOverflow.ellipsis, + )); + }).toList(), + ), + Text(movie.description!) + ]), + )) + ]), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - ..._buildMainDescription(), - _buildMainActorsList(), - _buildSupportingActorsList(), - ..._buildRatings() + LoginGuard( + builder: (context) => OutlinedButton.icon( + onPressed: () { + _toggleFavorite(); + }, + icon: Icon(_favorited + ? Icons.favorite + : Icons.favorite_border), + label: Text( + _favorited + ? 'Remove From Favorites' + : 'Add To Favorites', + ), + ), + ) ], - )))), + ), + SizedBox( + height: 125, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Main Actors", + style: TextStyle(fontSize: 30), + ), + Expanded( + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + GetMovieByIdMovieMainActors actor = + data!.movie!.mainActors[index]; + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CircleAvatar( + radius: 30, + child: ClipOval( + child: + Image.network(actor.imageUrl))), + Text( + actor.name, + overflow: TextOverflow.ellipsis, + ) + ]); + }, + itemCount: data!.movie!.mainActors.length, + )) + ], + ), + ), + Container( + height: 125, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Supporting Actors", + style: TextStyle(fontSize: 30), + ), + Expanded( + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + GetMovieByIdMovieSupportingActors actor = + data!.movie!.supportingActors[index]; + return InkWell( + child: Column( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + CircleAvatar( + radius: 30, + child: ClipOval( + child: Image.network( + actor.imageUrl))), + Text( + actor.name, + overflow: TextOverflow.ellipsis, + ) + ]), + onTap: () { + context.push("/actors/${actor.id}"); + }, + ); + }, + itemCount: data!.movie!.mainActors.length, + ), + ) + ], + ), + ), + Text("Rating: $_ratingValue"), + Slider( + value: _ratingValue, + max: 10, + divisions: 20, + label: _ratingValue.toString(), + onChanged: (double value) { + setState(() { + _ratingValue = value; + }); + }, + ), + LoginGuard( + builder: (context) => TextField( + decoration: const InputDecoration( + hintText: "Write your review", + border: OutlineInputBorder(), + ), + controller: _reviewTextController, + ), + message: "writing a review", + ), + LoginGuard( + builder: (context) => OutlinedButton.icon( + onPressed: () { + MoviesConnector.instance + .addReview( + movieId: widget.id, + rating: _ratingValue.toInt(), + reviewText: _reviewTextController.text) + .execute() + .then( + (_) { + _refreshData(); + _reviewTextController.clear(); + MovieState.triggerUpdateFavorite(); + }, + ); + }, + label: const Text('Submit Review'), + ), + ), + ...data!.movie!.reviews.map((review) { + return Card( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(review.user.username), + Row( + children: [ + Text(DateFormat.yMMMd() + .format(review.reviewDate)), + const SizedBox( + width: 10, + ), + Text("Rating ${review.rating}") + ], + ), + Text(review.reviewText!) + ], + )), + ); + }), + ], + ), + ), + ); + }(), + ), ); } } diff --git a/dataconnect/lib/navigation_shell.dart b/dataconnect/lib/navigation_shell.dart index f73b02e8..0d476160 100644 --- a/dataconnect/lib/navigation_shell.dart +++ b/dataconnect/lib/navigation_shell.dart @@ -1,9 +1,14 @@ -import 'package:dataconnect/destination.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'destination.dart'; + class NavigationShell extends StatelessWidget { - const NavigationShell({required this.navigationShell, super.key}); + const NavigationShell({ + super.key, + required this.navigationShell, + }); + final StatefulNavigationShell navigationShell; void _goBranch(int index) { @@ -24,9 +29,8 @@ class NavigationShell extends StatelessWidget { bottomNavigationBar: NavigationBar( selectedIndex: navigationShell.currentIndex, onDestinationSelected: _goBranch, - destinations: paths - .map((destination) => NavigationDestination( - icon: Icon(destination.iconData), label: destination.label)) + destinations: paths // + .map((destination) => destination.toDestination()) .toList(), ), ); From e24edc9f5f83f72f6437072fe1855b0839ed5df3 Mon Sep 17 00:00:00 2001 From: Rody Davis Date: Fri, 15 Nov 2024 15:41:06 -0800 Subject: [PATCH 14/17] updating router --- dataconnect/lib/actor_detail.dart | 107 ++++++++++++------------ dataconnect/lib/destination.dart | 15 +--- dataconnect/lib/movie_detail.dart | 2 +- dataconnect/lib/movie_state.dart | 2 +- dataconnect/lib/navigation_shell.dart | 4 +- dataconnect/lib/router.dart | 113 ++++++++++++++------------ dataconnect/lib/search.dart | 9 +- 7 files changed, 128 insertions(+), 124 deletions(-) diff --git a/dataconnect/lib/actor_detail.dart b/dataconnect/lib/actor_detail.dart index 5bc6e8c4..a25a0556 100644 --- a/dataconnect/lib/actor_detail.dart +++ b/dataconnect/lib/actor_detail.dart @@ -14,64 +14,65 @@ class ActorDetail extends StatelessWidget { @override Widget build(BuildContext context) { return FutureBuilder( - future: MovieState.getActorById(actorId), - builder: (context, snapshot) { - final actor = snapshot.data?.data.actor; - final loading = snapshot.connectionState == ConnectionState.waiting; - return Scaffold( - body: SafeArea( - child: () { - if (actor == null || loading) { - return const Center( - child: CircularProgressIndicator(), - ); - } - return Padding( - padding: const EdgeInsets.all(30), - child: SingleChildScrollView( - child: Column( - children: [ - Align( - alignment: Alignment.centerLeft, - child: Text( - actor.name, - style: const TextStyle(fontSize: 30), - )), - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: AspectRatio( - aspectRatio: - 9 / 16, // 9:16 aspect ratio for the image - child: Image.network( - actor.imageUrl, - fit: BoxFit.cover, - ), + future: MovieState.getActorById(actorId), + builder: (context, snapshot) { + final actor = snapshot.data?.data.actor; + final loading = snapshot.connectionState == ConnectionState.waiting; + return Scaffold( + body: SafeArea( + child: () { + if (actor == null || loading) { + return const Center( + child: CircularProgressIndicator(), + ); + } + return Padding( + padding: const EdgeInsets.all(30), + child: SingleChildScrollView( + child: Column( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + actor.name, + style: const TextStyle(fontSize: 30), + )), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: AspectRatio( + aspectRatio: + 9 / 16, // 9:16 aspect ratio for the image + child: Image.network( + actor.imageUrl, + fit: BoxFit.cover, ), ), - ], - ), - ListMovies( - movies: MovieState.convertMainActorDetail( - actor.mainActors, ), - title: "Main Roles", + ], + ), + ListMovies( + movies: MovieState.convertMainActorDetail( + actor.mainActors, ), - ListMovies( - movies: MovieState.convertSupportingActorDetail( - actor.supportingActors, - ), - title: "Supporting Roles", + title: "Main Roles", + ), + ListMovies( + movies: MovieState.convertSupportingActorDetail( + actor.supportingActors, ), - ], - ), + title: "Supporting Roles", + ), + ], ), - ); - }(), - ), - ); - }); + ), + ); + }(), + ), + ); + }, + ); } } diff --git a/dataconnect/lib/destination.dart b/dataconnect/lib/destination.dart index 50961c1a..25820bbe 100644 --- a/dataconnect/lib/destination.dart +++ b/dataconnect/lib/destination.dart @@ -1,21 +1,14 @@ import 'package:flutter/material.dart'; -class Route { +class Route extends NavigationDestination { Route({ + super.key, required this.path, - required this.label, + required super.label, required this.iconData, - }); + }) : super(icon: Icon(iconData)); final String path; - final String label; final IconData iconData; - - NavigationDestination toDestination() { - return NavigationDestination( - icon: Icon(iconData), - label: label, - ); - } } final homePath = Route( diff --git a/dataconnect/lib/movie_detail.dart b/dataconnect/lib/movie_detail.dart index 2ee57ece..02b284e8 100644 --- a/dataconnect/lib/movie_detail.dart +++ b/dataconnect/lib/movie_detail.dart @@ -176,7 +176,7 @@ class _MovieDetailState extends State { ], ), ), - Container( + SizedBox( height: 125, child: Column( mainAxisAlignment: MainAxisAlignment.start, diff --git a/dataconnect/lib/movie_state.dart b/dataconnect/lib/movie_state.dart index 3be9cfb6..e12c806b 100644 --- a/dataconnect/lib/movie_state.dart +++ b/dataconnect/lib/movie_state.dart @@ -1,6 +1,6 @@ -import 'package:dataconnect/movies_connector/movies.dart'; import 'package:firebase_data_connect/firebase_data_connect.dart'; +import 'movies_connector/movies.dart'; import 'models/movie.dart'; class MovieState { diff --git a/dataconnect/lib/navigation_shell.dart b/dataconnect/lib/navigation_shell.dart index 0d476160..6f0964e7 100644 --- a/dataconnect/lib/navigation_shell.dart +++ b/dataconnect/lib/navigation_shell.dart @@ -29,9 +29,7 @@ class NavigationShell extends StatelessWidget { bottomNavigationBar: NavigationBar( selectedIndex: navigationShell.currentIndex, onDestinationSelected: _goBranch, - destinations: paths // - .map((destination) => destination.toDestination()) - .toList(), + destinations: paths, ), ); } diff --git a/dataconnect/lib/router.dart b/dataconnect/lib/router.dart index 63bcc630..4aeb25b1 100644 --- a/dataconnect/lib/router.dart +++ b/dataconnect/lib/router.dart @@ -1,9 +1,9 @@ -import 'package:dataconnect/destination.dart'; -import 'package:dataconnect/login.dart'; -import 'package:dataconnect/profile.dart'; -import 'package:dataconnect/search.dart'; import 'package:go_router/go_router.dart'; +import 'login.dart'; +import 'destination.dart'; +import 'profile.dart'; +import 'search.dart'; import 'actor_detail.dart'; import 'main.dart'; import 'movie_detail.dart'; @@ -11,56 +11,67 @@ import 'navigation_shell.dart'; import 'sign_up.dart'; import 'util/auth.dart'; -var router = GoRouter(initialLocation: homePath.path, routes: [ - StatefulShellRoute.indexedStack( +var router = GoRouter( + refreshListenable: Auth.instance, + initialLocation: homePath.path, + routes: [ + StatefulShellRoute.indexedStack( builder: (context, state, navigationShell) { return NavigationShell(navigationShell: navigationShell); }, branches: [ - StatefulShellBranch(routes: [ - GoRoute( - path: homePath.path, - builder: (context, state) => const MyHomePage(), - ), - GoRoute( - path: '/movies/:movieId', - builder: (context, state) => - MovieDetail(id: state.pathParameters['movieId']!)), - GoRoute( - path: "/actors", - redirect: (context, state) => - '/actors/${state.pathParameters['actorId']}', - routes: [ - GoRoute( - path: ":actorId", - builder: (context, state) => - ActorDetail(actorId: state.pathParameters['actorId']!)) - ]) - ]), - StatefulShellBranch(routes: [ - GoRoute( - path: "/search", - builder: (context, state) => const Search(), - ), - ]), - StatefulShellBranch(routes: [ - GoRoute( - path: "/profile", + StatefulShellBranch( + routes: [ + GoRoute( + path: homePath.path, + builder: (context, state) => const MyHomePage(), + ), + GoRoute( + path: '/movies/:movieId', + builder: (context, state) => + MovieDetail(id: state.pathParameters['movieId']!)), + GoRoute( + path: "/actors", + redirect: (context, state) => + '/actors/${state.pathParameters['actorId']}', + routes: [ + GoRoute( + path: ":actorId", + builder: (context, state) => ActorDetail( + actorId: state.pathParameters['actorId']!)) + ]) + ], + ), + StatefulShellBranch( + routes: [ + GoRoute( + path: "/search", + builder: (context, state) => const Search(), + ), + ], + ), + StatefulShellBranch( + routes: [ + GoRoute( + path: "/profile", + redirect: (context, state) async { + return Auth.instance.isLoggedIn ? null : '/login'; + }, + builder: (context, state) => const Profile()), + GoRoute( + path: "/login", + builder: (context, state) => const Login(), redirect: (context, state) async { - return Auth.instance.isLoggedIn ? null : '/login'; + return Auth.instance.isLoggedIn ? '/profile' : null; }, - builder: (context, state) => const Profile()), - GoRoute( - path: "/login", - builder: (context, state) => const Login(), - redirect: (context, state) async { - return Auth.instance.isLoggedIn ? '/profile' : null; - }, - ), - GoRoute( - path: "/signup", - builder: (context, state) => const SignUp(), - ) - ]) - ]) -]); + ), + GoRoute( + path: "/signup", + builder: (context, state) => const SignUp(), + ) + ], + ) + ], + ) + ], +); diff --git a/dataconnect/lib/search.dart b/dataconnect/lib/search.dart index bc2d18c1..23932e26 100644 --- a/dataconnect/lib/search.dart +++ b/dataconnect/lib/search.dart @@ -1,10 +1,11 @@ -import 'package:dataconnect/models/movie.dart'; -import 'package:dataconnect/movies_connector/movies.dart'; -import 'package:dataconnect/widgets/list_actors.dart'; -import 'package:dataconnect/widgets/list_movies.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'models/movie.dart'; +import 'movies_connector/movies.dart'; +import 'widgets/list_actors.dart'; +import 'widgets/list_movies.dart'; + class Search extends StatefulWidget { const Search({super.key}); From 5bae89922ed9f1835235fcbc854c53c860289cea Mon Sep 17 00:00:00 2001 From: Rody Davis Date: Fri, 15 Nov 2024 15:54:26 -0800 Subject: [PATCH 15/17] update widgets --- dataconnect/lib/movie_detail.dart | 67 ++++++++---- dataconnect/lib/profile.dart | 175 ++++++++++++------------------ 2 files changed, 117 insertions(+), 125 deletions(-) diff --git a/dataconnect/lib/movie_detail.dart b/dataconnect/lib/movie_detail.dart index 02b284e8..5f9ccef2 100644 --- a/dataconnect/lib/movie_detail.dart +++ b/dataconnect/lib/movie_detail.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:dataconnect/movie_state.dart'; import 'package:dataconnect/movies_connector/movies.dart'; import 'package:dataconnect/widgets/login_guard.dart'; @@ -20,24 +22,59 @@ class _MovieDetailState extends State { GetMovieByIdData? data; bool _favorited = false; - final TextEditingController _reviewTextController = TextEditingController(); + final _reviewTextController = TextEditingController(); + StreamSubscription? _movieByIdSub, _movieInfoSub; + @override void initState() { super.initState(); + init(widget.id); + } - MovieState.subscribeToMovieById(widget.id).listen((value) { - if (mounted) { - setState(() { - loading = false; - data = value.data; - }); - } - }); + @override + void dispose() { + _movieByIdSub?.cancel(); + _movieInfoSub?.cancel(); + super.dispose(); + } + + @override + void didUpdateWidget(covariant MovieDetail oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.id != widget.id) { + init(widget.id); + } + } + + Future init(String id) async { + _movieByIdSub?.cancel(); + _movieInfoSub?.cancel(); + _movieByIdSub = MovieState.subscribeToMovieById(widget.id).listen( + (value) { + if (mounted) { + setState(() { + loading = false; + data = value.data; + }); + } + }, + ); + _movieInfoSub = MovieState.subscribeToGetMovieInfo(widget.id).listen( + (value) { + if (mounted) { + setState(() { + _favorited = value.data.favorite_movie != null; + }); + } + }, + ); + } - MovieState.subscribeToGetMovieInfo(widget.id).listen((value) { + void _toggleFavorite() { + MovieState.toggleFavorite(widget.id, _favorited).then((_) { if (mounted) { setState(() { - _favorited = value.data.favorite_movie != null; + _favorited = !_favorited; }); } }); @@ -47,14 +84,6 @@ class _MovieDetailState extends State { MovieState.refreshMovieDetail(widget.id); } - void _toggleFavorite() { - MovieState.toggleFavorite(widget.id, _favorited).then((_) { - setState(() { - _favorited = !_favorited; - }); - }); - } - @override Widget build(BuildContext context) { return Scaffold( diff --git a/dataconnect/lib/profile.dart b/dataconnect/lib/profile.dart index 7b7d57ee..b1337d97 100644 --- a/dataconnect/lib/profile.dart +++ b/dataconnect/lib/profile.dart @@ -1,118 +1,81 @@ -import 'dart:async'; - -import 'package:dataconnect/movie_state.dart'; -import 'package:dataconnect/models/movie.dart'; -import 'package:dataconnect/movies_connector/movies.dart'; -import 'package:dataconnect/util/auth.dart'; -import 'package:dataconnect/widgets/list_movies.dart'; -import 'package:dataconnect/widgets/list_reviews.dart'; import 'package:firebase_auth/firebase_auth.dart'; -import 'package:firebase_data_connect/firebase_data_connect.dart'; import 'package:flutter/material.dart'; - import 'package:go_router/go_router.dart'; -class Profile extends StatefulWidget { - const Profile({super.key}); - - @override - State createState() => _ProfileState(); -} +import 'movie_state.dart'; +import 'models/movie.dart'; +import 'movies_connector/movies.dart'; +import 'widgets/list_movies.dart'; +import 'widgets/list_reviews.dart'; -class _ProfileState extends State - with WidgetsBindingObserver, RouteAware { - User? _currentUser; - List _favoriteMovies = []; - List _reviews = []; - String? _displayName; - final RouteObserver routeObserver = RouteObserver(); - StreamSubscription>? _listener; - - @override - void initState() { - super.initState(); - _listener = MovieState.subscribeToCurrentUser().listen((res) { - if (mounted) { - setState(() { - _displayName = res.data.user!.name; - _favoriteMovies = - res.data.user!.favoriteMovies.map((e) => e.movie).toList(); - _reviews = res.data.user!.reviews; - }); - } - }); - } - - @override - void dispose() { - super.dispose(); - _listener?.cancel(); - } - - _refresh() { - MoviesConnector.instance.getCurrentUser().execute(); - } - - Widget _buildUserInfo() { - return Container( - child: Column( - children: [ - Text('Welcome back ${_displayName ?? ''}!'), - TextButton( - onPressed: () async { - FirebaseAuth.instance.signOut(); - context.go('/login'); - }, - child: Text('Sign out')) - ], - ), - ); - } +class Profile extends StatelessWidget { + const Profile({super.key}); @override Widget build(BuildContext context) { - return _currentUser == null - ? const Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [CircularProgressIndicator()], - ) - : RefreshIndicator( + return StreamBuilder( + stream: MovieState.subscribeToCurrentUser(), + builder: (context, snapshot) { + final res = snapshot.data; + if (res == null) { + return const Center( + child: CircularProgressIndicator(), + ); + } + final displayName = res.data.user!.name; + final favoriteMovies = + res.data.user!.favoriteMovies.map((e) => e.movie).toList(); + final reviews = res.data.user!.reviews; + final currentUser = res.data.user; + return RefreshIndicator( child: SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), - child: Container( - padding: EdgeInsets.all(30), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildUserInfo(), - ListMovies( - title: "Favorite Movies", - movies: _favoriteMovies - .map( - (e) => Movie( - id: e.id, - title: e.title, - imageUrl: e.imageUrl), - ) - .toList()), - ListReviews( - reviews: _reviews - .map( - (e) => Review( - reviewText: e.reviewText!, - rating: e.rating!, - username: _currentUser!.email!, - date: e.reviewDate), - ) - .toList(), - title: "Reviews"), - ], - ), - )), + physics: const AlwaysScrollableScrollPhysics(), + child: Container( + padding: const EdgeInsets.all(30), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + children: [ + Text('Welcome back $displayName !'), + TextButton( + onPressed: () async { + FirebaseAuth.instance.signOut(); + context.go('/login'); + }, + child: const Text('Sign out')) + ], + ), + ListMovies( + title: "Favorite Movies", + movies: favoriteMovies + .map( + (e) => Movie( + id: e.id, + title: e.title, + imageUrl: e.imageUrl), + ) + .toList()), + ListReviews( + reviews: reviews + .map( + (e) => Review( + reviewText: e.reviewText!, + rating: e.rating!, + username: currentUser!.username, + date: e.reviewDate), + ) + .toList(), + title: "Reviews"), + ], + ), + ), + ), onRefresh: () async { - await _refresh(); - }); + MoviesConnector.instance.getCurrentUser().execute(); + }, + ); + }); } } From 986f513bd614ae25e4358b002e4202faeb8a4f2d Mon Sep 17 00:00:00 2001 From: Rody Davis Date: Fri, 15 Nov 2024 16:09:01 -0800 Subject: [PATCH 16/17] Update profile.dart --- dataconnect/lib/profile.dart | 127 ++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 62 deletions(-) diff --git a/dataconnect/lib/profile.dart b/dataconnect/lib/profile.dart index b1337d97..d33c6ae7 100644 --- a/dataconnect/lib/profile.dart +++ b/dataconnect/lib/profile.dart @@ -5,77 +5,80 @@ import 'package:go_router/go_router.dart'; import 'movie_state.dart'; import 'models/movie.dart'; import 'movies_connector/movies.dart'; +import 'util/auth.dart'; import 'widgets/list_movies.dart'; import 'widgets/list_reviews.dart'; +import 'widgets/login_guard.dart'; class Profile extends StatelessWidget { const Profile({super.key}); @override Widget build(BuildContext context) { - return StreamBuilder( - stream: MovieState.subscribeToCurrentUser(), - builder: (context, snapshot) { - final res = snapshot.data; - if (res == null) { - return const Center( - child: CircularProgressIndicator(), - ); - } - final displayName = res.data.user!.name; - final favoriteMovies = - res.data.user!.favoriteMovies.map((e) => e.movie).toList(); - final reviews = res.data.user!.reviews; - final currentUser = res.data.user; - return RefreshIndicator( - child: SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), - child: Container( - padding: const EdgeInsets.all(30), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - children: [ - Text('Welcome back $displayName !'), - TextButton( - onPressed: () async { - FirebaseAuth.instance.signOut(); - context.go('/login'); - }, - child: const Text('Sign out')) - ], - ), - ListMovies( - title: "Favorite Movies", - movies: favoriteMovies - .map( - (e) => Movie( - id: e.id, - title: e.title, - imageUrl: e.imageUrl), - ) - .toList()), - ListReviews( - reviews: reviews - .map( - (e) => Review( - reviewText: e.reviewText!, - rating: e.rating!, - username: currentUser!.username, - date: e.reviewDate), - ) - .toList(), - title: "Reviews"), - ], + return LoginGuard(builder: (context) { + return StreamBuilder( + stream: MovieState.subscribeToCurrentUser(), + builder: (context, snapshot) { + final res = snapshot.data; + if (res == null) { + return const Center( + child: CircularProgressIndicator(), + ); + } + final displayName = res.data.user!.name; + final favoriteMovies = + res.data.user!.favoriteMovies.map((e) => e.movie).toList(); + final reviews = res.data.user!.reviews; + return RefreshIndicator( + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: Container( + padding: const EdgeInsets.all(30), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + children: [ + Text('Welcome back $displayName !'), + TextButton( + onPressed: () async { + FirebaseAuth.instance.signOut(); + context.go('/login'); + }, + child: const Text('Sign out')) + ], + ), + ListMovies( + title: "Favorite Movies", + movies: favoriteMovies + .map( + (e) => Movie( + id: e.id, + title: e.title, + imageUrl: e.imageUrl), + ) + .toList()), + ListReviews( + reviews: reviews + .map( + (e) => Review( + reviewText: e.reviewText!, + rating: e.rating!, + username: Auth.instance.currentUser!.email!, + date: e.reviewDate), + ) + .toList(), + title: "Reviews"), + ], + ), ), ), - ), - onRefresh: () async { - MoviesConnector.instance.getCurrentUser().execute(); - }, - ); - }); + onRefresh: () async { + MoviesConnector.instance.getCurrentUser().execute(); + }, + ); + }); + }); } } From 813f4a6391b3dd835f4f92517200973ffee41946 Mon Sep 17 00:00:00 2001 From: Rody Davis Date: Fri, 15 Nov 2024 16:24:41 -0800 Subject: [PATCH 17/17] update firebase --- dataconnect/.gitignore | 2 + dataconnect/firebase.json | 39 ------ dataconnect/macos/Podfile.lock | 131 ++++++++++++++++++ .../macos/Runner.xcodeproj/project.pbxproj | 104 +++++++++++++- .../contents.xcworkspacedata | 3 + dataconnect/macos/Runner/AppDelegate.swift | 4 + 6 files changed, 241 insertions(+), 42 deletions(-) create mode 100644 dataconnect/macos/Podfile.lock diff --git a/dataconnect/.gitignore b/dataconnect/.gitignore index 5b1e3843..fd09e19b 100644 --- a/dataconnect/.gitignore +++ b/dataconnect/.gitignore @@ -5,9 +5,11 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ # IntelliJ related diff --git a/dataconnect/firebase.json b/dataconnect/firebase.json index 00106af8..958f35d4 100644 --- a/dataconnect/firebase.json +++ b/dataconnect/firebase.json @@ -1,43 +1,4 @@ { - "flutter": { - "platforms": { - "android": { - "default": { - "projectId": "quickstart-flutter-cc624", - "appId": "1:731568610039:android:2fda8b27330be9447251f2", - "fileOutput": "android/app/google-services.json" - } - }, - "ios": { - "default": { - "projectId": "quickstart-flutter-cc624", - "appId": "1:731568610039:ios:e78b43f1d75a77d87251f2", - "uploadDebugSymbols": false, - "fileOutput": "ios/Runner/GoogleService-Info.plist" - } - }, - "dart": { - "lib/firebase_options.dart": { - "projectId": "quickstart-flutter-cc624", - "configurations": { - "android": "1:731568610039:android:2fda8b27330be9447251f2", - "ios": "1:731568610039:ios:e78b43f1d75a77d87251f2", - "macos": "1:731568610039:ios:e78b43f1d75a77d87251f2", - "web": "1:731568610039:web:2896847d0f5655fb7251f2", - "windows": "1:731568610039:web:3c1e404f955f0b467251f2" - } - } - }, - "macos": { - "default": { - "projectId": "quickstart-flutter-cc624", - "appId": "1:731568610039:ios:e78b43f1d75a77d87251f2", - "uploadDebugSymbols": false, - "fileOutput": "macos/Runner/GoogleService-Info.plist" - } - } - } - }, "dataconnect": { "source": "dataconnect" }, "emulators": { "dataconnect": { "port": 9399 }, "auth": { "port": 9400 } } } diff --git a/dataconnect/macos/Podfile.lock b/dataconnect/macos/Podfile.lock new file mode 100644 index 00000000..7cb336e7 --- /dev/null +++ b/dataconnect/macos/Podfile.lock @@ -0,0 +1,131 @@ +PODS: + - AppCheckCore (11.2.0): + - GoogleUtilities/Environment (~> 8.0) + - GoogleUtilities/UserDefaults (~> 8.0) + - PromisesObjC (~> 2.4) + - Firebase/AppCheck (11.4.2): + - Firebase/CoreOnly + - FirebaseAppCheck (~> 11.4.0) + - Firebase/Auth (11.4.2): + - Firebase/CoreOnly + - FirebaseAuth (~> 11.4.0) + - Firebase/CoreOnly (11.4.2): + - FirebaseCore (= 11.4.2) + - firebase_app_check (0.3.1-4): + - Firebase/AppCheck (~> 11.4.0) + - Firebase/CoreOnly (~> 11.4.0) + - firebase_core + - FlutterMacOS + - firebase_auth (5.3.3): + - Firebase/Auth (~> 11.4.0) + - Firebase/CoreOnly (~> 11.4.0) + - firebase_core + - FlutterMacOS + - firebase_core (3.8.0): + - Firebase/CoreOnly (~> 11.4.0) + - FlutterMacOS + - FirebaseAppCheck (11.4.0): + - AppCheckCore (~> 11.0) + - FirebaseAppCheckInterop (~> 11.0) + - FirebaseCore (~> 11.0) + - GoogleUtilities/Environment (~> 8.0) + - GoogleUtilities/UserDefaults (~> 8.0) + - FirebaseAppCheckInterop (11.5.0) + - FirebaseAuth (11.4.0): + - FirebaseAppCheckInterop (~> 11.0) + - FirebaseAuthInterop (~> 11.0) + - FirebaseCore (~> 11.4) + - FirebaseCoreExtension (~> 11.4) + - GoogleUtilities/AppDelegateSwizzler (~> 8.0) + - GoogleUtilities/Environment (~> 8.0) + - GTMSessionFetcher/Core (< 5.0, >= 3.4) + - RecaptchaInterop (~> 100.0) + - FirebaseAuthInterop (11.5.0) + - FirebaseCore (11.4.2): + - FirebaseCoreInternal (< 12.0, >= 11.4.2) + - GoogleUtilities/Environment (~> 8.0) + - GoogleUtilities/Logger (~> 8.0) + - FirebaseCoreExtension (11.4.1): + - FirebaseCore (~> 11.0) + - FirebaseCoreInternal (11.5.0): + - "GoogleUtilities/NSData+zlib (~> 8.0)" + - FlutterMacOS (1.0.0) + - GoogleUtilities/AppDelegateSwizzler (8.0.2): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Privacy + - GoogleUtilities/Environment (8.0.2): + - GoogleUtilities/Privacy + - GoogleUtilities/Logger (8.0.2): + - GoogleUtilities/Environment + - GoogleUtilities/Privacy + - GoogleUtilities/Network (8.0.2): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Privacy + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (8.0.2)": + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (8.0.2) + - GoogleUtilities/Reachability (8.0.2): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GoogleUtilities/UserDefaults (8.0.2): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GTMSessionFetcher/Core (4.1.0) + - PromisesObjC (2.4.0) + +DEPENDENCIES: + - firebase_app_check (from `Flutter/ephemeral/.symlinks/plugins/firebase_app_check/macos`) + - firebase_auth (from `Flutter/ephemeral/.symlinks/plugins/firebase_auth/macos`) + - firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + +SPEC REPOS: + trunk: + - AppCheckCore + - Firebase + - FirebaseAppCheck + - FirebaseAppCheckInterop + - FirebaseAuth + - FirebaseAuthInterop + - FirebaseCore + - FirebaseCoreExtension + - FirebaseCoreInternal + - GoogleUtilities + - GTMSessionFetcher + - PromisesObjC + +EXTERNAL SOURCES: + firebase_app_check: + :path: Flutter/ephemeral/.symlinks/plugins/firebase_app_check/macos + firebase_auth: + :path: Flutter/ephemeral/.symlinks/plugins/firebase_auth/macos + firebase_core: + :path: Flutter/ephemeral/.symlinks/plugins/firebase_core/macos + FlutterMacOS: + :path: Flutter/ephemeral + +SPEC CHECKSUMS: + AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f + Firebase: 7fd5466678d964be78fbf536d8a3385da19c4828 + firebase_app_check: 27a62bd66d30049207742fcb7fc996bdb82ba622 + firebase_auth: 85ed6c80b24da60af13391f9cdc0e566440b1963 + firebase_core: d95c4a2225d7b6ed46bc31fb2a6f421fc7c8285b + FirebaseAppCheck: 933cbda29279ed316b82360bca77602ac1af1ff2 + FirebaseAppCheckInterop: d265d9f4484e7ec1c591086408840fdd383d1213 + FirebaseAuth: c359af98bd703cbf4293eec107a40de08ede6ce6 + FirebaseAuthInterop: 1219bee9b23e6ebe84c256a0d95adab53d11c331 + FirebaseCore: 6b32c57269bd999aab34354c3923d92a6e5f3f84 + FirebaseCoreExtension: f1bc67a4702931a7caa097d8e4ac0a1b0d16720e + FirebaseCoreInternal: f47dd28ae7782e6a4738aad3106071a8fe0af604 + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d + GTMSessionFetcher: 923b710231ad3d6f3f0495ac1ced35421e07d9a6 + PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + +PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 + +COCOAPODS: 1.16.2 diff --git a/dataconnect/macos/Runner.xcodeproj/project.pbxproj b/dataconnect/macos/Runner.xcodeproj/project.pbxproj index e6892799..1cfc1f84 100644 --- a/dataconnect/macos/Runner.xcodeproj/project.pbxproj +++ b/dataconnect/macos/Runner.xcodeproj/project.pbxproj @@ -21,12 +21,14 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 0B54BE36095256A990923F60 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2C7FA3F3771C2A29C4152FF /* Pods_RunnerTests.framework */; }; 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 682E69E29E5999549E31008B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FCBDA75210EC7C9219DEEA17 /* Pods_Runner.framework */; }; E81C99BCE641EAAC42D0435C /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = F9721B425DB992F996064CCA /* GoogleService-Info.plist */; }; /* End PBXBuildFile section */ @@ -61,6 +63,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 04AEC284C642086067839821 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 0D7D17F289FAFC2610AFF3B2 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; @@ -77,9 +81,15 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 5074E90362781627D86FABAA /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 8B4A2D9CD56B4E2E89139CB8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + AA887168DC22BA276076B2A8 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + B2ADFEFAAEAA3DEBDB5C916D /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + B2C7FA3F3771C2A29C4152FF /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F9721B425DB992F996064CCA /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; + FCBDA75210EC7C9219DEEA17 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -87,6 +97,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0B54BE36095256A990923F60 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -94,6 +105,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 682E69E29E5999549E31008B /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -128,6 +140,7 @@ 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, F9721B425DB992F996064CCA /* GoogleService-Info.plist */, + CB6772AFF3560852DF3C4E63 /* Pods */, ); sourceTree = ""; }; @@ -175,9 +188,24 @@ path = Runner; sourceTree = ""; }; + CB6772AFF3560852DF3C4E63 /* Pods */ = { + isa = PBXGroup; + children = ( + 04AEC284C642086067839821 /* Pods-Runner.debug.xcconfig */, + 8B4A2D9CD56B4E2E89139CB8 /* Pods-Runner.release.xcconfig */, + 5074E90362781627D86FABAA /* Pods-Runner.profile.xcconfig */, + 0D7D17F289FAFC2610AFF3B2 /* Pods-RunnerTests.debug.xcconfig */, + B2ADFEFAAEAA3DEBDB5C916D /* Pods-RunnerTests.release.xcconfig */, + AA887168DC22BA276076B2A8 /* Pods-RunnerTests.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + FCBDA75210EC7C9219DEEA17 /* Pods_Runner.framework */, + B2C7FA3F3771C2A29C4152FF /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -189,6 +217,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + DE64E3F8A561EACF28AA5DB4 /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -207,11 +236,13 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 03EF311D5499B576A847F58B /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + D515E6E5EBB879A7D1A062B1 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -295,6 +326,28 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 03EF311D5499B576A847F58B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -333,6 +386,45 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + D515E6E5EBB879A7D1A062B1 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + DE64E3F8A561EACF28AA5DB4 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -384,6 +476,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 0D7D17F289FAFC2610AFF3B2 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -398,6 +491,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = B2ADFEFAAEAA3DEBDB5C916D /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -412,6 +506,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = AA887168DC22BA276076B2A8 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -465,7 +560,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -487,6 +582,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -547,7 +643,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -597,7 +693,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -619,6 +715,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -639,6 +736,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; diff --git a/dataconnect/macos/Runner.xcworkspace/contents.xcworkspacedata b/dataconnect/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a16..21a3cc14 100644 --- a/dataconnect/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/dataconnect/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/dataconnect/macos/Runner/AppDelegate.swift b/dataconnect/macos/Runner/AppDelegate.swift index 8e02df28..b3c17614 100644 --- a/dataconnect/macos/Runner/AppDelegate.swift +++ b/dataconnect/macos/Runner/AppDelegate.swift @@ -6,4 +6,8 @@ class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } }