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.
Running async code on import/require is usually not recommended, this is a good example why
Specifically, the
require('./db')inindex.jsinitiates the call intocreateDB, immediately returns with an emptymodule.exports, and that's whatpoolgets set to beforecreateDBeven starts running. By the time it setsmodule.exportsit's no longer read by anyoneInstead of having db.js immediately run this on import:
You can wrap it in an async function:
and then in
index.jsyou canawaituntil pool is ready:and from this point, it would work as you expect
Side note - Would also recommend not mixing
thenwithawait. Behind the scenes, they do the same thing, so it'll be easier to read if everything wasawait: