3

I have a getter for a singleton instance of a SQFlite Database, like this:

static Database _db;
static Future<Database> get db async {
    if( _db == null )
        _db = await openOrCreateDatabase();
    return _db;
}

Now, I want to perform a query on the db:

final List<Map<String, dynamic>> rows = await (await db).query(
    'mytable', 
    where: 'id<?', 
    whereArgs: [10]
);

I find the await (await db) ugly - is there a nicer way to "chain" two await's together in serial?

Magnus
  • 17,157
  • 19
  • 104
  • 189

2 Answers2

0

Since both operations returns a Future there is no other way that await for the two operations. To await multiple futures with a single await you need to add it to a list of futures and then use Future.wait but generally is more ugly and useless in this case.

      var futures = <Future>[];
      futures.add(operationThatReturnAFuture());
      futures.add(operationThatReturnAFuture());
      await Future.wait(futures);

Dart does not support this kind of chaining between await but i understand that looks odd on this case.

Maybe if you change the variable rows to a method the code will look a little cleaner.

For example something like:

getUser(int id) async {
    final db = await database;
    var res = await  db.query("User", where: "id = ?", whereArgs: [id]);
    return res.isNotEmpty ? User.fromMap(res.first) : Null ;
  }
fvillalba
  • 963
  • 10
  • 18
  • Using `Future.wait` won't help in this case since one `Future` depends on the other, and they therefore must be computed sequentially. – jamesdlin Jun 15 '19 at 19:12
  • Yes you are right! thats why i said that is useless in this case and it was just a explanation, the answer is the other part that dart does not have a way of do that chaining and is common to have code with multiple await sequentially. On your example the code looks "ugly" because the 2 awaits are on the same lane. – fvillalba Jun 15 '19 at 19:26
0

An alternative is to use the old syntax then():

Future getDb() => db;
Future makeQuery(db) => db.query(
    'mytable', 
    where: 'id<?', 
    whereArgs: [10]
);

void doSomethingWithQuery(query){}

getDb().then(makeQuery).then(doSomethingWithQuery);

The code reads naturally this way, "get the database, then make a query, then do something else". I don't think async keyword is needed for getDb() and makeQuery(db) but I might be wrong.

As a side note, the get db method could be streamlined using the null-aware ??= operator:

static Future<Database> get db async => _db ??= await openOrCreateDatabase();
Nam Nguyen
  • 141
  • 1
  • 4