简体   繁体   中英

Creating a Database programmatically with node-postgres

I want to create a Database when a user launches an application if it does not already exist. The way I tried doing this is, because there's no way that I know of to create a Database without having an existing connection, is to connect to the standard postgres Database, which is a default pre-existing one (I think).

Once I'm connected, I execute this from the default connection:

`SELECT 'CREATE DATABASE dbName WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'dbName')\\gexec`

This supposingly creates the Database if it doesn't exist. Once this runs, and I guaranteed to have a dbName database that exists. I thus shut off the other connection for it is no longer needed with

postgresCon.end();

And I connect to the recently created Database, in hopes to then use it to do whatever queries I would like and have the user be able to add workouts/exercises/whatever else.

The Problem Whenever I run the Select create database workout ... statement, I catch the error, and what it gives me is "Error: Connection Terminated", safe to say that this error isn't really... descriptive. In fact, this happens when workout database already exists. If it doesn't, it simply complains (later - when I try to execute a query on this database) that it doesn't exist.

This is the code, my theory is that it's Asynchronous and so though the connection "started connecting", the rest of the Queries are already being run and returning with "doesn't exist", because it hasn't been fully created yet.

Here is the code on pastebin for some highlighting (though apparently it's not happy with '' so the highlighting may be a bit scuffed): https://pastebin.com/fiiK35j7

If you need more detail/code/more clarity, do ask!

EDIT I've been told that my Theory is correct and that I should use async/await, but I am unsure how I could stop queries from being ran before the connection has been successfully completed, I assume it'd have to be something along the lines of:

async connection() => {await db.connect()}

connection()
.then(can do queries here)
.catch(panic)

but I am unsure what will actually work

I don't believe you can call \gexec from application code. That's a command which can only be used from the psql cli tool.

You'll have to issue and query and then do the conditional in your application code to subsequently create (or not) the database.

As was commented above, connecting with the DB superuser from an application is a bad idea. But there are some scenarios where it might be warranted, ie from a CI/CD pipeline where you want to provision databases and users if they don't exist for new environments. I did the following (using ts-postgres instead of node-postgres):

const [host, username, password] = ['localhost', 'user', 'pass']
const client = new Client({host, user: username, password})
await client.connect()

///// 
// There is no CREATE DATABASE IF NOT EXISTS in postgres, which is decidedly annoying
// instead, we have to query and see if the database and user exists, and if not, create them
const dbQuery = await client.query(`SELECT FROM pg_database WHERE datname = $1`, [applicationDatabaseName])
if (dbQuery.rows.length === 0)  {
    // database does not exist, make it:
    await client.query(`CREATE DATABASE ${applicationDatabaseName}`)
}


const userQuery = await client.query(`SELECT FROM pg_roles where rolname = $1`, [applicationDatabaseUser])
if(userQuery.rows.length === 0) {
    //user doesn't exist. make it
    await client.query(`CREATE USER ${applicationDatabaseUser} with ENCRYPTED PASSWORD '${applicationDatabasePassword}'`)
    await client.query(`GRANT ALL PRIVILEGES ON DATABASE ${applicationDatabaseName} TO ${applicationDatabaseUser}`)
}
await client.end()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM