JorgeGRC
JorgeGRC

Reputation: 1052

Typescript async function wrapping promise

I'm curerntly playing with Typescript and ionic and also new to async-await on javascript. I'm trying to get a good undestanding of promises but I can't figure out how to wrap methods which call multiple promises to return a promise. I'll try to elaborate better:

Basically, I have an object which can create a SQLite database, and when the create() method is invoked, it would return a Promise with the actual database object once it has been created.

Then, when the promise resolves and the DB object is returned, I need to use it to execute some statements in a transaction to create all the tables, and a new promise is returned when I invoke the execution of all the statements in the transaction.

Then when the transaction is finished and everything went good, I need to assign the database object to a class property and set a flag indicating database is created and ready to go.

So I thought it would be a good idea to wrap this database initialization stuff in a method called createDatabase() or something like that, which returns a Promise<SQLiteObject>, where SQLiteObject represents the database. This method would be called on initialization and should return the SQLiteObject representing the database once everything went OK, or throw an error which I would log in the .catch() method of the Promise.

I have a basic understanding of promises and how to use then() and catch() methods but I'm a bit confused when I have to create the database, then do something else when the promise resolves, and when everything is done, return a Promise containing the DB object, which is an instance of the class SQLiteObject.


CODE
Below is my current Typescript code. It's not valid typescript as I don't know how to return the Promise<SQLiteObject> from the async function.

async createDatabase(): Promise<SQLiteObject> {

        this.sqlite.create({
            name: this.dbName,
            location: this.dbLocation
        }).then( (db: SQLiteObject) => {
            // Insert all tables.
            let createTableParam: string = `CREATE TABLE IF NOT EXISTS param (name PRIMARY KEY NOT NULL, value TEXT)`;
            let createTableNews: string = `CREATE TABLE IF NOT EXISTS news (id PRIMARY KEY NOT NULL,title TEXT,
                content TEXT, image TEXT, date DATE)`;

            db.transaction(tx => {
                    tx.executeSql(createTableParam);
                    tx.executeSql(createTableNews);
                    // Add here more tables to create if needed
                }
            )
                .then( () => {
                    console.log('Tables were created');
                    this.isActive = true;
                })
                .catch(error => {
                    console.log(`Error creating tables - ${error}`);
                });
        }).catch(
            error => console.log(`Error at SQLite initialization - ${error}`)
        );
    }

RESEARCH SO FAR

Upvotes: 0

Views: 9460

Answers (2)

Henry Ollarves
Henry Ollarves

Reputation: 519

It appears you're not resolving the promise.

A promise must be resolved or rejected so a async function is capable of responding with a value.

From TypeScript Deep Dive:

const promise = new Promise((resolve, reject) => {
    resolve(123);
});
promise.then((res) => {
    console.log('I get called:', res === 123); // I get called: true
});
promise.catch((err) => {
    // This is never called
});

So in my opinion you should create a promise, and when the DB is created and everything resolve it, if there's a problem with the DB creation, reject it.

Remember you can chain promises, so you could chain them as you create your database.

From TypeScript Deep Dive:

The chain-ability of promises is the heart of the benefit that promises provide. Once you have a promise, from that point on, you use the then function to create a chain of promises.

Check this URL for more info about promises.

Upvotes: 2

Duncan
Duncan

Reputation: 95612

You used async, so that means you can use await inside the function any time you have a Promise and write the code almost as though it were synchronous.

async createDatabase(): Promise<SQLiteObject> {
    let db: SQLiteObject;
    try {
      db = await this.sqlite.create({
        name: this.dbName,
        location: this.dbLocation
      });
    } catch(error) {
        console.log(`Error at SQLite initialization - ${error}`);
        return;
    );
    // Insert all tables.
    let createTableParam: string = `CREATE TABLE IF NOT EXISTS param (name PRIMARY KEY NOT NULL, value TEXT)`;
    let createTableNews: string = `CREATE TABLE IF NOT EXISTS news (id PRIMARY KEY NOT NULL,title TEXT,
        content TEXT, image TEXT, date DATE)`;

     try {
       await db.transaction(tx => {
                tx.executeSql(createTableParam);
                tx.executeSql(createTableNews);
                // Add here more tables to create if needed
            }
          );

       console.log('Tables were created');
       this.isActive = true;
       return db;
     catch(error) {
         console.log(`Error creating tables - ${error}`);
     });
}

Without the await you need to be sure to return that initial promise.

return this.sqlite.create({...

and then again further down you can return the db object:

       this.isActive = true;
       return db;

Also you should avoid nesting the .then() handlers: when you get another promise just return it from the first handler and chain another .then on the end:

createDatabase(): Promise<SQLiteObject> {
    let database: SQLiteObject = null;
    return this.sqlite.create({
        name: this.dbName,
        location: this.dbLocation
    })
    .catch(error => console.log(`Error at SQLite initialization - ${error}`))
    .then( (db: SQLiteObject) => {
        // Insert all tables.
        let createTableParam: string = `CREATE TABLE IF NOT EXISTS param (name PRIMARY KEY NOT NULL, value TEXT)`;
        let createTableNews: string = `CREATE TABLE IF NOT EXISTS news (id PRIMARY KEY NOT NULL,title TEXT,
            content TEXT, image TEXT, date DATE)`;
        database = db;
        return db.transaction(tx => {
                tx.executeSql(createTableParam);
                tx.executeSql(createTableNews);
                // Add here more tables to create if needed
            }
        );
    })
    .then( () => {
        console.log('Tables were created');
        this.isActive = true;
        return database;
    })
    .catch(error => console.log(`Error creating tables - ${error}`));

Upvotes: 2

Related Questions