feat: added Prisma
This commit is contained in:
Riccardo Senica
2023-08-05 17:23:34 +02:00
committed by GitHub
parent 9c01101c1b
commit 392e0db67b
17 changed files with 181 additions and 18 deletions

View File

@@ -2,6 +2,13 @@ name: Pipeline
on: [push]
env:
POSTGRES_DATABASE: ${{ secrets.POSTGRES_DATABASE }}
POSTGRES_USERNAME: ${{ secrets.POSTGRES_USERNAME }}
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
POSTGRES_HOST: ${{ secrets.POSTGRES_HOST }}
POSTGRES_PORT: ${{ secrets.POSTGRES_PORT }}
jobs:
lint:
runs-on: ubuntu-latest
@@ -32,12 +39,27 @@ jobs:
- run: yarn audit
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15.3
env:
POSTGRES_USER: ${{ env.POSTGRES_USERNAME }}
POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
POSTGRES_DB: ${{ env.POSTGRES_DATABASE }}
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- env:
DATABASE_URL: postgres://${{ secrets.POSTGRES_USERNAME }}:${{ secrets.POSTGRES_PASSWORD }}@${{ secrets.POSTGRES_HOST }}:${{ secrets.POSTGRES_PORT }}/${{ secrets.POSTGRES_DATABASE }}
run: |
echo "DATABASE_URL=${DATABASE_URL}" > .env
- run: yarn
- run: yarn db:migrate
- run: yarn test
build:
runs-on: ubuntu-latest

1
.gitignore vendored
View File

@@ -131,3 +131,4 @@ dist
# Custom
build
.env

View File

@@ -10,6 +10,11 @@ It contains basic configurations for the following:
- Winston (logging)
- GitHub Actions (CI/CD)
# Environment Variables
- PORT - The port to run the server on
- `DATABASE_URL` - The URL to the database, formatted as `postgres://<username>:<password>@<host>:<port>/<database>`
## Commands
Install dependencies:

View File

@@ -10,7 +10,8 @@ const config: Config = {
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.ts$': '@swc/jest'
}
},
setupFilesAfterEnv: ['./src/utils/clearDatabase.ts']
};
export default config;

View File

@@ -13,7 +13,10 @@
"typecheck": "tsc",
"format": "prettier --config .prettierrc 'src/**/*.ts' --write",
"test": "jest --runInBand --detectOpenHandles",
"prepare": "husky install"
"prepare": "husky install",
"db:generate": "prisma generate",
"db:migrate": "prisma migrate deploy",
"db:reset": "prisma migrate reset --force"
},
"lint-staged": {
"*.ts": [
@@ -24,11 +27,14 @@
]
},
"dependencies": {
"@prisma/client": "5.1.1",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"crypto": "^1.0.1",
"express": "^4.18.2",
"helmet": "^7.0.0",
"jsonschema": "^1.4.1",
"prisma": "^5.1.1",
"winston": "^3.10.0",
"winston-daily-rotate-file": "^4.7.1"
},

View File

@@ -0,0 +1,8 @@
-- CreateTable
CREATE TABLE "Addition" (
"id" TEXT NOT NULL,
"datetime" TIMESTAMP(3) NOT NULL,
"value" INTEGER NOT NULL,
CONSTRAINT "Addition_pkey" PRIMARY KEY ("id")
);

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"

17
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,17 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Addition {
id String @id
datetime DateTime
value Int
}

View File

@@ -0,0 +1,13 @@
import { createAddition, readAddition } from './database';
describe('Database', () => {
it('creates a new record in the Addition table and reads it', async () => {
const value = 13;
const createResult = await createAddition(value);
const readResult = await readAddition(createResult.id);
expect(readResult).toBeDefined();
expect(readResult.value).toBe(value);
});
});

32
src/database/database.ts Normal file
View File

@@ -0,0 +1,32 @@
import { PrismaClient } from '@prisma/client';
import { randomUUID } from 'crypto';
const prisma = new PrismaClient();
/**
* Create a new record in the Addition table.
* @param value - The value number to add as a new record.
* @returns Whether the database operation succeeded.
*/
export async function createAddition(value: number) {
return await prisma.addition.create({
data: {
id: randomUUID(),
datetime: new Date(),
value
}
});
}
/**
* Retrieve a record from the Addition table.
* @param id - The id of the record.
* @returns The retrieved record, or an error.
*/
export async function readAddition(id: string) {
return await prisma.addition.findUniqueOrThrow({
where: {
id
}
});
}

View File

