Synchronous programming using pg-promise
Asked Answered
F

1

8

I am new to node.js and pg-promise coming from a synchronis programming background it requires a new thinking.

I would to start with a scenario of running database initialisation before the main program logic.

Following this example: https://github.com/vitaly-t/pg-promise/wiki/Learn-by-Example#simple-select

db.any("select * from users where active=$1", [true])
  .then(function (data) {
    // success;
  })
  .catch(function (error) {
    // error;
  });

Would my code read as either:

db.query("DELETE FROM records")
  .then(function (data) {
    // success;
    console.log("This is where all my main logic goes");
  })
  .catch(function (error) {
    // error;
  });

Or would it read as:

db.query("DELETE FROM records")
  .then(function (data) {
    // success;
  })
  .catch(function (error) {
    // error;
  });
console.log("This is where all my main logic goes");

My understanding is that with the latter the message would be displayed before the records were deleted.

Update: After reading numerous articles on promises and callbacks I understand that pg-promise uses chaining being .then and .catch for both success and error scenarios. I also now believe I understand the pg-promise command should be placed within a function wrapper such as:

function initialiseDB() {
  db.query("DELETE FROM records")
    .then(function (data) {
      // success;
    })
    .catch(function (error) {
      // error;
    });
  }

Then from within my code I would call the function with a simple command which would run the function asynchronously:

initialiseDB();

I am however still unsure of how this concept of asychronous coding and promises fits into the overall structure of a program as surely almost everything in a program would need the initialisation to be completed first. Accordingly would the entire program not need to be placed in the ".then" section of the function? i.e the only code at the top level would effectively be the intialiseDB() function?

// Start of code here 
var pgp = require('pg-promise')();

//Configure the database connection
var config = {
  user:               'username', //env var: PGUSER 
  database:           'database', //env var: PGDATABASE 
  password:           'password', //env var: PGPASSWORD 
};

var db = pgp(config);

function initialiseDB() {
  db.query("DELETE FROM records")
    .then(function (data) {
      // This is where the main program logic goes after this line;
    })
    .catch(function (error) {
      // error;
    });
}

// Commence the program here
initialiseDB();
Fenestra answered 1/8, 2016 at 6:48 Comment(5)
It is the first one. And you should read about proper use of promises, there is plenty of information about it today, starting with PromiseJS.Plague
Thanks you, all new to me. "Early on node experimented with a feature called 'promises' that added a number of features to make async code appear more linear. It was taken out of node core for a few reasons:" github.com/maxogden/art-of-node/blob/master/readme.mdFenestra
That's a bad article, to even suggest a nonsense like that. Promises is the best way for writing asynchronous code today.Plague
You can find my comments there: github.com/maxogden/art-of-node/issues/67Plague
Appreciate the clarification as for a noob it's all very confusing both learning new technologies whilst trying to filter them within a sea of conflicting information.Fenestra
H
3

PG promise actually allows for the use of generators and async/await on newer nodejs versions. Generators require an adapter with promises that vitaly built into the system, so supplying a generator function will allow for a cleaner code flow in a synchronous manner

Taken from the repository under the tag task

Without generators:

db.task(t => {
        // this.ctx = task config + state context;
        return t.one('SELECT * FROM users WHERE id = $1', 123)
            .then(user => {
                return t.any('SELECT * FROM events WHERE login = $1',user.name);
            });
    })
    .then(events => {
        // success;
    })
    .catch(error => {
        // error;
    });

With generators:

db.task(function * (t) {
        // this.ctx = task config + state context;
        let user = yield t.one('SELECT * FROM users WHERE id = $1', 123);
        return yield t.any('SELECT * FROM events WHERE login = $1', user.name);
    })
    .then(events => {
        // success;
    })
    .catch(error => {
        // error
    });

If using async/await, you can simple replace the function * (t) with async function (t) and yield with await and it'll work much the same.

Some caveats:

In more complex logic, you should use try catch blocks around things that might fail, as they'll bubble the error in generators and async/await

db.task(function * (t) {
    yield Promise.reject(new Error('This will cause your app to error')
}

You should also pay close attention to his pg-promise demo! It'll teach you great things like the extend event, repos, external SQL files, and a lot of other great things in the library like helpers!

Hynda answered 14/9, 2017 at 18:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.