From 6d03f32009cbd0ee8404ebf43a92725cfb63325a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Broks=20Randolfs=20Gail=C4=ABtis?= Date: Wed, 5 Mar 2025 21:47:09 +0200 Subject: [PATCH] Initial db config Plus add cert creation for local development --- .gitignore | 6 + apps/blakus-api/.env.development | 5 + apps/blakus-api/knexfile.js | 22 ++ .../migrations/20250304134127_initial.js | 35 ++++ apps/blakus-api/project.json | 114 ++++++++++- apps/blakus-api/seeds/users.js | 37 ++++ apps/blakus-api/src/app/routes/root.ts | 5 +- apps/blakus-api/src/db.ts | 19 ++ apps/blakus-api/tsconfig.app.json | 6 +- package-lock.json | 192 +++++++++++++++--- package.json | 6 +- 11 files changed, 408 insertions(+), 39 deletions(-) create mode 100644 apps/blakus-api/.env.development create mode 100644 apps/blakus-api/knexfile.js create mode 100644 apps/blakus-api/migrations/20250304134127_initial.js create mode 100644 apps/blakus-api/seeds/users.js create mode 100644 apps/blakus-api/src/db.ts diff --git a/.gitignore b/.gitignore index fa5c690..01c78b5 100644 --- a/.gitignore +++ b/.gitignore @@ -41,5 +41,11 @@ Thumbs.db .nx/cache .nx/workspace-data +*.sqlite +*.sqlite3 +*.sqlite-journal *.db *.db-journal + +cert.pem +key.pem \ No newline at end of file diff --git a/apps/blakus-api/.env.development b/apps/blakus-api/.env.development new file mode 100644 index 0000000..89d6fdd --- /dev/null +++ b/apps/blakus-api/.env.development @@ -0,0 +1,5 @@ +DB_HOST=localhost +DB_PORT=5432 +DB_NAME=blakus +DB_USER=dev +DB_PASSWORD=dhzVd5s@pazAWG4eKrm@ \ No newline at end of file diff --git a/apps/blakus-api/knexfile.js b/apps/blakus-api/knexfile.js new file mode 100644 index 0000000..c4e8b75 --- /dev/null +++ b/apps/blakus-api/knexfile.js @@ -0,0 +1,22 @@ +// Update with your config settings. + +/** + * @type { Object. } + */ +module.exports = { + client: 'postgresql', + connection: { + host: process.env.DB_HOST, + port: process.env.DB_PORT, + database: process.env.DB_NAME, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD + }, + pool: { + min: 2, + max: 10 + }, + migrations: { + tableName: 'knex_migrations' + } +}; \ No newline at end of file diff --git a/apps/blakus-api/migrations/20250304134127_initial.js b/apps/blakus-api/migrations/20250304134127_initial.js new file mode 100644 index 0000000..45b31a1 --- /dev/null +++ b/apps/blakus-api/migrations/20250304134127_initial.js @@ -0,0 +1,35 @@ +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = function(knex) { + + return knex.schema + .createTable('users', function (table) { + table.uuid('id') + .primary() + .defaultTo(knex.raw(`gen_random_uuid()`)); + table.string('first_name', 255) + .notNullable(); + table.string('last_name', 255) + .notNullable(); + table.string('email', 255) + .unique() + .notNullable(); + }) + // .createTable('products', function (table) { + // table.increments('id'); + // table.decimal('price').notNullable(); + // table.string('name', 1000).notNullable(); + // }); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = function(knex) { + return knex.schema + // .dropTable('products') + .dropTable('users'); +}; diff --git a/apps/blakus-api/project.json b/apps/blakus-api/project.json index 3ab026e..54e8784 100644 --- a/apps/blakus-api/project.json +++ b/apps/blakus-api/project.json @@ -26,7 +26,16 @@ } }, "configurations": { - "development": {}, + "development": { + "assets": [ + "apps/blakus-api/src/assets", + { + "glob": "**/*", + "input": "apps/blakus-api/certs", + "output": "apps/blakus-api/certs" + } + ] + }, "production": { "esbuildOptions": { "sourcemap": false, @@ -47,7 +56,8 @@ }, "configurations": { "development": { - "buildTarget": "blakus-api:build:development" + "buildTarget": "blakus-api:build:development", + "watch": true }, "production": { "buildTarget": "blakus-api:build:production" @@ -59,20 +69,106 @@ "passWithNoTests": true } }, - "prisma-generate": { + "knex:migrate-make": { "executor": "nx:run-commands", "defaultConfiguration": "development", "options": { "cwd": "apps/blakus-api", - "commands": ["npx prisma generate"] + "command": "npx knex migrate:make farts" + }, + "schema": { + "name": { + "type": "string", + "required": true + } + } + }, + "knex:migrate-latest": { + "executor": "nx:run-commands", + "defaultConfiguration": "development", + "options": { + "cwd": "apps/blakus-api", + "command": "npx knex migrate:latest" }, "configurations": { - "development": { - "envFile": "apps/blakus-api/.env.development" - }, - "production": { - "envFile": "apps/blakus-api/.env.production" + "development": {}, + "production": {} + } + }, + "knex:migrate-rollback": { + "executor": "nx:run-commands", + "defaultConfiguration": "development", + "options": { + "cwd": "apps/blakus-api", + "command": "npx knex migrate:rollback" + }, + "configurations": { + "development": {}, + "production": {} + } + }, + "knex:migrate-up": { + "executor": "nx:run-commands", + "defaultConfiguration": "development", + "options": { + "cwd": "apps/blakus-api", + "command": "npx knex migrate:up" + }, + "configurations": { + "development": {}, + "production": {} + } + }, + "knex:migrate-down": { + "executor": "nx:run-commands", + "defaultConfiguration": "development", + "options": { + "cwd": "apps/blakus-api", + "command": "npx knex migrate:down" + }, + "configurations": { + "development": {}, + "production": {} + } + }, + "knex:seed-make": { + "executor": "nx:run-commands", + "defaultConfiguration": "development", + "options": { + "cwd": "apps/blakus-api", + "command": "npx knex seed:make initial" + }, + "schema": { + "name": { + "type": "string", + "required": true } + }, + "configurations": { + "development": {}, + "production": {} + } + }, + "knex:seed-run": { + "executor": "nx:run-commands", + "defaultConfiguration": "development", + "options": { + "cwd": "apps/blakus-api", + "command": "npx knex seed:run" + }, + "configurations": { + "development": {}, + "production": {} + } + }, + "certs:generate": { + "executor": "nx:run-commands", + "options": { + "cwd": "apps/blakus-api", + "commands": [ + "mkcert -install", + "mkcert -key-file ./certs/key.pem -cert-file ./certs/cert.pem localhost 127.0.0.1 ::1 ${API_HOST}" + ] } } } diff --git a/apps/blakus-api/seeds/users.js b/apps/blakus-api/seeds/users.js new file mode 100644 index 0000000..e855fe9 --- /dev/null +++ b/apps/blakus-api/seeds/users.js @@ -0,0 +1,37 @@ +const { fakerLV : faker } = require('@faker-js/faker'); + +const USER_COUNT = 500; + +const createUser = ({ + sex = faker.person.sexType(), + first_name = `${faker.person.firstName(sex)}`, + last_name = faker.person.lastName(sex), + email = faker.internet.email({ lastName: last_name, firstName: first_name }).toLocaleLowerCase(), +} = {}) => { + return { + first_name, + last_name, + email, + } +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.seed = async function(knex) { + // Deletes ALL existing entries + await knex('users').del() + await knex('users').insert([ + createUser({ + first_name: 'Broks Randolfs', + last_name: 'Gailītis', + email: 'broks.randolfs@gailitis.dev' + }), + createUser({ + first_name: 'Ieva', + last_name: 'Gailīte' + }), + ...new Array(USER_COUNT).fill(() => createUser()).map((fn, i) => fn(i)), + ]); +}; diff --git a/apps/blakus-api/src/app/routes/root.ts b/apps/blakus-api/src/app/routes/root.ts index 8eafa60..e361629 100644 --- a/apps/blakus-api/src/app/routes/root.ts +++ b/apps/blakus-api/src/app/routes/root.ts @@ -1,8 +1,9 @@ import { FastifyInstance } from 'fastify'; - +import db from '../../db'; export default async function (fastify: FastifyInstance) { + const users = await db.select('*').from('users'); fastify.get('/', async function () { - return { usersWithPosts: [] }; + return { users }; }); } diff --git a/apps/blakus-api/src/db.ts b/apps/blakus-api/src/db.ts new file mode 100644 index 0000000..9f34947 --- /dev/null +++ b/apps/blakus-api/src/db.ts @@ -0,0 +1,19 @@ +import knex from 'knex'; + +const knexInstance = knex({ + client: 'postgresql', + connection: { + database: process.env.DB_NAME, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD + }, + pool: { + min: 2, + max: 10 + }, + migrations: { + tableName: 'knex_migrations' + } +}); + +export default knexInstance; \ No newline at end of file diff --git a/apps/blakus-api/tsconfig.app.json b/apps/blakus-api/tsconfig.app.json index 21e2061..9111a77 100644 --- a/apps/blakus-api/tsconfig.app.json +++ b/apps/blakus-api/tsconfig.app.json @@ -3,8 +3,10 @@ "compilerOptions": { "outDir": "../../dist/out-tsc", "module": "commonjs", - "types": ["node"] + "types": ["node"], + "allowJs": true, + "esModuleInterop": true }, - "include": ["src/**/*.ts"], + "include": ["src/**/*.ts", "src/**/*.js"], "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] } diff --git a/package-lock.json b/package-lock.json index 6937160..52d1cf5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,14 +12,17 @@ "@fastify/autoload": "~6.0.3", "@fastify/sensible": "~6.0.2", "@nativescript/core": "~8.8.0", + "@sinclair/typebox": "^0.34.28", "axios": "^1.6.0", "fastify": "~5.2.1", "fastify-plugin": "~5.0.1", "knex": "^3.1.0", + "pg": "^8.13.3", "sqlite3": "^5.1.7" }, "devDependencies": { "@eslint/js": "^9.8.0", + "@faker-js/faker": "^9.5.1", "@nativescript/nx": "^20.3.0", "@nativescript/types": "~8.8.0", "@nativescript/webpack": "~5.0.0", @@ -34,7 +37,6 @@ "@swc/core": "~1.5.7", "@swc/helpers": "~0.5.11", "@types/jest": "^29.5.12", - "@types/knex": "^0.15.2", "@types/node": "~18.16.9", "ajv": "^8.17.1", "esbuild": "^0.19.2", @@ -45,7 +47,7 @@ "nx": "20.4.6", "prettier": "^2.6.2", "ts-jest": "^29.1.0", - "ts-node": "10.9.1", + "ts-node": "^10.9.1", "tslib": "^2.3.0", "typescript": "~5.7.2", "typescript-eslint": "^8.19.0" @@ -2630,6 +2632,23 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@faker-js/faker": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.5.1.tgz", + "integrity": "sha512-0fzMEDxkExR2cn731kpDaCCnBGBUOIXEi2S1N5l8Hltp6aPf4soTMJ+g4k8r2sI5oB+rpwIW8Uy/6jkwGpnWPg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0.0", + "npm": ">=9.0.0" + } + }, "node_modules/@fastify/ajv-compiler": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-4.0.2.tgz", @@ -3062,6 +3081,13 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/schemas/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/source-map": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", @@ -4252,10 +4278,9 @@ "license": "MIT" }, "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, + "version": "0.34.28", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.28.tgz", + "integrity": "sha512-e2B9vmvaa5ym5hWgCHw5CstP54au6AOLXrhZErLsOyyRzuWJtXl/8TszKtc5x8rw/b+oY7HKS9m9iRI53RK0WQ==", "license": "MIT" }, "node_modules/@sinonjs/commons": { @@ -4670,13 +4695,6 @@ "@babel/types": "^7.20.7" } }, - "node_modules/@types/bluebird": { - "version": "3.5.42", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.42.tgz", - "integrity": "sha512-Jhy+MWRlro6UjVi578V/4ZGNfeCOcNCp0YaFNIUGFKlImowqwb1O/22wDVk3FDGMLqxdpOV3qQHD5fPEH4hK6A==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -4761,17 +4779,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/knex": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@types/knex/-/knex-0.15.2.tgz", - "integrity": "sha512-mw8OT8v+FK0SsgDdmio2XSkEM/yLD7ybFtiqW7I65EDTlr2aZtG+p9FhryErpNJDJ2FEXgQhe3JVBG0Gh7YbvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/bluebird": "*", - "@types/node": "*" - } - }, "node_modules/@types/node": { "version": "18.16.20", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.20.tgz", @@ -11660,12 +11667,101 @@ "node": ">=8" } }, + "node_modules/pg": { + "version": "8.13.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.3.tgz", + "integrity": "sha512-P6tPt9jXbL9HVu/SSRERNYaYG++MjnscnegFh9pPHihfoBSujsrka0hyuymMzeJKFWrcG8wvCKy8rCe8e5nDUQ==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.7.0", + "pg-pool": "^3.7.1", + "pg-protocol": "^1.7.1", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "license": "MIT", + "optional": true + }, "node_modules/pg-connection-string": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==", "license": "MIT" }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.1.tgz", + "integrity": "sha512-xIOsFoh7Vdhojas6q3596mXFsR8nwBQBXX5JiV7p9buEVAGqYL4yFzclON5P9vFrpu1u7Zwl2oriyDa89n0wbw==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.1.tgz", + "integrity": "sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/pg-connection-string": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", + "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==", + "license": "MIT" + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -11965,6 +12061,45 @@ "dev": true, "license": "MIT" }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prebuild-install": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", @@ -14613,6 +14748,15 @@ "node": ">=8.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 05ff2ee..4cb39ef 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "private": true, "devDependencies": { "@eslint/js": "^9.8.0", + "@faker-js/faker": "^9.5.1", "@nativescript/nx": "^20.3.0", "@nativescript/types": "~8.8.0", "@nativescript/webpack": "~5.0.0", @@ -20,7 +21,6 @@ "@swc/core": "~1.5.7", "@swc/helpers": "~0.5.11", "@types/jest": "^29.5.12", - "@types/knex": "^0.15.2", "@types/node": "~18.16.9", "ajv": "^8.17.1", "esbuild": "^0.19.2", @@ -31,7 +31,7 @@ "nx": "20.4.6", "prettier": "^2.6.2", "ts-jest": "^29.1.0", - "ts-node": "10.9.1", + "ts-node": "^10.9.1", "tslib": "^2.3.0", "typescript": "~5.7.2", "typescript-eslint": "^8.19.0" @@ -40,10 +40,12 @@ "@fastify/autoload": "~6.0.3", "@fastify/sensible": "~6.0.2", "@nativescript/core": "~8.8.0", + "@sinclair/typebox": "^0.34.28", "axios": "^1.6.0", "fastify": "~5.2.1", "fastify-plugin": "~5.0.1", "knex": "^3.1.0", + "pg": "^8.13.3", "sqlite3": "^5.1.7" }, "nativescript-nx": {