Question

I'm trying to code sql access to a database using sqljocky in Dart. As I want to make some computation with the result returned by my database Handler, the method return a Future.

But when I try to run it, I'm getting the following error:

Uncaught Error: The null object does not have a method 'then'`

I've ran the debugger and found that this error raise on:

db.query('select * from user where email="$email"').then(...)

but the catchError clause doesn't fire.

My handler method is:

// db is a ConnectionPool
Future<Map<String,String>> queryUser(String email){
    print(email);
    db.query('select * from user where email="${email}"').then((result) { // here raise the error
        Map<String,String> results = new Map<String,String>();
        result.forEach((row){
           results['status'] = '200'; 
           results['ID'] = row[0];
           results['Image'] = row[1];
           results['Name'] = row[2];
           results['Email'] = row[3];
           results['Password'] = row[4];
        });
        return results;
    }).catchError((error){
        Map<String,String> results = new Map<String,String>();
        results['status'] = '500';
        return results;
    });
}

And the method that call this handler is:

List getUser(String email) {
    Future<Map<String,String>> result = dbhandler.queryUser(email);
    result.then((Map<String,String> result) {
    String statuscode = result['status'];
    result.remove('status');
    String json = JSON.encode(result);
    List pair = new List();
    pair.add(statuscode);
    pair.add(json);
    return pair;
});

If I run the query directly in phpmyadmin, it return correct data, so it is correct.

Can someone give me a hint about how to solve it?

Was it helpful?

Solution

The queryUser() method will always return null, as there is no return statement. In the next release of Dart there will be a static hint warning for this, but at the moment there is none.

Perhaps the code below is what you meant to do. Note the initial return statement before db.query(), and the extra result.toList() call. I haven't tested this, so there's probably a typo or two.

Future<Map<String,String>> queryUser(String email){
    print(email);
    return db.query('select * from user where email="${email}"')
      .then((result) => result.toList())
      .then((rows) {
        var row = rows.single;
        Map<String,String> results = new Map<String,String>();
        results['status'] = '200'; 
        results['ID'] = row[0];
        results['Image'] = row[1];
        results['Name'] = row[2];
        results['Email'] = row[3];
        results['Password'] = row[4];
        return results;
      }).catchError((error){
        Map<String,String> results = new Map<String,String>();
        results['status'] = '500';
        return results;
      });
}

You can also make this a bit cuter using map literals:

Future<Map<String,String>> queryUser(String email){
    return db.query('select * from user where email="${email}"')
      .then((result) => result.toList())
      .then((rows) => <String, String> {
        'status': '200',
        'ID': rows.single[0],
        'Image': rows.single[1],
        'Name': rows.single[2],
        'Email': rows.single[3],
        'Password': rows.single[4] })
      .catchError((error) => <String, String> {'status': '500'});
}

OTHER TIPS

Finally I found the answer using Completer to control the Future object, but the real problem was, as Greg Lowe said, that my methods doesn't return anything as they come to end before the then clause.

Using completer, I've made my query method as:

Future<Map<String,String>> queryUser(String email){
    Completer c = new Completer(); 
    db.query('select * from user where email="$email"').then((result) {
        Map<String,String> results = new Map<String,String>();
        result.forEach((row){
            results['status'] = '200'; 
            results['ID'] = row[0].toString();
            results['Image'] = row[1];
            results['Name'] = row[2];
            results['Email'] = row[3];
            results['Password'] = row[4];
        }).then((onValue){
            c.complete(results);
        });
    }).catchError((error){
        Map<String,String> results = new Map<String,String>();
        results['status'] = '500';
        c.completeError((e) => print("error en queryUser"));
    });
return c.future;
}

I also solved an error when using the foreach method, at first I supposed it return nothing, but after that, I noticed that it return a Future, so I added a then clause.

And my getUser method:

Future<List> getUser(String email) {
    Completer c = new Completer(); 
    Future<Map<String,String>> result = dbhandler.queryUser(email);
    result.then((Map<String,String> result) {
        String statuscode = result['status'];
        result.remove('status');
        String json = JSON.encode(result);
        List pair = new List();
        pair.add(statuscode);
        pair.add(json);
        c.complete(pair); 
    });
    return c.future; 
}

After those changes, everything works right

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top