В запросе sqljocky нет метода then (доступ к базе данных dart)

Я пытаюсь закодировать доступ sql к базе данных с помощью sqljocky в Dart. Поскольку я хочу произвести некоторые вычисления с результатом, возвращаемым моим обработчиком базы данных, метод возвращает Future.

Но когда я пытаюсь запустить его, я получаю следующую ошибку:

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

Я запустил отладчик и обнаружил, что эта ошибка возникает:

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

но предложение catchError не срабатывает.

Мой метод обработчика:

// 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;
    });
}

И метод, вызывающий этот обработчик:

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;
});

Если я запустил запрос непосредственно в phpmyadmin, он вернет правильные данные, значит, он правильный.

Может кто-нибудь подскажет, как это решить?


person Ruben Bermudez    schedule 26.02.2014    source источник


Ответы (2)


Метод queryUser () всегда будет возвращать значение NULL, поскольку нет оператора возврата. В следующем выпуске Dart для этого будет статическая подсказка, но на данный момент ее нет.

Возможно, приведенный ниже код - это то, что вы хотели сделать. Обратите внимание на первоначальный оператор возврата перед db.query () и дополнительный вызов result.toList (). Я не тестировал это, так что, вероятно, есть одна или две опечатки.

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;
      });
}

Вы также можете сделать это немного симпатичнее, используя литералы карты:

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'});
}
person Greg Lowe    schedule 26.02.2014
comment
Спасибо Грег, вот решил, ответ напишу, может кому-нибудь пригодится. - person Ruben Bermudez; 27.02.2014

Наконец, я нашел ответ, используя Completer для управления объектом Future, но настоящая проблема заключалась, как сказал Грег Лоу, в том, что мои методы ничего не возвращают по мере их появления. заканчиваться перед предложением then.

Используя метод завершения, я сделал свой метод запроса следующим образом:

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;
}

Я также решил ошибку при использовании метода foreach, сначала я предполагал, что он ничего не возвращает, но после этого я заметил, что он возвращает Future, поэтому я добавил предложение then.

И мой метод getUser:

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; 
}

После этих изменений все работает правильно

person Ruben Bermudez    schedule 28.02.2014
comment
Это решение выглядит хуже, чем форма @GregLowe. Почему вы не пошли по его совету? Как вы думаете, в чем преимущество вашего решения? Добавление return (как предлагается) имеет тот же эффект, что и добавление кода Completer. - person Günter Zöchbauer; 28.02.2014
comment
Нет важной причины идти своим путем, но, поскольку я новичок в Dart и пришел с Java, мой путь выглядит немного легче для чтения, чем тот, который предоставлен @GregLowe, поэтому я хотел написать его здесь, поэтому он может помочь кому угодно в будущем. - person Ruben Bermudez; 28.02.2014
comment
Важно понимать, как вызовы then () можно объединить в цепочку. Завершители, вероятно, поначалу проще понять, но они становятся волосатыми, когда вы пытаетесь объединить несколько асинхронных операций в одну цепочку. Объединение вызовов then () означает, что обработка ошибок работает правильно. Например, что происходит в вашем примере, когда JSON.encode () выдает исключение? Я думаю, что ошибка не будет добавлена ​​в будущее, возвращаемое getUser (), и это приведет к сбою вашего приложения (если вы не используете зоны). Чтобы исправить это, вам понадобится дополнительный try catch и передать ошибку завершителю. - person Greg Lowe; 01.03.2014