Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return null on scalar queries such as "Select count(*) from ..." #576

Open
wzhou-grid opened this issue Jun 18, 2021 · 10 comments
Open

Return null on scalar queries such as "Select count(*) from ..." #576

wzhou-grid opened this issue Jun 18, 2021 · 10 comments

Comments

@wzhou-grid
Copy link

The following query always returns null:

@Query('SELECT COUNT(*) from Area')
  Future<int?> total();

I have tested other scalar queries, such as

@Query('SELECT MAX(Id) from Area')
  Future<int?> getMax();

still got null. very strange.

@evandrmb
Copy link

I have the same problem. The following query

@Query('SELECT MAX(createdAt), MAX(updatedAt) from people')
  Future<List<DateTime>> getOldestDates();

generates following code in database.g.dart

 await _queryAdapter
      .queryNoReturn('SELECT MAX(createdAt), MAX(updatedAt) from people');

which has a return type of void

@Sanshain
Copy link

Sanshain commented Aug 1, 2021

What about removing ? from Future generic type?

@Query('SELECT COUNT(*) from Area')
  Future<int> total();

I suppose COUNT(*) always returns number and never returns null

@evandrmb
Copy link

evandrmb commented Aug 4, 2021

What about removing ? from Future generic type?

@Query('SELECT COUNT(*) from Area')
  Future<int> total();

I suppose COUNT(*) always returns number and never returns null

He can't. If you do that and try to run flutter pub run build_runner build it will fail with the following warning:

Queries returning single elements might return null. Make the method return a Future of a nullable type e.g. Future<int?>`

@ayalma
Copy link

ayalma commented Aug 31, 2021

What about max (id) when db is empty?

@MrCsabaToth
Copy link

MrCsabaToth commented Nov 10, 2021

This is badly needed feature. I have several tables I'd like to know if they are empty or not. My workaround is to have raw queries in the AppDatabase class, something along the line of:

  Future<int> areaCount() async {
    final result = await database.rawQuery("SELECT COUNT(`id`) AS cnt FROM Area");

    return result.isEmpty ? 0 : result[0]['cnt'] as int? ?? 0;
  }

But this is sooo ugly and might not be robust! I think count is common enough to be supported along with CRUD.

@MrCsabaToth
Copy link

This feature will help #200

@MrCsabaToth
Copy link

What about max (id) when db is empty?

No matter how you spin it around the code generator portion needs to recognize and support what you want to do. And that's what is missing right now.

@Nathagamelle
Copy link

stranger still
with DAO
@query('SELECT COUNT(*) FROM MyItem')
Future<int?> getAllCount();
@query('SELECT * FROM MyItem')
Future<List> findAllItems();

int? count=await database.myItemDAO.getAllCount();
print('db-size' + count.toString());
==> returns null

List myItems= await database.myItemDAO.findAllItems();
print('db-size' + myItems.length.toString());
==> returns the actual count

@MrCsabaToth
Copy link

MrCsabaToth commented Dec 1, 2021

stranger still with DAO @query('SELECT COUNT(*) FROM MyItem') Future<int?> getAllCount(); @query('SELECT * FROM MyItem') Future findAllItems();

int? count=await database.myItemDAO.getAllCount(); print('db-size' + count.toString()); ==> returns null

List myItems= await database.myItemDAO.findAllItems(); print('db-size' + myItems.length.toString()); ==> returns the actual count

That length on the findAllItems result is very resource intensive especially with a larger table. First I would say just for this purpose you may want @query('SELECT id FROM MyItem') instead of @query('SELECT * FROM MyItem') just to decrease the bandwidth. But then you'd rather want to do what I advised and place a dedicated function for the purpose into your AppDatabase descendant class:

  Future<int> myItemCount() async {
    final result = await database.rawQuery("SELECT COUNT(`id`) AS cnt FROM MyItem");

    return result.isEmpty ? 0 : result[0]['cnt'] as int? ?? 0;
  }

@debbiefu
Copy link

debbiefu commented Mar 9, 2022

The auto-generated code for SELECT COUNT(*) is _queryAdapter.queryNoReturn, so you won't get any result.

dao code:

@Query('SELECT COUNT(*) FROM notification WHERE groupUid = :groupUid AND createTime >= :timestamp AND hasRead IS FALSE')
 Future<int?> getUnReadNotificationCountByGroupId(String groupUid, int timestamp);

My solution:
Modify the auto-generated database.g.dart code:

@override
  Future<int?> getUnReadNotificationCountByGroupId(String groupUid, int timestamp) async {
    return _queryAdapter.query(
        'SELECT COUNT(*) FROM notification WHERE groupUid = ?1 AND createTime >= ?2 AND hasRead IS FALSE',
        mapper: (Map<String, Object?> row) => row['COUNT(*)'] as int,
        arguments: [groupUid, timestamp]);
  }

The raw sql result is a map: {'COUNT(*)': value}, so you just write the mapper to get the value is ok.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

7 participants