0

I am trying to fetch one User (row) from users table in SQLite in Flutter. I am using sqflite package for that. But, the fetchedUser Map is empty as a result of query and I am getting errors:

  1. asynchronous suspension
  2. Unsupported operation: read-only

I read somewhere that I need to put List of results in another List, because raw data can contain some constraints..but that fails also. Here is the all relevant code:

Future<Database> createDatabaseAndUserTable() async {
    Database database;
    try {
      database = await openDatabase(
        join(await getDatabasesPath(), 'sqflite_database_rt.db'),

        version: 2,
        onCreate: (db, version) async {
          return await db.execute(
            'CREATE TABLE users(uid Text PRIMARY KEY, email TEXT,'
            ' '
            'enteredRoom TEXT, profileImage TEXT, name TEXT, surname TEXT, username TEXT, isAdmin INTEGER)',
          );
        },
      );
      return database;
    } catch (e) {
      throw Exception(e);
    }
  }
Future<Map<String, dynamic>> getOneEntitySQLite(
    Database database,
    String id,
  ) async {
    try {
      final List<Map<String, dynamic>> results = await database.query(
        'users',
        where: 'uid = ?',
        whereArgs: [id],
        limit: 1,
      );
      logger.i("User from local fetched!");
      //List<Map<String, dynamic>> mutableResults = List.from(results);
      Map<String, dynamic> userMap = results.first;
      if (results.first['isAdmin'] == 1) {
        userMap['isAdmin'] = true;
      } else {
        userMap['isAdmin'] = false;
      }
      return userMap;
    } catch (e) {
      logger.e(e);
      return {};
    }
  }

late Database database;//This is my database reference that I get in ElevatedButton
UserEntity? userFromLocalDatabase;//User that I want to fetch
ElevatedButton(
          onPressed: () async {
            try {
              //await getDatabaseReference();
              database = await iProfileRepository.createDatabaseAndUserTable();
              Map<String, dynamic> fetchedUser = await iProfileRepository
                  .getOneEntitySQLite(database, auth.currentUser!.uid);
              logger.i("FETCHED USER IS: $fetchedUser");
              UserEntity userEntity = UserEntity.fromMap(fetchedUser);
              setState(() {
                userFromLocalDatabase = userEntity;
              });
            } catch (e) {
              logger.e("Error reading single user $e");
            }
          },
          child: Text("Fetch one user", style: TextStyle(color: Colors.black)),
        ),
class UserEntity {
  String uid;
  String email;
  String? enteredRoom = "none";
  String profileImage;
  String name;
  String surname;
  String? username = "";
  bool? isAdmin = false;

  UserEntity({
    required this.uid,
    required this.email,
    this.enteredRoom,
    required this.profileImage,
    required this.name,
    required this.surname,
    this.username,
    this.isAdmin,
  });

  Map<String, dynamic> toMap() {
    return {
      'uid': uid,
      'email': email,
      'enteredRoom': enteredRoom,
      'profileImage': profileImage,
      'name': name,
      'surname': surname,
      'username': username,
      'isAdmin': isAdmin,
    };
  }

  factory UserEntity.fromMap(Map<String, dynamic> user) {
    return UserEntity(
      uid: user['uid'].toString(),
      email: user['email'].toString(),
      enteredRoom: user['enteredRoom'].toString(),
      profileImage: user['profileImage'].toString(),
      name: user['name'].toString(),
      surname: user['surname'].toString(),
      isAdmin: user['isAdmin'],
    );
  }

  @override
  String toString() {
    return 'User{uid: $uid, email: $email, enteredRoom: $enteredRoom,'
        ' '
        'profileImage: $profileImage, name: $name, surname: $surname,'
        ' '
        'username: $username, isAdmin: $isAdmin }';
  }
}

Problem is that fetchedUser that I log is empty Map. Can someone explain me why that is happening?

1
  • does any matching row exist in the users table for the given user id? Have you seeded earlier or saved atleast one matching record? Commented Sep 2 at 12:09

2 Answers 2

1

Instead of doing this which causes the problem


 Map<String, dynamic> userMap = results.first;
//
      if (results.first['isAdmin'] == 1) {
        userMap['isAdmin'] = true;
      } else {
        userMap['isAdmin'] = false;
      }
      return userMap;

Why don't do the conversion inside fromMap

 factory UserEntity.fromMap(Map<String, dynamic> user) {
    return UserEntity(
      uid: user['uid'].toString(),
      email: user['email'].toString(),
      enteredRoom: user['enteredRoom'].toString(),
      profileImage: user['profileImage'].toString(),
      name: user['name'].toString(),
      surname: user['surname'].toString(),
      isAdmin: user['isAdmin']==1,// handle type conversion here
    );
  }
Sign up to request clarification or add additional context in comments.

6 Comments

this is only an optimization! Doesn't fix the problem?
Yes , as the line causing the problem is userMap['isAdmin'] = true;
Thank you folks for your answers. But, I finally found solution :D The problem was in how Maps work. "results.first" is read-only, so I have to make copy of it to make it mutable. I did this: Map<String, dynamic> userMapMutable = Map.of( results.first,); And this works now when I want to write true/false in userMapMutable['isAdmin'] Hope this helps someone in future :D
You don't have to make a copy of the list, as you can change isAdmin in the model
If you found a solution yourself, please post it as an answer - rather than as a comment on somebody else's answer. That way you can accept it, and it's more likely to be found by future visitors.
Got it. I will do that. Thanks.
1

The problem was in how Maps work. results.first is read-only, so I have to make copy of it to make it mutable.

I did this:

Map<String, dynamic> userMapMutable = Map.of( results.first);

This works, so that now I can write true/false in userMapMutable['isAdmin'].

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.