Reputation: 11
I have a question regarding the nature of module.exports i am trying to build a simple todo app with postgres, express and node.
This is my index.js
const express = require("express");
const cors = require("cors");
const pool = require("./db");
const app = express();
const PORT = 5000;
app.use(cors());
app.use(express.json());
console.log("2");
app.get("/todos", async (req, res) => {
try {
const result = await pool.query("SELECT * FROM todo");
res.json(result.rows);
} catch (err) {
console.log(err);
}
});
This is my db.js
const fs = require("fs").promises;
const path = require("path");
const pgtools = require("pgtools");
const { Pool } = require("pg");
const dB = "perntodo";
const config = {
user: "postgres",
password: "my_pass",
port: 5432,
host: "localhost",
};
const createDB = async () => {
try {
await pgtools.createdb(config, dB);
console.log(`database ${dB} created`);
} catch (err) {
console.log(err);
}
};
createDB()
.then(async () => {
const pool = new Pool({
...config,
database: dB,
});
const schemaPath = path.join(__dirname, "database.sql");
const schema = await fs.readFile(schemaPath, "utf8");
await pool.query(schema);
return pool;
})
.then((pool) => {
console.log("1");
module.exports = pool;
})
.catch((err) => console.log(err));
database.sql is just a simple create table query.
This issue i am facing is, module.exports happens even before the value of pool becomes an object instantiated by new Pool and hence i get the following error message from index.js
TypeError: pool.query is not a function
I have placed console.logs in my code, and it seems that there is something wrong with the promise chaining as 2 is being executed before 1.
What exactly is the error in my promise chain?
This is what i think is the control flow of db.js, First, the createDB() function is called which creates the perntodo database if it doesn't exist. Once the database is created, the first .then() block is executed which creates a new Pool and loads the SQL schema file into the database using pool.query(). The Pool object is assigned to the pool variable declared outside of the block.
Finally, the second .then() block is executed which sets the pool object as the exported module for the current file using module.exports. This ensures that the pool object is available for use in other parts of the application that require this module.
Upvotes: 0
Views: 381
Reputation: 527
Running async code on import/require is usually not recommended, this is a good example why
Specifically, the require('./db')
in index.js
initiates the call into createDB
, immediately returns with an empty module.exports
, and that's what pool
gets set to before createDB
even starts running. By the time it sets module.exports
it's no longer read by anyone
Instead of having db.js immediately run this on import:
createDB()
.then(async () => {
...
You can wrap it in an async function:
async function initPool() {
return createDB()
.then(async () => {
...
return pool;
}
}
and then in index.js
you can await
until pool is ready:
const db = require("./db");
const pool = await db.initPool();
and from this point, it would work as you expect
Side note - Would also recommend not mixing then
with await
. Behind the scenes, they do the same thing, so it'll be easier to read if everything was await
:
async function initPool() {
await createDB();
...
return pool;
}
Upvotes: 1