Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save simplesNotEZ/799ea9a211ccfe63af80685d84108c08 to your computer and use it in GitHub Desktop.
Save simplesNotEZ/799ea9a211ccfe63af80685d84108c08 to your computer and use it in GitHub Desktop.

Setting Up New Project with Postgres, Knex, Express

All right, let's start :

-create a new repo on Github

git clone repo

-add a .gitignore and at the very least type in node_modules and .env

then

npm init -y
npm install body-parser cors express knex morgan pg

-This will install dependencies. Open your package.json and make sure your "main" is "app.js" and in your scripts you add "start": "node index.js"

-For the galvanize drills, you also need to test them. For that, in your scripts, add "test": "mocha --exit". Also, after the }, that closes out the "dependencies":{ block, add

    "devDependencies": {
        "chai": "^4.1.2",
        "mocha": "^4.1.0",
        "supertest": "^3.0.0"
    }

-After that, directly in your terminal (as in, NOT in the psql cli) type

createdb yourdatabasename

-To check if it's there, type

psql --list

Next, type

knex init

-This will create a knexfile.js. Open that up and paste in

module.exports = {

  development: {
    client: 'pg',
    connection: 'postgres:///yourdatabasename'
  },
  
  production: {
    client: 'pg',
    connection: process.env.DATABASE_URL
  }
};

-You'll notice the three forward slashes after postgres: - this is just shorthand for postgres://localhost/. make sure to replace "yourdatabasename" with the name of the database you created with the createdb command

-in your terminal type

knex migrate:make the_name_of_the_table

-This will create a migrations folder and a timestamped migration file in your code. Open up that file and paste in

exports.up = function(knex, Promise) {
    return knex.schema.createTable('the_name_of_the_table', the_name_of_the_table => {
        the_name_of_the_table.increments();
        the_name_of_the_table.date('dueDate');
        the_name_of_the_table.string('resolution');
    });
};

exports.down = function(knex, Promise) {
    return knex.schema.dropTableIfExists('the_name_of_the_table');
};

-Of course, replace the schema of the table with whatever your table data structure is.

-Once that's done, run the migration! That's

knex migrate:latest

-Let's make sure that ran correctly.

psql yourdatabasename

-This will get you into the psql cli. Your command line prompt should look like

yourdatabasename=#

-If instead you typed just psql in the terminal, it likely connected to your computer username database - so, then, to connect to the database you want, connect to the database in psql by typing

\c yourdatabasename

-If you're thinkin "but I forget what I called my database", to see the names of all your databases when in the psql client, type

\l

-Anyways....connected to your database? Good. To see all the tables in your database, type

\dt

-This will describe the tables of your database. To see the data structure of a specific table:

\d the_name_of_the_table

-The data structure should match the migration you specified.

-Now let's make a seed file. In your terminal, get out of the psql client by typing \q and then type

knex seed:make 00_the_name_of_the_table

-Notice the 00_ in front of the filename. Generally you want to prepend your seed files with a double-digit number and underscore so all your seed files run in order.

-In any case, now you have a seeds folder. Open up that seed file and paste in

exports.seed = function(knex, Promise) {
  return knex('the_name_of_the_table').del()
    .then(function () {
      // Inserts seed entries
      return knex('the_name_of_the_table').insert([{
          id: 1, 
          dueDate: '1997-02-01',
          resolution: 'Go skiing'
        },
        {
          id: 2, 
          dueDate: '1997-05-01',
          resolution: 'Do stand-up'
        },
        {
          id: 3, 
          dueDate: '1997-09-01',
          resolution: 'Start knitting'
        }]);
    }).then(() => {
      return knex.raw("alter sequence the_name_of_the_table_id_seq restart with 4;");
    });
};

-Replace the tablename and actual data with what you want. You might not want the weird .then statement, but for the Galvanize drills, it needs them - along with the explicitly typed ids, which normally you do not need to do. However, to pass the test files they wrote, it needs them.

-Now seed the database!

knex seed:run

-To see your data, type

psql yourdatabasename
\d the_name_of_the_table
SELECT * FROM the_name_of_the_table;

-We finally have all our data set up and seeded. Now back into the code. Make a database-connection.js file and paste in

const CONFIG = require("./knexfile")[process.env.NODE_ENV || "development"];
module.exports = require("knex")(CONFIG);

-make a queries.js file and paste in

const database = require("./database-connection");

module.exports = {
    list(){
        return database('the_name_of_the_table').select();
    },
    read(id){
        return database('the_name_of_the_table').select().where('id', id).first();
    },
    create(the_name_of_the_table){
        return database('the_name_of_the_table').insert(the_name_of_the_table).returning('*').then(record => record[0]);
    },
    update(id, the_name_of_the_table){
        return database('the_name_of_the_table').update(the_name_of_the_table).returning('*').then(record => record[0]);
    },
    delete(id){
        return database('the_name_of_the_table').delete().where('id', id);
    }
};

-Replace the_name_of_the_table and various components to match the queries you need.

-Also write your app.js - there's too much specifics to do a one-size-fits-all file, but refer to previous projects and setups. Here's a basic one:

const express = require("express");
const bodyParser = require("body-parser");
const morgan = require("morgan");
const app = express();

const yourRoutes = require("./routes/yourRoutes");

app.use(morgan('dev'));
app.use(bodyParser.json());

app.use("/someendpoint", yourRoutes);

// catch 404 and forward to error handler
app.use((req, res, next) => {
    const err = new Error("Not Found");
    err.status = 404;
    next(err);
});

// error handler
app.use((err, req, res, next) => {
    res.status(err.status || 500);
    res.json({
        message: err.message,
        error: req.app.get("env") === "development" ? err.stack : {}
    });
});

module.exports = app;

You'll likely need a routes folder with a the_name_of_the_table.js file in it. If you didn't get an index.js file created for you, it's

const app = require("./app");
const port = process.env.PORT || 3000;

app.listen(port)
  .on('error',     console.error.bind(console))
  .on('listening', console.log.bind(console, 'Listening on ' + port));

Time to commit what we've done so far:

-Do your regular git commands to add, commit, and push to Github. At this point, you've got your local app working and local database all built and seeded.

Deploying to Heroku

Make sure you have the heroku cli installed and type

heroku create THENAME

-Replace THENAME with a project name of your choosing that hasn't been taken yet. Heroku should create the git remote for you at this point.

-Add the remote database on heroku:

heroku addons:create heroku-postgresql:hobby-dev

-Don't replace anything in the above command. That's what to type - including the hobby-dev part.

-Let's take a step back here. You have your local app working and pushed to Github. You have an empty project initialized on Heroku, and even a remote database on Heroku. BUT, you have no code pushed up to Heroku, therefore no seeds or migrations will work - there's no code to connect to this database. So let's push the code up to heroku:

git push heroku master

-Now the remote code to tell the migrations and seeds what to do (as well as install the necessary packages like knex, etc) are up on heroku. Now you can do:

heroku run knex migrate:latest
heroku run knex seed:run

-Done.

-One last thing: if you delete your local repo and you need to deploy it to heroku again, you need to re-establish the heroku git remote. You do that by doing:

heroku git:remote -a THENAME
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment