Home > Back-end >  Mapping a Stream<List> to another type is returning a Stream<Null>
Mapping a Stream<List> to another type is returning a Stream<Null>

Time:10-20

I'm trying to transform a Stream of a list of one type into a Stream of a list of another type, and having an issue with this.

I have this list of Habits that I'm streaming from Firebase, and I want to accept that stream in a function, and return a new stream that is a list of ViewModels of another type from it. But my function is returning a stream of the wrong type.

Here is my code:

  Stream<List<HabitCompletionViewModel>> _getTodaysHabits(
      Stream<List<Habit>> habitsStream) {
    var result = habitsStream.map((habitsList) {
      habitsList.map(
        (habit) async {
          await _getHabitCompletionsCurrent(habit);
          HabitCompletion completion = habit.completions!.firstWhere(
              (completion) => completion.date
                  .dayEqualityCheck(DateTime.now().startOfDate()));
          return HabitCompletionViewModel(completion: completion, habit: habit);
        },
      ).toList();
    });
    return result;
  }

I am getting a compile error because the result variable is showing as type Stream<Null> when I hover over it, where I would expect it to be Stream<List<HabitCompletionViewModel>>. Any idea what I'm doing wrong?

CodePudding user response:

Your outer .map call does not have a return statement which is why you are getting a Stream<Null>.

So add a return statement like so:

Stream<List<HabitCompletionViewModel>> _getTodaysHabits(
    Stream<List<Habit>> habitsStream) {
  var result = habitsStream.map((habitsList) {
    // added return statement here
    return habitsList.map(
      (habit) async {
        await _getHabitCompletionsCurrent(habit);
        HabitCompletion completion = habit.completions!.firstWhere(
            (completion) =>
                completion.date.dayEqualityCheck(DateTime.now().startOfDate()));
        return HabitCompletionViewModel(completion: completion, habit: habit);
      },
    ).toList();
  });
  return result;
}

However the above code still has an error because it is now returning a Stream<List<Future<HabitCompletionViewModel>>> instead of the desired Stream<List<HabitCompletionViewModel>>. To solve this you can use .asyncMap instead of .map.

Stream<List<HabitCompletionViewModel>> _getTodaysHabits(
    Stream<List<Habit>> habitsStream) {
  var result = habitsStream.asyncMap((habitsList) {
    return Stream.fromIterable(habitsList).asyncMap(
      (habit) async {
        await _getHabitCompletionsCurrent(habit);
        HabitCompletion completion = habit.completions!.firstWhere(
            (completion) =>
                completion.date.dayEqualityCheck(DateTime.now().startOfDate()));
        return HabitCompletionViewModel(completion: completion, habit: habit);
      },
    ).toList();
  });
  return result;
}
  • Related