@@ -1,5 +1,7 @@
import server from './server/server';
server.listen(3000, () => {
console.log('Server running on port 3000');
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

View File

@@ -1,15 +1,9 @@
import requests from 'supertest';
import server from './server';
beforeAll(() => {
jest.mock('../utils/addition', () => ({
addition: jest.fn((value: number) => value + 1)
}));
});
afterAll(() => {
jest.clearAllMocks();
});
jest.mock('../utils/addition', () => ({
addition: jest.fn((value: number) => value + 1)
}));
describe('server', () => {
it('returns input value increased by one', async () => {

View File

@@ -22,14 +22,18 @@ const schema = {
required: ['value']
};
server.post('/', (req: Request, res: Response) => {
server.post('/', async (req: Request, res: Response) => {
logger.info(`POST / with ${JSON.stringify(req.body)}`);
if (!validator.validate(req.body, schema).valid) {
return res.status(400).json({ message: 'Malformed query parameters' });
}
const { value } = req.body;
const result = await addition(value);
return res.json({
response: addition(parseInt(req.body.value))
response: result
});
});

View File

@@ -1,8 +1,17 @@
import { randomUUID } from 'crypto';
import { addition } from './addition';
jest.mock('../database/database', () => ({
createAddition: jest.fn((value: number) => ({
id: randomUUID(),
datetime: new Date(),
value
}))
}));
describe('call', () => {
it('returns the input value increased by one', async () => {
const response = addition(3);
const response = await addition(3);
expect(response).toBe(4);
});

View File

@@ -1,11 +1,14 @@
import { createAddition } from '../database/database';
import { logger } from './logger';
/**
* Format a response message containing a user input.
* Increase the user imput value by one, and creates an Addition record with that value.
* @param number - The user input value.
* @returns The value increased by one.
*/
export function addition(value: number) {
export async function addition(value: number) {
logger.info(`addition(${value})`);
await createAddition(value);
return value + 1;
}

View File

@@ -0,0 +1,14 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
/**
* Clear the database of all records.
*/
export const clearDatabase = async () => {
await prisma.addition.deleteMany({});
};
global.beforeAll(async () => {
await clearDatabase();
});

View File

@@ -846,6 +846,23 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@prisma/client@5.1.1":
version "5.1.1"
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.1.1.tgz#ea2b0c8599bdb3f86d92e8df46fba795a744db01"
integrity sha512-fxcCeK5pMQGcgCqCrWsi+I2rpIbk0rAhdrN+ke7f34tIrgPwA68ensrpin+9+fZvuV2OtzHmuipwduSY6HswdA==
dependencies:
"@prisma/engines-version" "5.1.1-1.6a3747c37ff169c90047725a05a6ef02e32ac97e"
"@prisma/engines-version@5.1.1-1.6a3747c37ff169c90047725a05a6ef02e32ac97e":
version "5.1.1-1.6a3747c37ff169c90047725a05a6ef02e32ac97e"
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.1.1-1.6a3747c37ff169c90047725a05a6ef02e32ac97e.tgz#2e8a1f098ec09452dbe00923b24f582f95d1747c"
integrity sha512-owZqbY/wucbr65bXJ/ljrHPgQU5xXTSkmcE/JcbqE1kusuAXV/TLN3/exmz21SZ5rJ7WDkyk70J2G/n68iogbQ==
"@prisma/engines@5.1.1":
version "5.1.1"
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.1.1.tgz#9c26d209f93a563e048eab63b1976f222f1707d0"
integrity sha512-NV/4nVNWFZSJCCIA3HIFJbbDKO/NARc9ej0tX5S9k2EVbkrFJC4Xt9b0u4rNZWL4V+F5LAjvta8vzEUw0rw+HA==
"@sinclair/typebox@^0.27.8":
version "0.27.8"
resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz"
@@ -1922,6 +1939,11 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"
crypto@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037"
integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==
dargs@^7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz"
@@ -3936,6 +3958,13 @@ pretty-format@^29.0.0, pretty-format@^29.6.1:
ansi-styles "^5.0.0"
react-is "^18.0.0"
prisma@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.1.1.tgz#8f5c0f9467a828746cb94f846d694dc7b7481a9e"
integrity sha512-WJFG/U7sMmcc6TjJTTifTfpI6Wjoh55xl4AzopVwAdyK68L9/ogNo8QQ2cxuUjJf/Wa82z/uhyh3wMzvRIBphg==
dependencies:
"@prisma/engines" "5.1.1"
prompts@^2.0.1:
version "2.4.2"
resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz"