Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
60 changes: 30 additions & 30 deletions packages/_flutterfire_internals/lib/_flutterfire_internals.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import 'src/interop_shimmer.dart'
if (dart.library.js_interop) 'package:firebase_core_web/firebase_core_web_interop.dart'
as core_interop;
import 'src/interop_shimmer.dart'
if (dart.library.js_interop) 'src/js_interop.dart' as js_interop;
if (dart.library.js_interop) 'src/js_interop.dart'
as js_interop;

export 'src/exception.dart';

Expand Down Expand Up @@ -70,17 +71,14 @@ FirebaseException _firebaseExceptionFromCoreFirebaseError(
final convertCode = _safeConvertFromPossibleJSObject(firebaseError.code);
final code = codeParser(convertCode);

final String convertMessage =
_safeConvertFromPossibleJSObject(firebaseError.message);
final String convertMessage = _safeConvertFromPossibleJSObject(
firebaseError.message,
);
final message = messageParser != null
? messageParser(code, convertMessage)
: convertMessage.replaceFirst('(${firebaseError.code})', '');

return FirebaseException(
plugin: plugin,
message: message,
code: code,
);
return FirebaseException(plugin: plugin, message: message, code: code);
}

/// Checks whether a thrown object needs to be mapped using [_mapException] or
Expand Down Expand Up @@ -135,30 +133,32 @@ R guardWebExceptions<R>(

if (value is Future) {
return value.catchError(
(err, stack) => Error.throwWithStackTrace(
_mapException(
err,
plugin: plugin,
codeParser: codeParser,
messageParser: messageParser,
),
stack,
),
test: _testException,
) as R;
(err, stack) => Error.throwWithStackTrace(
_mapException(
err,
plugin: plugin,
codeParser: codeParser,
messageParser: messageParser,
),
stack,
),
test: _testException,
)
as R;
} else if (value is Stream) {
return value.handleError(
(err, stack) => Error.throwWithStackTrace(
_mapException(
err,
plugin: plugin,
codeParser: codeParser,
messageParser: messageParser,
),
stack,
),
test: _testException,
) as R;
(err, stack) => Error.throwWithStackTrace(
_mapException(
err,
plugin: plugin,
codeParser: codeParser,
messageParser: messageParser,
),
stack,
),
test: _testException,
)
as R;
}

return value;
Expand Down
4 changes: 2 additions & 2 deletions packages/_flutterfire_internals/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ version: 1.3.77
resolution: workspace

environment:
sdk: '^3.6.0'
flutter: '>=3.27.0'
sdk: '^3.10.0'
flutter: '>=3.38.0'

dependencies:
collection: ^1.0.0
Expand Down
3 changes: 2 additions & 1 deletion packages/_flutterfire_internals/test/exception_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ void main() {
message: 'a channel level message',
details: {
'code': 'permission-denied',
'message': "Client doesn't have permission to access the desired "
'message':
"Client doesn't have permission to access the desired "
'data.',
},
),
Expand Down
113 changes: 60 additions & 53 deletions packages/_flutterfire_internals/test/guard_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,63 +8,70 @@ import 'package:flutter_test/flutter_test.dart';

void main() {
group('guardWebException', () {
test('preserves stacktrace on futures that fail with FirebaseError',
() async {
final current = StackTrace.current;
try {
await guardWebExceptions(
() => Future.error(_FirebaseError(), current),
plugin: 'test',
codeParser: (c) => c,
);
fail('dead code');
} catch (err, stack) {
expect(stack, current);
}
});
test(
'preserves stacktrace on futures that fail with FirebaseError',
() async {
final current = StackTrace.current;
try {
await guardWebExceptions(
() => Future.error(_FirebaseError(), current),
plugin: 'test',
codeParser: (c) => c,
);
fail('dead code');
} catch (err, stack) {
expect(stack, current);
}
},
);

test('preserves stacktrace on streams that fail with FirebaseError',
() async {
final current = StackTrace.current;
try {
await guardWebExceptions(
() => Stream.error(_FirebaseError(), current),
plugin: 'test',
codeParser: (c) => c,
).first;
fail('dead code');
} catch (err, stack) {
expect(stack, current);
}
});
test(
'preserves stacktrace on streams that fail with FirebaseError',
() async {
final current = StackTrace.current;
try {
await guardWebExceptions(
() => Stream.error(_FirebaseError(), current),
plugin: 'test',
codeParser: (c) => c,
).first;
fail('dead code');
} catch (err, stack) {
expect(stack, current);
}
},
);

test('preserves stacktrace on functions that throw a FirebaseError',
() async {
final current = StackTrace.current;
try {
guardWebExceptions<void>(
() => Error.throwWithStackTrace(_FirebaseError(), current),
plugin: 'test',
codeParser: (c) => c,
);
fail('dead code');
} catch (err, stack) {
expect(stack, current);
}
});
test(
'preserves stacktrace on functions that throw a FirebaseError',
() async {
final current = StackTrace.current;
try {
guardWebExceptions<void>(
() => Error.throwWithStackTrace(_FirebaseError(), current),
plugin: 'test',
codeParser: (c) => c,
);
fail('dead code');
} catch (err, stack) {
expect(stack, current);
}
},
);

test(
'propagates plain Dart errors from Futures (e.g. ArgumentError on web)',
() async {
await expectLater(
guardWebExceptions(
() => Future<void>.error(ArgumentError('test')),
plugin: 'test',
codeParser: (c) => c,
),
throwsA(isA<ArgumentError>()),
);
});
'propagates plain Dart errors from Futures (e.g. ArgumentError on web)',
() async {
await expectLater(
guardWebExceptions(
() => Future<void>.error(ArgumentError('test')),
plugin: 'test',
codeParser: (c) => c,
),
throwsA(isA<ArgumentError>()),
);
},
);
});
}

