diff --git a/packages/firebase_data_connect/firebase_data_connect/example/.firebaserc b/packages/firebase_data_connect/firebase_data_connect/example/.firebaserc index cad24fca0101..cc8e47248c84 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/.firebaserc +++ b/packages/firebase_data_connect/firebase_data_connect/example/.firebaserc @@ -3,10 +3,5 @@ "default": "flutterfire-e2e-tests" }, "targets": {}, - "etags": {}, - "dataconnectEmulatorConfig": { - "postgres": { - "localConnectionString": "postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable" - } - } + "etags": {} } \ No newline at end of file diff --git a/packages/firebase_data_connect/firebase_data_connect/example/integration_test/generation_e2e.dart b/packages/firebase_data_connect/firebase_data_connect/example/integration_test/generation_e2e.dart index 568f499f37dc..ccedb69f4930 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/integration_test/generation_e2e.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/integration_test/generation_e2e.dart @@ -30,40 +30,39 @@ void runGenerationTest() { testWidgets('should have generated correct MutationRef', (WidgetTester tester) async { - final ref = MoviesConnector.instance.createMovie - .ref( + final ref = MoviesConnector.instance + .createMovie( genre: 'Action', title: 'The Matrix', releaseYear: 1999, ) .rating(4.5); expect(ref, isNotNull); - expect(ref.build().execute, isNotNull); + expect(ref.execute, isNotNull); }); testWidgets('should have generated correct QueryRef', (WidgetTester tester) async { - final ref = MoviesConnector.instance.listMovies.ref(); + final ref = MoviesConnector.instance.listMovies().ref(); expect(ref, isNotNull); - expect(ref.build().execute, isNotNull); + expect(ref.execute, isNotNull); }); testWidgets('should have generated correct MutationRef using name', (WidgetTester tester) async { - final ref = - MoviesConnector.instance.addPerson.ref().name('Keanu Reeves'); + final ref = MoviesConnector.instance.addPerson().name('Keanu Reeves'); expect(ref, isNotNull); - expect(ref.build().execute, isNotNull); + expect(ref.execute, isNotNull); }); testWidgets('should have generated correct MutationRef using nested id', (WidgetTester tester) async { - final ref = MoviesConnector.instance.addDirectorToMovie - .ref() + final ref = MoviesConnector.instance + .addDirectorToMovie() .movieId('movieId') .personId(AddDirectorToMovieVariablesPersonId(id: 'personId')); expect(ref, isNotNull); - expect(ref.build().execute, isNotNull); + expect(ref.execute, isNotNull); }); }, ); diff --git a/packages/firebase_data_connect/firebase_data_connect/example/integration_test/listen_e2e.dart b/packages/firebase_data_connect/firebase_data_connect/example/integration_test/listen_e2e.dart index 2d4145994600..c8cfffaa9431 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/integration_test/listen_e2e.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/integration_test/listen_e2e.dart @@ -21,7 +21,7 @@ void runListenTests() { testWidgets('should be able to listen to the list of movies', (WidgetTester tester) async { final initialValue = - await MoviesConnector.instance.listMovies.ref().build().execute(); + await MoviesConnector.instance.listMovies().ref().execute(); expect(initialValue.data.movies.length, 0, reason: 'Initial movie list should be empty'); @@ -29,9 +29,9 @@ void runListenTests() { final Completer hasBeenListened = Completer(); int count = 0; - final listener = MoviesConnector.instance.listMovies + final listener = MoviesConnector.instance + .listMovies() .ref() - .build() .subscribe() .listen((value) { final movies = value.data.movies; @@ -54,17 +54,17 @@ void runListenTests() { await isReady.future; // Create the movie - await MoviesConnector.instance.createMovie - .ref( + await MoviesConnector.instance + .createMovie( genre: 'Action', title: 'The Matrix', releaseYear: 1999, ) .rating(4.5) - .build() + .ref() .execute(); - await MoviesConnector.instance.listMovies.ref().build().execute(); + await MoviesConnector.instance.listMovies().ref().execute(); // Wait for the listener to receive the movie update final bool hasListenerReceived = await hasBeenListened.future; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/integration_test/query_e2e.dart b/packages/firebase_data_connect/firebase_data_connect/example/integration_test/query_e2e.dart index c262e4035a6c..4ef24e41b467 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/integration_test/query_e2e.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/integration_test/query_e2e.dart @@ -7,14 +7,10 @@ import 'package:firebase_data_connect_example/generated/movies.dart'; import 'package:flutter_test/flutter_test.dart'; Future deleteAllMovies() async { - final value = - await MoviesConnector.instance.listMovies.ref().build().execute(); + final value = await MoviesConnector.instance.listMovies().ref().execute(); final result = value.data; for (var movie in result.movies) { - await MoviesConnector.instance.deleteMovie - .ref(id: movie.id) - .build() - .execute(); + await MoviesConnector.instance.deleteMovie(id: movie.id).ref().execute(); } } @@ -28,78 +24,76 @@ void runQueryTests() { testWidgets('can query', (WidgetTester tester) async { final value = - await MoviesConnector.instance.listMovies.ref().build().execute(); + await MoviesConnector.instance.listMovies().ref().execute(); final result = value.data; expect(result.movies.length, 0); }); testWidgets('can add a movie', (WidgetTester tester) async { - MutationRef ref = MoviesConnector.instance.createMovie - .ref( + MutationRef ref = MoviesConnector.instance + .createMovie( genre: 'Action', title: 'The Matrix', releaseYear: 1999, ) .rating(4.5) - .build(); + .ref(); await ref.execute(); final value = - await MoviesConnector.instance.listMovies.ref().build().execute(); + await MoviesConnector.instance.listMovies().ref().execute(); final result = value.data; expect(result.movies.length, 1); expect(result.movies[0].title, 'The Matrix'); }); testWidgets('can add a director to a movie', (WidgetTester tester) async { - MutationRef ref = MoviesConnector.instance.addPerson - .ref() - .name('Keanu Reeves') - .build(); + MutationRef ref = + MoviesConnector.instance.addPerson().name('Keanu Reeves').ref(); await ref.execute(); final personId = - (await MoviesConnector.instance.listPersons.ref().build().execute()) + (await MoviesConnector.instance.listPersons().ref().execute()) .data .people[0] .id; final value = - await MoviesConnector.instance.listMovies.ref().build().execute(); + await MoviesConnector.instance.listMovies().ref().execute(); final result = value.data; expect(result.movies.length, 0); - ref = MoviesConnector.instance.createMovie - .ref( + ref = MoviesConnector.instance + .createMovie( genre: 'Action', title: 'The Matrix', releaseYear: 1999, ) .rating(4.5) - .build(); + .ref(); await ref.execute(); final value2 = - await MoviesConnector.instance.listMovies.ref().build().execute(); + await MoviesConnector.instance.listMovies().ref().execute(); final result2 = value2.data; expect(result2.movies.length, 1); final movieId = result2.movies[0].id; - ref = MoviesConnector.instance.addDirectorToMovie - .ref() + ref = MoviesConnector.instance + .addDirectorToMovie() .movieId(movieId) .personId(AddDirectorToMovieVariablesPersonId(id: personId)) - .build(); + .ref(); await ref.execute(); final value3 = - await MoviesConnector.instance.listMovies.ref().build().execute(); + await MoviesConnector.instance.listMovies().ref().execute(); final result3 = value3.data; expect(result3.movies.length, 1); expect(result3.movies[0].directed_by.length, 1); @@ -107,30 +101,30 @@ void runQueryTests() { }); testWidgets('can delete a movie', (WidgetTester tester) async { - MutationRef ref = MoviesConnector.instance.createMovie - .ref( + MutationRef ref = MoviesConnector.instance + .createMovie( genre: 'Action', title: 'The Matrix', releaseYear: 1999, ) .rating(4.5) - .build(); + .ref(); await ref.execute(); final value = - await MoviesConnector.instance.listMovies.ref().build().execute(); + await MoviesConnector.instance.listMovies().ref().execute(); final result = value.data; expect(result.movies.length, 1); final movieId = result.movies[0].id; - ref = MoviesConnector.instance.deleteMovie.ref(id: movieId).build(); + ref = MoviesConnector.instance.deleteMovie(id: movieId).ref(); await ref.execute(); final value2 = - await MoviesConnector.instance.listMovies.ref().build().execute(); + await MoviesConnector.instance.listMovies().ref().execute(); final result2 = value2.data; expect(result2.movies.length, 0); }); diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_date_and_timestamp.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_date_and_timestamp.dart index 22cadd25caf6..a47e74d62b5b 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_date_and_timestamp.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_date_and_timestamp.dart @@ -15,7 +15,12 @@ class AddDateAndTimestampVariablesBuilder { (dynamic json) => AddDateAndTimestampData.fromJson(jsonDecode(json)); Serializer varsSerializer = (AddDateAndTimestampVariables vars) => jsonEncode(vars.toJson()); - MutationRef build() { + Future> + execute() { + return this.ref().execute(); + } + + MutationRef ref() { AddDateAndTimestampVariables vars = AddDateAndTimestampVariables( date: date, timestamp: timestamp, @@ -26,23 +31,6 @@ class AddDateAndTimestampVariablesBuilder { } } -class AddDateAndTimestamp { - String name = "addDateAndTimestamp"; - AddDateAndTimestamp({required this.dataConnect}); - AddDateAndTimestampVariablesBuilder ref({ - required DateTime date, - required Timestamp timestamp, - }) { - return AddDateAndTimestampVariablesBuilder( - dataConnect, - date: date, - timestamp: timestamp, - ); - } - - FirebaseDataConnect dataConnect; -} - class AddDateAndTimestampTimestampHolderInsert { String id; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_director_to_movie.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_director_to_movie.dart index f0170c7bc70a..62879fd75d0f 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_director_to_movie.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_director_to_movie.dart @@ -24,7 +24,12 @@ class AddDirectorToMovieVariablesBuilder { (dynamic json) => AddDirectorToMovieData.fromJson(jsonDecode(json)); Serializer varsSerializer = (AddDirectorToMovieVariables vars) => jsonEncode(vars.toJson()); - MutationRef build() { + Future> + execute() { + return this.ref().execute(); + } + + MutationRef ref() { AddDirectorToMovieVariables vars = AddDirectorToMovieVariables( personId: _personId, movieId: _movieId, @@ -35,18 +40,6 @@ class AddDirectorToMovieVariablesBuilder { } } -class AddDirectorToMovie { - String name = "addDirectorToMovie"; - AddDirectorToMovie({required this.dataConnect}); - AddDirectorToMovieVariablesBuilder ref() { - return AddDirectorToMovieVariablesBuilder( - dataConnect, - ); - } - - FirebaseDataConnect dataConnect; -} - class AddDirectorToMovieDirectedByInsert { String directedbyId; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_person.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_person.dart index f31befd81d12..e5773420278c 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_person.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_person.dart @@ -16,7 +16,11 @@ class AddPersonVariablesBuilder { (dynamic json) => AddPersonData.fromJson(jsonDecode(json)); Serializer varsSerializer = (AddPersonVariables vars) => jsonEncode(vars.toJson()); - MutationRef build() { + Future> execute() { + return this.ref().execute(); + } + + MutationRef ref() { AddPersonVariables vars = AddPersonVariables( name: _name, ); @@ -26,18 +30,6 @@ class AddPersonVariablesBuilder { } } -class AddPerson { - String name = "addPerson"; - AddPerson({required this.dataConnect}); - AddPersonVariablesBuilder ref() { - return AddPersonVariablesBuilder( - dataConnect, - ); - } - - FirebaseDataConnect dataConnect; -} - class AddPersonPersonInsert { String id; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_timestamp.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_timestamp.dart index 6fd98d0adc88..9a5f4266026e 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_timestamp.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/add_timestamp.dart @@ -13,7 +13,11 @@ class AddTimestampVariablesBuilder { (dynamic json) => AddTimestampData.fromJson(jsonDecode(json)); Serializer varsSerializer = (AddTimestampVariables vars) => jsonEncode(vars.toJson()); - MutationRef build() { + Future> execute() { + return this.ref().execute(); + } + + MutationRef ref() { AddTimestampVariables vars = AddTimestampVariables( timestamp: timestamp, ); @@ -23,21 +27,6 @@ class AddTimestampVariablesBuilder { } } -class AddTimestamp { - String name = "addTimestamp"; - AddTimestamp({required this.dataConnect}); - AddTimestampVariablesBuilder ref({ - required Timestamp timestamp, - }) { - return AddTimestampVariablesBuilder( - dataConnect, - timestamp: timestamp, - ); - } - - FirebaseDataConnect dataConnect; -} - class AddTimestampTimestampHolderInsert { String id; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/create_movie.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/create_movie.dart index a685dc465dc1..3a3dbed47186 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/create_movie.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/create_movie.dart @@ -29,7 +29,11 @@ class CreateMovieVariablesBuilder { (dynamic json) => CreateMovieData.fromJson(jsonDecode(json)); Serializer varsSerializer = (CreateMovieVariables vars) => jsonEncode(vars.toJson()); - MutationRef build() { + Future> execute() { + return this.ref().execute(); + } + + MutationRef ref() { CreateMovieVariables vars = CreateMovieVariables( title: title, releaseYear: releaseYear, @@ -43,25 +47,6 @@ class CreateMovieVariablesBuilder { } } -class CreateMovie { - String name = "createMovie"; - CreateMovie({required this.dataConnect}); - CreateMovieVariablesBuilder ref({ - required String title, - required int releaseYear, - required String genre, - }) { - return CreateMovieVariablesBuilder( - dataConnect, - title: title, - releaseYear: releaseYear, - genre: genre, - ); - } - - FirebaseDataConnect dataConnect; -} - class CreateMovieMovieInsert { String id; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/delete_movie.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/delete_movie.dart index 326b0b9f9cdb..1b3edbe71cef 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/delete_movie.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/delete_movie.dart @@ -13,7 +13,11 @@ class DeleteMovieVariablesBuilder { (dynamic json) => DeleteMovieData.fromJson(jsonDecode(json)); Serializer varsSerializer = (DeleteMovieVariables vars) => jsonEncode(vars.toJson()); - MutationRef build() { + Future> execute() { + return this.ref().execute(); + } + + MutationRef ref() { DeleteMovieVariables vars = DeleteMovieVariables( id: id, ); @@ -23,21 +27,6 @@ class DeleteMovieVariablesBuilder { } } -class DeleteMovie { - String name = "deleteMovie"; - DeleteMovie({required this.dataConnect}); - DeleteMovieVariablesBuilder ref({ - required String id, - }) { - return DeleteMovieVariablesBuilder( - dataConnect, - id: id, - ); - } - - FirebaseDataConnect dataConnect; -} - class DeleteMovieMovieDelete { String id; @@ -61,7 +50,9 @@ class DeleteMovieData { DeleteMovieMovieDelete? movie_delete; DeleteMovieData.fromJson(dynamic json) - : movie_delete = DeleteMovieMovieDelete.fromJson(json['movie_delete']) {} + : movie_delete = json['movie_delete'] == null + ? null + : DeleteMovieMovieDelete.fromJson(json['movie_delete']) {} Map toJson() { Map json = {}; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_movies.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_movies.dart index 6d8371f0d472..170559b9a690 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_movies.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_movies.dart @@ -9,22 +9,14 @@ class ListMoviesVariablesBuilder { Deserializer dataDeserializer = (dynamic json) => ListMoviesData.fromJson(jsonDecode(json)); - QueryRef build() { - return _dataConnect.query( - "ListMovies", dataDeserializer, emptySerializer, null); + Future> execute() { + return this.ref().execute(); } -} -class ListMovies { - String name = "ListMovies"; - ListMovies({required this.dataConnect}); - ListMoviesVariablesBuilder ref() { - return ListMoviesVariablesBuilder( - dataConnect, - ); + QueryRef ref() { + return _dataConnect.query( + "ListMovies", dataDeserializer, emptySerializer, null); } - - FirebaseDataConnect dataConnect; } class ListMoviesMovies { @@ -42,7 +34,9 @@ class ListMoviesMovies { directed_by = (json['directed_by'] as List) .map((e) => ListMoviesMoviesDirectedBy.fromJson(e)) .toList(), - rating = nativeFromJson(json['rating']) {} + rating = json['rating'] == null + ? null + : nativeFromJson(json['rating']) {} Map toJson() { Map json = {}; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_movies_by_partial_title.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_movies_by_partial_title.dart index 38eea667b30f..0aeb24a0cad4 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_movies_by_partial_title.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_movies_by_partial_title.dart @@ -13,8 +13,14 @@ class ListMoviesByPartialTitleVariablesBuilder { (dynamic json) => ListMoviesByPartialTitleData.fromJson(jsonDecode(json)); Serializer varsSerializer = (ListMoviesByPartialTitleVariables vars) => jsonEncode(vars.toJson()); + Future< + QueryResult> execute() { + return this.ref().execute(); + } + QueryRef - build() { + ref() { ListMoviesByPartialTitleVariables vars = ListMoviesByPartialTitleVariables( input: input, ); @@ -24,21 +30,6 @@ class ListMoviesByPartialTitleVariablesBuilder { } } -class ListMoviesByPartialTitle { - String name = "ListMoviesByPartialTitle"; - ListMoviesByPartialTitle({required this.dataConnect}); - ListMoviesByPartialTitleVariablesBuilder ref({ - required String input, - }) { - return ListMoviesByPartialTitleVariablesBuilder( - dataConnect, - input: input, - ); - } - - FirebaseDataConnect dataConnect; -} - class ListMoviesByPartialTitleMovies { String id; @@ -52,7 +43,9 @@ class ListMoviesByPartialTitleMovies { : id = nativeFromJson(json['id']), title = nativeFromJson(json['title']), genre = nativeFromJson(json['genre']), - rating = nativeFromJson(json['rating']) {} + rating = json['rating'] == null + ? null + : nativeFromJson(json['rating']) {} Map toJson() { Map json = {}; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_persons.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_persons.dart index cf2d27f2693f..1cbdee8139f8 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_persons.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_persons.dart @@ -9,22 +9,14 @@ class ListPersonsVariablesBuilder { Deserializer dataDeserializer = (dynamic json) => ListPersonsData.fromJson(jsonDecode(json)); - QueryRef build() { - return _dataConnect.query( - "ListPersons", dataDeserializer, emptySerializer, null); + Future> execute() { + return this.ref().execute(); } -} -class ListPersons { - String name = "ListPersons"; - ListPersons({required this.dataConnect}); - ListPersonsVariablesBuilder ref() { - return ListPersonsVariablesBuilder( - dataConnect, - ); + QueryRef ref() { + return _dataConnect.query( + "ListPersons", dataDeserializer, emptySerializer, null); } - - FirebaseDataConnect dataConnect; } class ListPersonsPeople { diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_thing.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_thing.dart index 471682f13c20..50ed195d3723 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_thing.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_thing.dart @@ -17,7 +17,11 @@ class ListThingVariablesBuilder { (dynamic json) => ListThingData.fromJson(jsonDecode(json)); Serializer varsSerializer = (ListThingVariables vars) => jsonEncode(vars.toJson()); - QueryRef build() { + Future> execute() { + return this.ref().execute(); + } + + QueryRef ref() { ListThingVariables vars = ListThingVariables( data: _data, ); @@ -27,18 +31,6 @@ class ListThingVariablesBuilder { } } -class ListThing { - String name = "ListThing"; - ListThing({required this.dataConnect}); - ListThingVariablesBuilder ref() { - return ListThingVariablesBuilder( - dataConnect, - ); - } - - FirebaseDataConnect dataConnect; -} - class ListThingThings { AnyValue title; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_timestamps.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_timestamps.dart index c9efff6081d7..fb3c9e956b53 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_timestamps.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/list_timestamps.dart @@ -9,22 +9,14 @@ class ListTimestampsVariablesBuilder { Deserializer dataDeserializer = (dynamic json) => ListTimestampsData.fromJson(jsonDecode(json)); - QueryRef build() { - return _dataConnect.query( - "ListTimestamps", dataDeserializer, emptySerializer, null); + Future> execute() { + return this.ref().execute(); } -} -class ListTimestamps { - String name = "ListTimestamps"; - ListTimestamps({required this.dataConnect}); - ListTimestampsVariablesBuilder ref() { - return ListTimestampsVariablesBuilder( - dataConnect, - ); + QueryRef ref() { + return _dataConnect.query( + "ListTimestamps", dataDeserializer, emptySerializer, null); } - - FirebaseDataConnect dataConnect; } class ListTimestampsTimestampHolders { @@ -34,7 +26,9 @@ class ListTimestampsTimestampHolders { ListTimestampsTimestampHolders.fromJson(dynamic json) : timestamp = Timestamp.fromJson(json['timestamp']), - date = nativeFromJson(json['date']) {} + date = json['date'] == null + ? null + : nativeFromJson(json['date']) {} Map toJson() { Map json = {}; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/movies.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/movies.dart index c85f61434f19..b936ec498fc1 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/movies.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/movies.dart @@ -32,60 +32,109 @@ part 'list_thing.dart'; part 'list_timestamps.dart'; class MoviesConnector { - AddPerson get addPerson { - return AddPerson(dataConnect: dataConnect); + AddPersonVariablesBuilder addPerson() { + return AddPersonVariablesBuilder( + dataConnect, + ); } - AddDirectorToMovie get addDirectorToMovie { - return AddDirectorToMovie(dataConnect: dataConnect); + AddDirectorToMovieVariablesBuilder addDirectorToMovie() { + return AddDirectorToMovieVariablesBuilder( + dataConnect, + ); } - AddTimestamp get addTimestamp { - return AddTimestamp(dataConnect: dataConnect); + AddTimestampVariablesBuilder addTimestamp({ + required Timestamp timestamp, + }) { + return AddTimestampVariablesBuilder( + dataConnect, + timestamp: timestamp, + ); } - AddDateAndTimestamp get addDateAndTimestamp { - return AddDateAndTimestamp(dataConnect: dataConnect); + AddDateAndTimestampVariablesBuilder addDateAndTimestamp({ + required DateTime date, + required Timestamp timestamp, + }) { + return AddDateAndTimestampVariablesBuilder( + dataConnect, + date: date, + timestamp: timestamp, + ); } - SeedMovies get seedMovies { - return SeedMovies(dataConnect: dataConnect); + SeedMoviesVariablesBuilder seedMovies() { + return SeedMoviesVariablesBuilder( + dataConnect, + ); } - CreateMovie get createMovie { - return CreateMovie(dataConnect: dataConnect); + CreateMovieVariablesBuilder createMovie({ + required String title, + required int releaseYear, + required String genre, + }) { + return CreateMovieVariablesBuilder( + dataConnect, + title: title, + releaseYear: releaseYear, + genre: genre, + ); } - DeleteMovie get deleteMovie { - return DeleteMovie(dataConnect: dataConnect); + DeleteMovieVariablesBuilder deleteMovie({ + required String id, + }) { + return DeleteMovieVariablesBuilder( + dataConnect, + id: id, + ); } - Thing get thing { - return Thing(dataConnect: dataConnect); + ThingVariablesBuilder thing() { + return ThingVariablesBuilder( + dataConnect, + ); } - SeedData get seedData { - return SeedData(dataConnect: dataConnect); + SeedDataVariablesBuilder seedData() { + return SeedDataVariablesBuilder( + dataConnect, + ); } - ListMovies get listMovies { - return ListMovies(dataConnect: dataConnect); + ListMoviesVariablesBuilder listMovies() { + return ListMoviesVariablesBuilder( + dataConnect, + ); } - ListMoviesByPartialTitle get listMoviesByPartialTitle { - return ListMoviesByPartialTitle(dataConnect: dataConnect); + ListMoviesByPartialTitleVariablesBuilder listMoviesByPartialTitle({ + required String input, + }) { + return ListMoviesByPartialTitleVariablesBuilder( + dataConnect, + input: input, + ); } - ListPersons get listPersons { - return ListPersons(dataConnect: dataConnect); + ListPersonsVariablesBuilder listPersons() { + return ListPersonsVariablesBuilder( + dataConnect, + ); } - ListThing get listThing { - return ListThing(dataConnect: dataConnect); + ListThingVariablesBuilder listThing() { + return ListThingVariablesBuilder( + dataConnect, + ); } - ListTimestamps get listTimestamps { - return ListTimestamps(dataConnect: dataConnect); + ListTimestampsVariablesBuilder listTimestamps() { + return ListTimestampsVariablesBuilder( + dataConnect, + ); } static ConnectorConfig connectorConfig = ConnectorConfig( diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/seed_data.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/seed_data.dart index 28757f8f0dcf..1e90fc1136bf 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/seed_data.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/seed_data.dart @@ -9,22 +9,14 @@ class SeedDataVariablesBuilder { Deserializer dataDeserializer = (dynamic json) => SeedDataData.fromJson(jsonDecode(json)); - MutationRef build() { - return _dataConnect.mutation( - "seedData", dataDeserializer, emptySerializer, null); + Future> execute() { + return this.ref().execute(); } -} -class SeedData { - String name = "seedData"; - SeedData({required this.dataConnect}); - SeedDataVariablesBuilder ref() { - return SeedDataVariablesBuilder( - dataConnect, - ); + MutationRef ref() { + return _dataConnect.mutation( + "seedData", dataDeserializer, emptySerializer, null); } - - FirebaseDataConnect dataConnect; } class SeedDataTheMatrix { diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/seed_movies.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/seed_movies.dart index 8fbdb3c19254..833930f98388 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/seed_movies.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/seed_movies.dart @@ -9,22 +9,14 @@ class SeedMoviesVariablesBuilder { Deserializer dataDeserializer = (dynamic json) => SeedMoviesData.fromJson(jsonDecode(json)); - MutationRef build() { - return _dataConnect.mutation( - "seedMovies", dataDeserializer, emptySerializer, null); + Future> execute() { + return this.ref().execute(); } -} -class SeedMovies { - String name = "seedMovies"; - SeedMovies({required this.dataConnect}); - SeedMoviesVariablesBuilder ref() { - return SeedMoviesVariablesBuilder( - dataConnect, - ); + MutationRef ref() { + return _dataConnect.mutation( + "seedMovies", dataDeserializer, emptySerializer, null); } - - FirebaseDataConnect dataConnect; } class SeedMoviesTheMatrix { diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/thing.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/thing.dart index 164eaef843e1..b9b6f3570f43 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/thing.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/generated/thing.dart @@ -17,7 +17,11 @@ class ThingVariablesBuilder { (dynamic json) => ThingData.fromJson(jsonDecode(json)); Serializer varsSerializer = (ThingVariables vars) => jsonEncode(vars.toJson()); - MutationRef build() { + Future> execute() { + return this.ref().execute(); + } + + MutationRef ref() { ThingVariables vars = ThingVariables( title: _title, ); @@ -27,18 +31,6 @@ class ThingVariablesBuilder { } } -class Thing { - String name = "thing"; - Thing({required this.dataConnect}); - ThingVariablesBuilder ref() { - return ThingVariablesBuilder( - dataConnect, - ); - } - - FirebaseDataConnect dataConnect; -} - class ThingThingInsert { String id; diff --git a/packages/firebase_data_connect/firebase_data_connect/example/lib/main.dart b/packages/firebase_data_connect/firebase_data_connect/example/lib/main.dart index 7d085ebe3a36..abe7b9444466 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/lib/main.dart +++ b/packages/firebase_data_connect/firebase_data_connect/example/lib/main.dart @@ -111,7 +111,7 @@ class _DataConnectWidgetState extends State { double _rating = 0; Future triggerReload() async { - QueryRef ref = MoviesConnector.instance.listMovies.ref().build(); + QueryRef ref = MoviesConnector.instance.listMovies().ref(); ref.execute(); } @@ -120,7 +120,7 @@ class _DataConnectWidgetState extends State { super.initState(); QueryRef ref = - MoviesConnector.instance.listMovies.ref().build(); + MoviesConnector.instance.listMovies().ref(); ref.subscribe().listen((event) { setState(() { @@ -195,14 +195,14 @@ class _DataConnectWidgetState extends State { return; } - MutationRef ref = MoviesConnector.instance.createMovie - .ref( + MutationRef ref = MoviesConnector.instance + .createMovie( title: title, releaseYear: _releaseYearDate.year, genre: genre, ) .rating(_rating) - .build(); + .ref(); try { await ref.execute(); triggerReload(); diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/common/common_library.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/common/common_library.dart index f8e9bfb7bbd6..b6ccf1059755 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/common/common_library.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/common/common_library.dart @@ -17,7 +17,6 @@ library firebase_data_connect_common; import 'dart:convert'; import 'package:firebase_app_check/firebase_app_check.dart'; -import 'package:firebase_auth/firebase_auth.dart'; part 'dataconnect_error.dart'; part 'dataconnect_options.dart'; @@ -59,9 +58,6 @@ abstract class DataConnectTransport { /// DataConnect backend configuration. DataConnectOptions options; - /// FirebaseAuth to use to get auth token. - FirebaseAuth? auth; - /// FirebaseAppCheck to use to get app check token. FirebaseAppCheck? appCheck; @@ -76,12 +72,14 @@ abstract class DataConnectTransport { String queryName, Deserializer deserializer, Serializer serializer, - Variables? vars); + Variables? vars, + String? token); /// Invokes corresponding mutation endpoint. Future invokeMutation( String queryName, Deserializer deserializer, Serializer serializer, - Variables? vars); + Variables? vars, + String? token); } diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/core/ref.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/core/ref.dart index ce865ebaa766..68f528ceff78 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/core/ref.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/core/ref.dart @@ -42,10 +42,18 @@ abstract class OperationRef { DataConnectTransport _transport; Deserializer deserializer; Serializer serializer; + String? _lastToken; FirebaseDataConnect dataConnect; Future> execute(); + Future _shouldRetry() async { + String? newToken = + await this.dataConnect.auth?.currentUser?.getIdToken(false); + bool shouldRetry = newToken != null && _lastToken != newToken; + _lastToken = newToken; + return shouldRetry; + } } /// Tracks currently active queries, and emits events when a new query is executed. @@ -112,11 +120,29 @@ class QueryRef extends OperationRef { variables); QueryManager _queryManager; + @override Future> execute() async { + bool shouldRetry = await _shouldRetry(); + try { + QueryResult r = await this._executeOperation(_lastToken); + return r; + } on DataConnectError catch (e) { + if (shouldRetry && + e.code == DataConnectErrorCode.unauthorized.toString()) { + return this.execute(); + } else { + throw e; + } + } catch (e) { + throw e; + } + } + + Future> _executeOperation(String? token) async { try { Data data = await _transport.invokeQuery( - operationName, deserializer, serializer, variables); + operationName, deserializer, serializer, variables, token); QueryResult res = QueryResult(dataConnect, data, this); await _queryManager.triggerCallback(operationName, serializer(variables as Variables), this, res.data, null); @@ -155,10 +181,32 @@ class MutationRef extends OperationRef { Variables? variables, ) : super(dataConnect, operationName, transport, deserializer, serializer, variables); + @override Future> execute() async { + bool shouldRetry = await _shouldRetry(); + try { + // Logic below is duplicated due to the fact that `executeOperation` returns + // an `OperationResult` here, and `QueryRef` expects a `QueryResult`. + OperationResult r = + await this._executeOperation(_lastToken); + return r; + } on DataConnectError catch (e) { + if (shouldRetry && + e.code == DataConnectErrorCode.unauthorized.toString()) { + return this.execute(); + } else { + throw e; + } + } catch (e) { + throw e; + } + } + + Future> _executeOperation( + String? token) async { Data data = await _transport.invokeMutation( - operationName, deserializer, serializer, variables); + operationName, deserializer, serializer, variables, token); return OperationResult(dataConnect, data, this); } } diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart index f979366105bd..d3c677929a5b 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart @@ -80,8 +80,8 @@ class FirebaseDataConnect extends FirebasePluginPlatform { void checkTransport() { transportOptions ??= TransportOptions('firebasedataconnect.googleapis.com', null, true); - transport = getTransport(transportOptions!, options, app.options.appId, - _sdkType, auth, appCheck); + transport = getTransport( + transportOptions!, options, app.options.appId, _sdkType, appCheck); } /// Returns a [QueryRef] object. diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/grpc_library.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/grpc_library.dart index a3e53bff84ac..804a34eb192f 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/grpc_library.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/grpc_library.dart @@ -18,7 +18,6 @@ import 'dart:convert'; import 'dart:developer'; import 'package:firebase_app_check/firebase_app_check.dart'; -import 'package:firebase_auth/firebase_auth.dart'; import 'package:grpc/grpc.dart'; import '../common/common_library.dart'; diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/grpc_transport.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/grpc_transport.dart index 7956f9e1c1e2..695259487178 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/grpc_transport.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/grpc_transport.dart @@ -22,7 +22,6 @@ class GRPCTransport implements DataConnectTransport { this.options, this.appId, this.sdkType, - this.auth, this.appCheck, ) { bool isSecure = @@ -38,10 +37,6 @@ class GRPCTransport implements DataConnectTransport { 'projects/${options.projectId}/locations/${options.location}/services/${options.serviceId}/connectors/${options.connector}'; } - /// FirebaseAuth - @override - FirebaseAuth? auth; - /// FirebaseAppCheck @override FirebaseAppCheck? appCheck; @@ -70,13 +65,7 @@ class GRPCTransport implements DataConnectTransport { @override String appId; - Future> getMetadata() async { - String? authToken; - try { - authToken = await auth?.currentUser?.getIdToken(); - } catch (e) { - log('Unable to get auth token: $e'); - } + Future> getMetadata(String? authToken) async { String? appCheckToken; try { appCheckToken = await appCheck?.getToken(); @@ -101,11 +90,11 @@ class GRPCTransport implements DataConnectTransport { /// Invokes GPRC query endpoint. @override Future invokeQuery( - String queryName, - Deserializer deserializer, - Serializer? serializer, - Variables? vars, - ) async { + String queryName, + Deserializer deserializer, + Serializer? serializer, + Variables? vars, + String? authToken) async { ExecuteQueryResponse response; ExecuteQueryRequest request = @@ -115,9 +104,13 @@ class GRPCTransport implements DataConnectTransport { } try { response = await stub.executeQuery(request, - options: CallOptions(metadata: await getMetadata())); + options: CallOptions(metadata: await getMetadata(authToken))); return deserializer(jsonEncode(response.data.toProto3Json())); } on Exception catch (e) { + if (e.toString().contains("invalid Firebase Auth Credentials")) { + throw DataConnectError(DataConnectErrorCode.unauthorized, + 'Failed to invoke operation: ${e.toString()}'); + } throw DataConnectError(DataConnectErrorCode.other, 'Failed to invoke operation: ${e.toString()}'); } @@ -137,7 +130,8 @@ class GRPCTransport implements DataConnectTransport { String queryName, Deserializer deserializer, Serializer? serializer, - Variables? vars) async { + Variables? vars, + String? authToken) async { ExecuteMutationResponse response; ExecuteMutationRequest request = ExecuteMutationRequest(name: name, operationName: queryName); @@ -146,7 +140,7 @@ class GRPCTransport implements DataConnectTransport { } try { response = await stub.executeMutation(request, - options: CallOptions(metadata: await getMetadata())); + options: CallOptions(metadata: await getMetadata(authToken))); if (response.errors.isNotEmpty) { throw Exception(response.errors); } @@ -164,6 +158,5 @@ DataConnectTransport getTransport( DataConnectOptions options, String appId, CallerSDKType sdkType, - FirebaseAuth? auth, FirebaseAppCheck? appCheck) => - GRPCTransport(transportOptions, options, appId, sdkType, auth, appCheck); + GRPCTransport(transportOptions, options, appId, sdkType, appCheck); diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/rest_library.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/rest_library.dart index fe0c852a3d20..c35015cb9a50 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/rest_library.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/rest_library.dart @@ -18,7 +18,6 @@ import 'dart:convert'; import 'dart:developer'; import 'package:firebase_app_check/firebase_app_check.dart'; -import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/rest_transport.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/rest_transport.dart index 7836fa523f65..c8fb389288fd 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/rest_transport.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/rest_transport.dart @@ -18,7 +18,7 @@ part of firebase_data_connect_rest; class RestTransport implements DataConnectTransport { /// Initializes necessary protocol and port. RestTransport(this.transportOptions, this.options, this.appId, this.sdkType, - this.auth, this.appCheck) { + this.appCheck) { String protocol = 'http'; if (transportOptions.isSecure == null || transportOptions.isSecure == true) { @@ -34,9 +34,6 @@ class RestTransport implements DataConnectTransport { '$protocol://$host:$port/v1beta/projects/$project/locations/$location/services/$service/connectors/$connector'; } - @override - FirebaseAuth? auth; - @override FirebaseAppCheck? appCheck; @@ -67,11 +64,13 @@ class RestTransport implements DataConnectTransport { /// Invokes the current operation, whether its a query or mutation. Future invokeOperation( - String queryName, - Deserializer deserializer, - Serializer? serializer, - Variables? vars, - String endpoint) async { + String queryName, + String endpoint, + Deserializer deserializer, + Serializer? serializer, + Variables? vars, + String? authToken, + ) async { String project = options.projectId; String location = options.location; String service = options.serviceId; @@ -81,12 +80,6 @@ class RestTransport implements DataConnectTransport { 'Accept': 'application/json', 'x-goog-api-client': getGoogApiVal(sdkType, packageVersion) }; - String? authToken; - try { - authToken = await auth?.currentUser?.getIdToken(); - } catch (e) { - log('Unable to get auth token: $e'); - } String? appCheckToken; try { appCheckToken = await appCheck?.getToken(); @@ -148,25 +141,25 @@ class RestTransport implements DataConnectTransport { /// Invokes query REST endpoint. @override Future invokeQuery( - String queryName, - Deserializer deserializer, - Serializer? serializer, - Variables? vars, - ) async { + String queryName, + Deserializer deserializer, + Serializer? serializer, + Variables? vars, + String? token) async { return invokeOperation( - queryName, deserializer, serializer, vars, 'executeQuery'); + queryName, 'executeQuery', deserializer, serializer, vars, token); } /// Invokes mutation REST endpoint. @override Future invokeMutation( - String queryName, - Deserializer deserializer, - Serializer? serializer, - Variables? vars, - ) async { + String queryName, + Deserializer deserializer, + Serializer? serializer, + Variables? vars, + String? token) async { return invokeOperation( - queryName, deserializer, serializer, vars, 'executeMutation'); + queryName, 'executeMutation', deserializer, serializer, vars, token); } } @@ -176,6 +169,5 @@ DataConnectTransport getTransport( DataConnectOptions options, String appId, CallerSDKType sdkType, - FirebaseAuth? auth, FirebaseAppCheck? appCheck) => - RestTransport(transportOptions, options, appId, sdkType, auth, appCheck); + RestTransport(transportOptions, options, appId, sdkType, appCheck); diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/transport_library.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/transport_library.dart index 840e6caae3c2..6da4450bc490 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/transport_library.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/transport_library.dart @@ -15,7 +15,6 @@ library firebase_data_connect_transport; import 'package:firebase_app_check/firebase_app_check.dart'; -import 'package:firebase_auth/firebase_auth.dart'; import '../common/common_library.dart'; part 'transport_stub.dart'; diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/transport_stub.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/transport_stub.dart index 69861cfb6956..2a08e06aa236 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/network/transport_stub.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/network/transport_stub.dart @@ -22,13 +22,11 @@ class TransportStub implements DataConnectTransport { this.options, this.appId, this.sdkType, - this.auth, this.appCheck, ); /// FirebaseAuth @override - FirebaseAuth? auth; /// FirebaseAppCheck @override @@ -55,7 +53,8 @@ class TransportStub implements DataConnectTransport { String queryName, Deserializer deserializer, Serializer? serializer, - Variables? vars) async { + Variables? vars, + String? token) async { // TODO: implement invokeMutation throw UnimplementedError(); } @@ -66,7 +65,8 @@ class TransportStub implements DataConnectTransport { String queryName, Deserializer deserializer, Serializer? serialize, - Variables? vars) async { + Variables? vars, + String? token) async { // TODO: implement invokeQuery throw UnimplementedError(); } @@ -77,7 +77,6 @@ DataConnectTransport getTransport( DataConnectOptions options, String appId, CallerSDKType sdkType, - FirebaseAuth? auth, FirebaseAppCheck? appCheck, ) => - TransportStub(transportOptions, options, appId, sdkType, auth, appCheck); + TransportStub(transportOptions, options, appId, sdkType, appCheck); diff --git a/packages/firebase_data_connect/firebase_data_connect/test/src/common/common_library_test.dart b/packages/firebase_data_connect/firebase_data_connect/test/src/common/common_library_test.dart index d5f4f4358760..6f9e5e42425e 100644 --- a/packages/firebase_data_connect/firebase_data_connect/test/src/common/common_library_test.dart +++ b/packages/firebase_data_connect/firebase_data_connect/test/src/common/common_library_test.dart @@ -105,7 +105,7 @@ void main() { final queryName = 'testQuery'; final deserializer = (json) => json; final result = await transport.invokeQuery( - queryName, deserializer, emptySerializer, null); + queryName, deserializer, emptySerializer, null, null); expect(result, isNotNull); }); @@ -114,7 +114,7 @@ void main() { final queryName = 'testMutation'; final deserializer = (json) => json; final result = await transport.invokeMutation( - queryName, deserializer, emptySerializer, null); + queryName, deserializer, emptySerializer, null, null); expect(result, isNotNull); }); @@ -127,28 +127,27 @@ class TestDataConnectTransport extends DataConnectTransport { DataConnectOptions options, String appId, CallerSDKType sdkType, {FirebaseAuth? auth, FirebaseAppCheck? appCheck}) : super(transportOptions, options, appId, sdkType) { - this.auth = auth; this.appCheck = appCheck; } @override Future invokeQuery( - String queryName, - Deserializer deserializer, - Serializer? serializer, - Variables? vars, - ) async { + String queryName, + Deserializer deserializer, + Serializer? serializer, + Variables? vars, + String? authToken) async { // Simulate query invocation logic here return deserializer('{}'); } @override Future invokeMutation( - String queryName, - Deserializer deserializer, - Serializer? serializer, - Variables? vars, - ) async { + String queryName, + Deserializer deserializer, + Serializer? serializer, + Variables? vars, + String? authToken) async { // Simulate mutation invocation logic here return deserializer('{}'); } diff --git a/packages/firebase_data_connect/firebase_data_connect/test/src/core/ref_test.dart b/packages/firebase_data_connect/firebase_data_connect/test/src/core/ref_test.dart index b1930827da7a..d6a66907499d 100644 --- a/packages/firebase_data_connect/firebase_data_connect/test/src/core/ref_test.dart +++ b/packages/firebase_data_connect/firebase_data_connect/test/src/core/ref_test.dart @@ -15,18 +15,38 @@ // ignore_for_file: unused_local_variable import 'dart:async'; +import 'package:http/http.dart' as http; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_data_connect/firebase_data_connect.dart'; import 'package:firebase_data_connect/src/common/common_library.dart'; import 'package:firebase_data_connect/src/core/ref.dart'; +import 'package:firebase_data_connect/src/network/rest_library.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; +import '../network/rest_transport_test.mocks.dart'; + // Mock classes class MockDataConnectTransport extends Mock implements DataConnectTransport {} class MockFirebaseDataConnect extends Mock implements FirebaseDataConnect {} +class DCMockUser extends Mock implements User { + int count = 0; + List tokens = ['invalid-token', 'valid-token']; + @override + Future getIdToken([bool forceRefresh = false]) { + // First return an invalid token, then return a valid token + return Future.value(tokens[count++]); + } +} + +class MockFirebaseAuth extends Mock implements FirebaseAuth { + @override + User? get currentUser => DCMockUser(); +} + class MockQueryManager extends Mock implements QueryManager {} class MockOperationRef extends Mock implements OperationRef {} @@ -96,4 +116,54 @@ void main() { deserializer = (data) => 'deserializedData'; }); }); + group('QueryRef', () { + late RestTransport transport; + late MockFirebaseDataConnect mockDataConnect; + late Serializer serializer; + late MockClient mockHttpClient; + late Deserializer deserializer; + + setUp(() { + mockDataConnect = MockFirebaseDataConnect(); + when(mockDataConnect.auth).thenReturn(MockFirebaseAuth()); + mockHttpClient = MockClient(); + transport = RestTransport( + TransportOptions('testhost', 443, true), + DataConnectOptions( + 'testProject', + 'testLocation', + 'testConnector', + 'testService', + ), + 'testAppId', + CallerSDKType.core, + null, + ); + transport.setHttp(mockHttpClient); + mockDataConnect.transport = transport; + }); + test( + 'query should forceRefresh on ID token if the first request is unauthorized', + () async { + final mockResponse = http.Response('{"error": "Unauthorized"}', 401); + final mockResponseSuccess = http.Response('{"success": true}', 200); + final deserializer = (String data) => 'Deserialized Data'; + int count = 0; + QueryRef ref = QueryRef(mockDataConnect, 'operation', transport, + deserializer, QueryManager(mockDataConnect), emptySerializer, null); + + when(mockHttpClient.post(any, + headers: anyNamed('headers'), body: anyNamed('body'))) + .thenAnswer((invocation) => [ + Future.value(mockResponse), + Future.value(mockResponseSuccess), + ][count++]); + final result = await ref.execute(); + + expect(result.data, 'Deserialized Data'); + verify(mockHttpClient.post(any, + headers: anyNamed('headers'), body: anyNamed('body'))) + .called(2); + }); + }); } diff --git a/packages/firebase_data_connect/firebase_data_connect/test/src/network/rest_transport_test.dart b/packages/firebase_data_connect/firebase_data_connect/test/src/network/rest_transport_test.dart index 62bb26735804..af891aa12f07 100644 --- a/packages/firebase_data_connect/firebase_data_connect/test/src/network/rest_transport_test.dart +++ b/packages/firebase_data_connect/firebase_data_connect/test/src/network/rest_transport_test.dart @@ -52,7 +52,6 @@ void main() { ), 'testAppId', CallerSDKType.core, - mockAuth, mockAppCheck, ); @@ -78,7 +77,6 @@ void main() { ), 'testAppId', CallerSDKType.core, - mockAuth, mockAppCheck, ); @@ -98,10 +96,11 @@ void main() { final result = await transport.invokeOperation( 'testQuery', + 'executeQuery', deserializer, null, null, - 'executeQuery', + null, ); expect(result, 'Deserialized Data'); @@ -118,7 +117,7 @@ void main() { expect( () => transport.invokeOperation( - 'testQuery', deserializer, null, null, 'executeQuery'), + 'testQuery', 'executeQuery', deserializer, null, null, null), throwsA(isA()), ); }); @@ -134,7 +133,7 @@ void main() { expect( () => transport.invokeOperation( - 'testQuery', deserializer, null, null, 'executeQuery'), + 'testQuery', 'executeQuery', deserializer, null, null, null), throwsA(isA()), ); }); @@ -148,7 +147,7 @@ void main() { final deserializer = (String data) => 'Deserialized Data'; - await transport.invokeQuery('testQuery', deserializer, null, null); + await transport.invokeQuery('testQuery', deserializer, null, null, null); verify(mockHttpClient.post( any, @@ -170,7 +169,8 @@ void main() { final deserializer = (String data) => 'Deserialized Mutation Data'; - await transport.invokeMutation('testMutation', deserializer, null, null); + await transport.invokeMutation( + 'testMutation', deserializer, null, null, null); verify(mockHttpClient.post( any, @@ -195,8 +195,8 @@ void main() { final deserializer = (String data) => 'Deserialized Data'; - await transport.invokeOperation( - 'testQuery', deserializer, null, null, 'executeQuery'); + await transport.invokeOperation('testQuery', 'executeQuery', deserializer, + null, null, 'authToken123'); verify(mockHttpClient.post( any, @@ -222,7 +222,7 @@ void main() { final deserializer = (String data) => 'Deserialized Data'; await transport.invokeOperation( - 'testQuery', deserializer, null, null, 'executeQuery'); + 'testQuery', 'executeQuery', deserializer, null, null, null); verify(mockHttpClient.post( any, @@ -257,7 +257,7 @@ void main() { expect( () => transport.invokeOperation( - 'testQuery', deserializer, null, null, 'executeQuery'), + 'testQuery', 'executeQuery', deserializer, null, null, null), throwsA(isA()), ); }); diff --git a/packages/firebase_data_connect/firebase_data_connect/test/src/network/transport_stub_test.dart b/packages/firebase_data_connect/firebase_data_connect/test/src/network/transport_stub_test.dart index e72a7a55ece0..0382771ae660 100644 --- a/packages/firebase_data_connect/firebase_data_connect/test/src/network/transport_stub_test.dart +++ b/packages/firebase_data_connect/firebase_data_connect/test/src/network/transport_stub_test.dart @@ -30,13 +30,11 @@ class MockDataConnectOptions extends Mock implements DataConnectOptions {} void main() { group('TransportStub', () { - late MockFirebaseAuth mockAuth; late MockFirebaseAppCheck mockAppCheck; late MockTransportOptions mockTransportOptions; late MockDataConnectOptions mockDataConnectOptions; setUp(() { - mockAuth = MockFirebaseAuth(); mockAppCheck = MockFirebaseAppCheck(); mockTransportOptions = MockTransportOptions(); mockDataConnectOptions = MockDataConnectOptions(); @@ -48,11 +46,9 @@ void main() { mockDataConnectOptions, 'mockAppId', CallerSDKType.core, - mockAuth, mockAppCheck, ); - expect(transportStub.auth, equals(mockAuth)); expect(transportStub.appCheck, equals(mockAppCheck)); expect(transportStub.transportOptions, equals(mockTransportOptions)); expect(transportStub.options, equals(mockDataConnectOptions)); @@ -64,7 +60,6 @@ void main() { mockDataConnectOptions, 'mockAppId', CallerSDKType.core, - mockAuth, mockAppCheck, ); @@ -74,6 +69,7 @@ void main() { (json) => json, null, null, + null, ), throwsA(isA()), ); @@ -85,17 +81,12 @@ void main() { mockDataConnectOptions, 'mockAppId', CallerSDKType.core, - mockAuth, mockAppCheck, ); expect( () async => await transportStub.invokeQuery( - 'queryName', - (json) => json, - null, - null, - ), + 'queryName', (json) => json, null, null, null), throwsA(isA()), ); });