simply learn-full-stack-7
November 21, 2022
Simply Learn Full-Stack React & Node.js
Let's jump right in!
All the edits we need to make are on the server. We're gonna use Prisma ORM and SqlLite DB for convenience. We need to install these in node-server
Install the Prisma client which express will use to connect to our database:
npm i -S @prisma/client
Next install Prisma, also on the server:
npm i -D prisma
-Dis shorthand for--save-dev. This saves the package under devDependencies
Under node-server create a new folder prisma
In folder prisma, create a new file schema.prisma. Set the contents to:
1datasource db {2 provider = "sqlite"3 url = "file:./data.db?connection_limit=1"4}56generator client {7 provider = "prisma-client-js"8}910model Note {11 id String @id @default(cuid())12 title String13 content String14 authorId String15 lang String16 isLive Boolean17 category String1819 createdAt DateTime @default(now())20 updatedAt DateTime @updatedAt2122 author Author @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade)23}2425model Author {26 id String @id @default(cuid())27 username String @unique2829 createdAt DateTime @default(now())30 updatedAt DateTime @updatedAt3132 notes Note[]33}
We have two tables here:
- Note
- Author
To generate the SqlLite database file run this command from node-server folder:
npx prisma db push
Now to generate the DB entities run:
npx prisma generate
In node-server create a new folder: models. Inside node-server/models create 3 new files:
- db.js
- author.model.js
- note.model.js
Edit db.js to:
1const { PrismaClient } = require("@prisma/client")23let prisma;45if (process.env.NODE_ENV === "production") {6 prisma = new PrismaClient()7} else {8 const {__db__} = global;910 if (__db__) {11 prisma = __db__12 } else {13 prisma = new PrismaClient({14 log: [15 {16 emit: "event",17 level: "query",18 },19 "info",20 "warn",21 "error",22 ],23 });2425 prisma.$on("query", ({query, duration}) => {26 console.log(`\x1b[36mprisma:query\x1b[0m ${query}`);27 console.log(`Took: ${duration}ms`)28 });2930 global.__db__ = prisma31 }3233 prisma.$connect();34}3536module.exports = {37 prisma38}
In development environments, this creates a single prisma instance and stores it as a global and logs SQL queries to the console.
Edit author.model.js to:
1const { prisma } = require("./db")23async function getAuthor(id) {4 return prisma.author.findUnique({ where: { id } });5}67async function getAuthorByName(username) {8 return prisma.author.findUnique({ where: { username } });9}1011async function createAuthor(12 author13) {14 return prisma.author.create({15 data: author16 });17}1819module.exports = {20 getAuthor,21 getAuthorByName,22 createAuthor,23}
Edit note.model.js to:
1const { prisma } = require("./db")23async function getNotes() {4 return prisma.note.findMany();5}67async function getNote(id) {8 return prisma.note.findUnique({ where: { id } });9}1011async function createNote(12 note13) {14 return prisma.note.create({15 data: note16 });17}1819async function updateNote(20 note21) {22 return prisma.note.update({23 data: note,24 });25}2627module.exports = {28 getNotes,29 getNote,30 createNote,31 updateNote,32}
That finishes our data access layer. These ORM functions can now be used in our controllers to access data.
First we need to create a script to seed our database. In the prisma folder, create a new file seed.js:
1const { PrismaClient } = require("@prisma/client")2const prisma = new PrismaClient();34async function seed() {5 // Blitz everything!6 await prisma.note.deleteMany();7 await prisma.author.deleteMany();89 const author = await prisma.author.create({10 data: {11 username: 'neohed'12 },13 });1415 await prisma.note.create({16 data: {17 title: 'A New Note',18 content: 'This note is retrieved from the database!',19 authorId: author.id,20 lang: 'en',21 isLive: true,22 category: '',23 },24 });2526 console.log(`Database has been seeded. 🌱`)27}2829seed()30 .then(() => {31 console.log('Prisma seed function in prisma/seed.js executed!')32 })33 .catch((e) => {34 console.error(e);35 process.exit(1)36 })37 .finally(async () => {38 await prisma.$disconnect()39 })
Now we need to reference this script from package.json. Edit package.json to this:
1{2 "name": "server",3 "version": "1.0.0",4 "description": "",5 "main": "index.js",6 "scripts": {7 "start": "node index.js",8 "test": "echo \"Error: no test specified\" && exit 1"9 },10 "keywords": [],11 "author": "",12 "license": "ISC",13 "dependencies": {14 "@prisma/client": "^4.0.0",15 "body-parser": "^1.20.0",16 "cors": "^2.8.5",17 "express": "^4.18.1",18 "morgan": "^1.10.0"19 },20 "devDependencies": {21 "prisma": "^4.0.0"22 },23 "prisma": {24 "seed": "node prisma/seed.js"25 }26}
Now run the seed script, execute this:
npx prisma db seed
This will run the seed.js script and populate the database with one author and one note record.
And finally, edit note.controller.js to:
1const authorRepo = require('../models/author.model');2const noteRepo = require('../models/note.model');34async function getNote(req, res) {5 const notes = await noteRepo.getNotes();6 //HACK return top 1 note7 const { authorId, ...noteRest } = notes[0];8 const { username } = await authorRepo.getAuthor(authorId);910 res.json({ note: {11 ...noteRest,12 author: username13 }14 });15}1617async function postNote(req, res) {18 const {body} = req;19 const {id, title, content, author, lang, isLive, category} = body;2021 console.log('Server received data:');22 console.log({id, title, content, author, lang, isLive, category})2324 res25 .status(200)26 .json({27 message: 'Ok'28 })29}3031module.exports = {32 getNote,33 postNote34}
If you run your server and client now, you should see different data, loaded from the SqlLite database! You will also see the SQL queries logged in your server console.
Next CRUD operations, ...
Code repo: Github Repository