'Fetch data from firestore inside a stream map

Is it possible to let a stream await during a fetch from firestore? I want to achieve that a user also fetches his own roles from the firestore database. Of course there is another alternative and the preferred way like custom claims. But for my project it is too complex to set it up.

Here is my attempt:

Stream<User> get user {
return _firebaseAuth.authStateChanges().map((firebaseUser) {
  User? result;
  final user = firebaseUser == null ? User.empty : firebaseUser.toUser;

  _firestore.userDoc(user.id).get().then((snapshot) {
    if (snapshot.exists) {
      final roles = snapshot.data()!['roles'] as Map<String, bool>;
      result = User(
        id: user.id,
        email: user.email,
        name: user.name,
        roles: roles,
      );
    }
  });
  _cache.write(key: userCacheKey, value: result);
  return result ?? user;
});

}

And here I also tried with asyncMap but it is not working either:

Stream<User> get user async{
return _firebaseAuth.authStateChanges().asyncMap((firebaseUser) {
  User? result;
  final user = firebaseUser == null ? User.empty : firebaseUser.toUser;
  _cache.write(key: userCacheKey, value: user);
  await _firestore.userDoc(user.id).get().then((snapshot) {
    if (snapshot.exists) {
      final roles = snapshot.data()!['roles'] as Map<String, bool>;
      result = User(
        id: user.id,
        email: user.email,
        name: user.name,
        roles: roles,
      );
    }
  });
  _cache.write(key: userCacheKey, value: result);
  return result ?? user;
});
}


Solution 1:[1]

There are multiple issues with this code. First, you should be using an async function. Second, don't mix await and then syntax.

Stream<User> get user { // I don't think `async` is needed here, you are returning a Stream synchronously
return _firebaseAuth.authStateChanges().asyncMap((firebaseUser) async { // added `async` here
  User? result;
  final user = firebaseUser == null ? User.empty : firebaseUser.toUser;
  _cache.write(key: userCacheKey, value: user);

  final userDoc = await _firestore.userDoc(user.id).get(); // simply `await` it here

  if (userDoc.exists) {
    final roles = userDoc.data()!['roles'] as Map<String, bool>;
    result = User(
      id: user.id,
      email: user.email,
      name: user.name,
      roles: roles,
    );
  }

  _cache.write(key: userCacheKey, value: result);
  return result ?? user;
});
}

Anyway, it's somewhat pseudo-code as I couldn't test it in an IDE, but you get the general idea.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Riwen