Skip to content

howell-brian project submission #343

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions api/model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
#### Data Access

Write a data access file that exports an object with the following function:

- `getRecipeById(recipe_id)`
- Should resolve a representation of the recipe similar to the one shown in the **Data Model** above.
- The function will pull information from several tables using Knex and then create a response object using loops, objects, array methods etc.
- There are many ways to solve this, but from a performance standpoint the fewer trips to the database the better!

#### Data Model

{
"recipe_id" : 1,
"recipe_name": "Spaghetti Bolognese",
"created_at": "2021-01-01 08:23:19.120",
"steps": [
{
"step_id": 11,
"step_number": 1,
"step_instructions": "Put a large saucepan on a medium heat",
"ingredients": []
},
{
"step_id": 12,
"step_number": 2,
"step_instructions": "Add 1 tbsp olive oil",
"ingredients": [
{ "ingredient_id": 27, "ingredient_name": "olive oil", "quantity": 0.014 }
]
},
]
}

*/

const db = require("../data/db-config.js");

function getRecipeById(recipe_id) {
return db("recipes")
.where("recipe_id", recipe_id)
.first()
.then((recipe) => {
if (!recipe) {
return null;
}
return db("steps")
.where("recipe_id", recipe_id)
.then((steps) => {
return {
recipe_id: recipe.recipe_id,
recipe_name: recipe.recipe_name,
created_at: recipe.created_at,
steps: steps.map((step) => {
return {
step_id: step.step_id,
step_number: step.step_number,
step_instructions: step.step_instructions,
ingredients: [],
};
}),
};
});
});
}

module.exports = {
getRecipeById,
};
15 changes: 15 additions & 0 deletions api/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const express = require("express");
const helpers = require("./model");

const router = express.Router();

router.get("/recipes/:recipe_id", (req, res, next) => {
helpers
.getRecipeById(req.params.recipe_id)
.then((recipe) => {
res.status(200).json(recipe);
})
.catch(next);
});

module.exports = router;
19 changes: 19 additions & 0 deletions api/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const express = require("express");
const helmet = require("helmet");
const router = require("./router");

const server = express();

server.use(helmet());
server.use(express.json());
server.use("/api", router);

server.use((err, req, res, next) => {
// eslint-disable-line
res.status(500).json({
message: err.message,
stack: err.stack,
});
});

module.exports = server;
5 changes: 5 additions & 0 deletions data/db-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const knex = require("knex");

const config = require("../knexfile.js");

module.exports = knex(config.development);
59 changes: 59 additions & 0 deletions data/migrations/20240617204828_create-tables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
exports.up = function (knex) {
// Tables
// - recipes
// - steps
// - ingredients
// - recipe_ingredients

return knex.schema
.createTable("recipes", (tbl) => {
tbl.increments("recipe_id");
tbl.string("recipe_name", 128).notNullable();
tbl.timestamp("created_at").defaultTo(knex.fn.now());
})
.createTable("steps", (tbl) => {
tbl.increments("step_id");
tbl.integer("step_number").notNullable();
tbl.string("step_instructions").notNullable();
tbl
.integer("recipe_id")
.unsigned()
.notNullable()
.references("recipe_id")
.inTable("recipes")
.onDelete("RESTRICT")
.onUpdate("RESTRICT");
})
.createTable("ingredients", (tbl) => {
tbl.increments("ingredient_id");
tbl.string("ingredient_name", 128).notNullable();
})
.createTable("recipe_ingredients", (tbl) => {
tbl
.integer("recipe_id")
.unsigned()
.notNullable()
.references("recipe_id")
.inTable("recipes")
.onDelete("RESTRICT")
.onUpdate("RESTRICT");
tbl
.integer("ingredient_id")
.unsigned()
.notNullable()
.references("ingredient_id")
.inTable("ingredients")
.onDelete("RESTRICT")
.onUpdate("RESTRICT");
tbl.float("quantity").notNullable();
tbl.primary(["recipe_id", "ingredient_id"]);
});
};

