Syncing problem

I’m trying to get informations from SQLite query:

data-provider.ts

import { Injectable } from '@angular/core';
import { SQLite, SQLiteObject } from '@ionic-native/sqlite';

@Injectable()
export class DatabaseProvider {
    query: any;

  constructor(public sqlite: SQLite) {
    this.query = [];

    this.sqlite.create({
        name: 'data.db',
        location: 'default'
    }).then((db: SQLiteObject) => {
            db.executeSql('CREATE TABLE IF NOT EXISTS tasks(id INTEGER PRIMARY KEY AUTOINCREMENT, description VARCHAR(50))', {})
            .then(() => console.log('Executed create table'))
            .catch(e => console.log(e.message));
        }).catch(e => console.log(e.message));
  }

  selectAll() {
      let tmp = [];
      this.sqlite.create({
        name: 'data.db',
        location: 'default'
      }).then((db: SQLiteObject) => {
          db.executeSql('SELECT * FROM tasks', {})
          .then(function(resultSet){
              for(var x = 0; x < resultSet.rows.length; x++) {
                tmp.push(resultSet.rows.item(x).description);
            }
            console.log('Executed select');
        }).then(() => {
            console.log('Returning');
            return tmp;
        }).catch(e => console.log(e.message));
        }).catch(e => console.log(e.message));
    }
}

home.ts

import { Component } from '@angular/core';
import { DatabaseProvider } from '../../providers/database-provider'
import { NavController, Platform } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

    tasks: any;

  constructor(public navCtrl: NavController, public sqlProvider: DatabaseProvider, public platform: Platform) {
      this.platform.ready().then(() => {
          this.tasks = this.sqlProvider.selectAll();
          console.log('Printing tasks: ' + this.tasks);
      })

  }

}

log

[18:16:20]  console.log: OPEN database: data.db 
[18:16:20]  console.log: OPEN database: data.db - OK 
[18:16:20]  console.log: Ionic Native: deviceready event fired after 861 ms 
[18:16:20]  console.log: database already open: data.db 
[18:16:20]  console.log: Printing tasks: undefined 
[18:16:20]  console.log: Executed create table 
[18:16:20]  console.log: Executed select 
[18:16:20]  console.log: Returning 

as you can see in log, ionic is printing before executing all the SQLite queries.

When selectAll() returns is completely unrelated to when the stuff it is doing is completed. A good rule of thumb when dealing with asynchronous tasks is “make ‘return’ the very first word of all your functions”, and if you follow it here, you should be happy:

selectAll(): Promise<Task[]> {
  return this.sqlite.create({}).then((db) => {
    // do other db stuff
  });
}

constructor() {
  platform.ready().then(() => {
    sqlProvider.selectAll().then((tasks) => {
      // only in here can we rely on tasks
    });
  });
}

There’s must be something wrong, the log is still printing before executing SQLite query

obs: other typer other than void gives an error

selectAll(): Promise<void> {
      return this.sqlite.create({
        name: 'data.db',
        location: 'default'
      }).then((db: SQLiteObject) => {
          db.executeSql('SELECT * FROM tasks', {})
          .then(function(resultSet){
              let tmp = [];
              for(var x = 0; x < resultSet.rows.length; x++) {
                tmp.push(resultSet.rows.item(x).description);
            }
            console.log('Executed select');
        }).catch(e => console.log(e.message));
        }).catch(e => console.log(e.message));
    }
constructor(public navCtrl: NavController, public sqlProvider: DatabaseProvider, public platform: Platform) {
      this.platform.ready().then(() => {
          this.sqlProvider.selectAll().then((tasks) => {
              this.lista = tasks;
              console.log('tasks: ' + tasks);
          });
      })
  }

log

[11:10:47]  console.log: OPEN database: data.db 
[11:10:47]  console.log: OPEN database: data.db - OK 
[11:10:47]  console.log: Ionic Native: deviceready event fired after 820 ms 
[11:10:47]  console.log: database already open: data.db 
[11:10:47]  console.log: Executed create table 
[11:10:47]  console.log: tasks: undefined 
[11:10:47]  console.log: Executed select

You’re not returning tmp out of the inner resolution.

1 Like

I did this and it worked

selectAll(): Promise<string[]> {
      return new Promise<string[]>((resolve, reject) => {
          let tmp = Array<string>();
          this.sqlite.create({
            name: 'data.db',
            location: 'default'
          }).then((db: SQLiteObject) => {
              db.executeSql('SELECT * FROM tasks', {})
              .then(function(resultSet){
                  for(var x = 0; x < resultSet.rows.length; x++) {
                    tmp.push(resultSet.rows.item(x).description);
                  }
                  console.log('Executed select');
                  resolve(tmp);
            }).catch(e => console.log(e.message));
            }).catch(e => console.log(e.message));
      })
    }

Thank you for your help

You shouldn’t need to be explicitly instantiating a promise. Just returning tmp out if its should have been sufficient.

1 Like

Returning tmp was giving me these errors:

Type 'any[]' is not assignable to type 'Promise<string[]>'.

or

Type 'any[]' is not assignable to type 'Promise<any[]>'.

Dealing with actual SQLite is a pain, so I mocked this up, which will hopefully be similar enough that you can adapt it. It works as expected in a sample project:

  makeDb(): Promise<any> {
    let db:any = {};
    db.executeSql = () => {
      return Promise.resolve(["banana", "cherimoya"]);
    };
    return Promise.resolve(db);
  }

  loadEverything(): Promise<string[]> {
    return this.makeDb().then((db) => {
      return db.executeSql().then((results) => {
        let rv = [] as string[];
        for (let i = 0; i < results.length; ++i) {
          rv.push(results[i]);
        }
        return rv;
      });
    })
  }

  onLoad(): void {
    this.loadEverything().then((fruits) => {
      this.fruits = fruits;
    });
  }

When I trigger onLoad() from a button, this.fruits is set to ['banana', 'cherimoya'].