Expand Down
80 changes: 29 additions & 51 deletions packages/cloud_firestore/cloud_firestore/dartpad/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,20 @@ final moviesRef = FirebaseFirestore.instance
);

/// The different ways that we can filter/sort movies.
enum MovieQuery {
year,
likesAsc,
likesDesc,
score,
sciFi,
fantasy,
}
enum MovieQuery { year, likesAsc, likesDesc, score, sciFi, fantasy }

extension on Query<Movie> {
/// Create a firebase query from a [MovieQuery]
Query<Movie> queryBy(MovieQuery query) {
return switch (query) {
MovieQuery.fantasy => where('genre', arrayContainsAny: ['Fantasy']),
MovieQuery.sciFi => where('genre', arrayContainsAny: ['Sci-Fi']),
MovieQuery.likesAsc ||
MovieQuery.likesDesc =>
orderBy('likes', descending: query == MovieQuery.likesDesc),
MovieQuery.likesAsc || MovieQuery.likesDesc => orderBy(
'likes',
descending: query == MovieQuery.likesDesc,
),
MovieQuery.year => orderBy('year', descending: true),
MovieQuery.score => orderBy('score', descending: true)
MovieQuery.score => orderBy('score', descending: true),
};
}
}
Expand All @@ -57,9 +51,7 @@ class FirestoreExampleApp extends StatelessWidget {
return MaterialApp(
title: 'Firestore Example App',
theme: ThemeData.dark(),
home: const Scaffold(
body: Center(child: FilmList()),
),
home: const Scaffold(body: Center(child: FilmList())),
);
}
}
Expand Down Expand Up @@ -148,9 +140,7 @@ class _FilmListState extends State<FilmList> {
stream: moviesRef.queryBy(query).snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
return Center(child: Text(snapshot.error.toString()));
}

if (!snapshot.hasData) {
Expand Down Expand Up @@ -193,10 +183,7 @@ class _MovieItem extends StatelessWidget {

/// Returns the movie poster.
Widget get poster {
return SizedBox(
width: 100,
child: Image.network(movie.poster),
);
return SizedBox(width: 100, child: Image.network(movie.poster));
}

/// Returns movie details.
Expand All @@ -209,10 +196,7 @@ class _MovieItem extends StatelessWidget {
title,
metadata,
genres,
Likes(
reference: reference,
currentLikes: movie.likes,
),
Likes(reference: reference, currentLikes: movie.likes),
],
),
);
Expand Down Expand Up @@ -251,10 +235,7 @@ class _MovieItem extends StatelessWidget {
padding: const EdgeInsets.only(right: 2),
child: Chip(
backgroundColor: Colors.lightBlue,
label: Text(
genre,
style: const TextStyle(color: Colors.white),
),
label: Text(genre, style: const TextStyle(color: Colors.white)),
),
),
];
Expand All @@ -264,9 +245,7 @@ class _MovieItem extends StatelessWidget {
Widget get genres {
return Padding(
padding: const EdgeInsets.only(top: 8),
child: Wrap(
children: genreItems,
),
child: Wrap(children: genreItems),
);
}

Expand All @@ -289,11 +268,8 @@ class _MovieItem extends StatelessWidget {
class Likes extends StatefulWidget {
/// Constructs a new [Likes] instance with a given [DocumentReference] and
/// current like count.
Likes({
Key? key,
required this.reference,
required this.currentLikes,
}) : super(key: key);
Likes({Key? key, required this.reference, required this.currentLikes})
: super(key: key);

/// The reference relating to the counter.
final DocumentReference<Movie> reference;
Expand Down Expand Up @@ -323,10 +299,12 @@ class _LikesState extends State<Likes> {
// We use a transaction because multiple users could update the likes count
// simultaneously. As such, our likes count may be different from the likes
// count on the server.
int newLikes = await FirebaseFirestore.instance
.runTransaction<int>((transaction) async {
DocumentSnapshot<Movie> movie =
await transaction.get<Movie>(widget.reference);
int newLikes = await FirebaseFirestore.instance.runTransaction<int>((
transaction,
) async {
DocumentSnapshot<Movie> movie = await transaction.get<Movie>(
widget.reference,
);

if (!movie.exists) {
throw Exception('Document does not exist!');
Expand Down Expand Up @@ -387,15 +365,15 @@ class Movie {
});

Movie.fromJson(Map<String, Object?> json)
: this(
genre: (json['genre']! as List).cast<String>(),
likes: json['likes']! as int,
poster: json['poster']! as String,
rated: json['rated']! as String,
runtime: json['runtime']! as String,
title: json['title']! as String,
year: json['year']! as int,
);
: this(
genre: (json['genre']! as List).cast<String>(),
likes: json['likes']! as int,
poster: json['poster']! as String,
rated: json['rated']! as String,
runtime: json['runtime']! as String,
title: json['title']! as String,
year: json['year']! as int,
);

final String poster;
final int likes;
Expand Down
Loading
Loading