exports.down = function (knex) {
return knex.schema
.dropTableIfExists("recipe_ingredients")
.dropTableIfExists("ingredients")
.dropTableIfExists("steps")
.dropTableIfExists("recipes");
};
Binary file added data/recipes.db3
Binary file not shown.
102 changes: 102 additions & 0 deletions data/seeds/seed-recipes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
async function peanutButterAndJelly(knex) {
await knex("recipes").insert({
recipe_name: "Peanut Butter and Jelly",
});
await knex("steps").insert([
{
step_number: 1,
step_instructions: "Spread peanut butter on one slice of bread",
recipe_id: 1,
},
{
step_number: 2,
step_instructions: "Spread jelly on the other slice of bread",
recipe_id: 1,
},
{
step_number: 3,
step_instructions: "Put the two slices of bread together",
recipe_id: 1,
},
]);
await knex("ingredients").insert([
{ ingredient_name: "peanut butter" },
{ ingredient_name: "jelly" },
{ ingredient_name: "bread" },
]);
await knex("recipe_ingredients").insert([
{ recipe_id: 1, ingredient_id: 1, quantity: 1 },
{ recipe_id: 1, ingredient_id: 2, quantity: 1 },
{ recipe_id: 1, ingredient_id: 3, quantity: 2 },
]);
}

async function spaghetti(knex) {
await knex("recipes").insert({
recipe_name: "Spaghetti",
});
await knex("steps").insert([
{
step_number: 1,
step_instructions: "Boil water",
recipe_id: 2,
},
{
step_number: 2,
step_instructions: "Add spaghetti noodles to boiling water",
recipe_id: 2,
},
{
step_number: 3,
step_instructions: "Cook spaghetti noodles for 10 minutes",
recipe_id: 2,
},
{
step_number: 4,
step_instructions: "Drain spaghetti noodles",
recipe_id: 2,
},
{
step_number: 5,
step_instructions: "Add spaghetti sauce to noodles",
recipe_id: 2,
},
]);
await knex("ingredients").insert([
{ ingredient_name: "spaghetti noodles" },
{ ingredient_name: "spaghetti sauce" },
]);
await knex("recipe_ingredients").insert([
{ recipe_id: 2, ingredient_id: 4, quantity: 1 },
{ recipe_id: 2, ingredient_id: 5, quantity: 1 },
]);
}

async function water(knex) {
await knex("recipes").insert({
recipe_name: "Water",
});
await knex("steps").insert([
{
step_number: 1,
step_instructions: "Fill glass with water",
recipe_id: 3,
},
]);
await knex("ingredients").insert([{ ingredient_name: "water" }]);
await knex("recipe_ingredients").insert([
{ recipe_id: 3, ingredient_id: 6, quantity: 1 },
]);
}

exports.seed = async function (knex) {
// Deletes ALL existing entries
await knex("recipe_ingredients").truncate();
await knex("ingredients").truncate();
await knex("steps").truncate();
await knex("recipes").truncate();

await peanutButterAndJelly(knex);
await spaghetti(knex);
await water(knex);
};
7 changes: 7 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const server = require("./api/server.js");

const PORT = process.env.PORT || 9000;

server.listen(PORT, () => {
console.log(`Listening on port ${PORT}...`);
});
21 changes: 21 additions & 0 deletions knexfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module.exports = {
development: {
client: "sqlite3",
useNullAsDefault: true, // needed for sqlite
connection: {
filename: "./data/recipes.db3",
},
migrations: {
directory: "./data/migrations",
},
seeds: {
directory: "./data/seeds",
},
pool: {
afterCreate: (conn, done) => {
// runs after a connection is made to the sqlite engine
conn.run("PRAGMA foreign_keys = ON", done); // turn on FK enforcement
},
},
},
};
Loading