diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..397b4a76 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.log diff --git a/Makefile b/Makefile index 9cac7388..28bd2115 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +DB_URL=postgresql://root:secret@localhost:5432/simple_bank?sslmode=disable + network: docker network create bank-network @@ -14,16 +16,22 @@ dropdb: docker exec -it postgres12 dropdb simple_bank migrateup: - migrate -path db/migration -database "postgresql://root:secret@localhost:5432/simple_bank?sslmode=disable" -verbose up + migrate -path db/migration -database "$(DB_URL)" -verbose up migrateup1: - migrate -path db/migration -database "postgresql://root:secret@localhost:5432/simple_bank?sslmode=disable" -verbose up 1 + migrate -path db/migration -database "$(DB_URL)" -verbose up 1 migratedown: - migrate -path db/migration -database "postgresql://root:secret@localhost:5432/simple_bank?sslmode=disable" -verbose down + migrate -path db/migration -database "$(DB_URL)" -verbose down migratedown1: - migrate -path db/migration -database "postgresql://root:secret@localhost:5432/simple_bank?sslmode=disable" -verbose down 1 + migrate -path db/migration -database "$(DB_URL)" -verbose down 1 + +db_docs: + dbdocs build doc/db.dbml + +db_schema: + dbml2sql --postgres -o doc/schema.sql doc/db.dbml sqlc: sqlc generate @@ -37,4 +45,4 @@ server: mock: mockgen -package mockdb -destination db/mock/store.go github.com/techschool/simplebank/db/sqlc Store -.PHONY: network postgres createdb dropdb migrateup migratedown migrateup1 migratedown1 sqlc test server mock +.PHONY: network postgres createdb dropdb migrateup migratedown migrateup1 migratedown1 db_docs db_schema sqlc test server mock diff --git a/README.md b/README.md index a8f895d9..bf732a8c 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,20 @@ The service that we’re going to build is a simple bank. It will provide APIs f brew install golang-migrate ``` +- [DB Docs](https://dbdocs.io/docs) + + ```bash + npm install -g dbdocs + dbdocs login + ``` + +- [DBML CLI](https://www.dbml.org/cli/#installation) + + ```bash + npm install -g @dbml/cli + dbml2sql --version + ``` + - [Sqlc](https://github.com/kyleconroy/sqlc#installation) ```bash @@ -139,8 +153,24 @@ The service that we’re going to build is a simple bank. It will provide APIs f make migratedown1 ``` +### Documentation + +- Generate DB documentation: + + ```bash + make db_docs + ``` + +- Access the DB documentation at [this address](https://dbdocs.io/techschool.guru/simple_bank). Password: `secret` + ### How to generate code +- Generate schema SQL file with DBML: + + ```bash + make db_schema + ``` + - Generate SQL CRUD with sqlc: ```bash diff --git a/doc/db.dbml b/doc/db.dbml new file mode 100644 index 00000000..dff34f7a --- /dev/null +++ b/doc/db.dbml @@ -0,0 +1,64 @@ +Project simple_bank { + database_type: 'PostgreSQL' + Note: ''' + # Simple Bank Database + ''' +} + +Table users as U { + username varchar [pk] + hashed_password varchar [not null] + full_name varchar [not null] + email varchar [unique, not null] + password_changed_at timestamptz [not null, default: '0001-01-01'] + created_at timestamptz [not null, default: `now()`] +} + +Table accounts as A { + id bigserial [pk] + owner varchar [ref: > U.username, not null] + balance bigint [not null] + currency varchar [not null] + created_at timestamptz [not null, default: `now()`] + + Indexes { + owner + (owner, currency) [unique] + } +} + +Table entries { + id bigserial [pk] + account_id bigint [ref: > A.id, not null] + amount bigint [not null, note: 'can be negative or positive'] + created_at timestamptz [not null, default: `now()`] + + Indexes { + account_id + } +} + +Table transfers { + id bigserial [pk] + from_account_id bigint [ref: > A.id, not null] + to_account_id bigint [ref: > A.id, not null] + amount bigint [not null, note: 'must be positive'] + created_at timestamptz [not null, default: `now()`] + + Indexes { + from_account_id + to_account_id + (from_account_id, to_account_id) + } +} + +Table sessions { + id uuid [pk] + username varchar [ref: > U.username, not null] + refresh_token varchar [not null] + user_agent varchar [not null] + client_ip varchar [not null] + is_blocked boolean [not null, default: false] + expires_at timestamptz [not null] + created_at timestamptz [not null, default: `now()`] +} diff --git a/doc/schema.sql b/doc/schema.sql new file mode 100644 index 00000000..612fc867 --- /dev/null +++ b/doc/schema.sql @@ -0,0 +1,72 @@ +-- SQL dump generated using DBML (dbml-lang.org) +-- Database: PostgreSQL +-- Generated at: 2022-03-12T09:34:57.260Z + +CREATE TABLE "users" ( + "username" varchar PRIMARY KEY, + "hashed_password" varchar NOT NULL, + "full_name" varchar NOT NULL, + "email" varchar UNIQUE NOT NULL, + "password_changed_at" timestamptz NOT NULL DEFAULT '0001-01-01', + "created_at" timestamptz NOT NULL DEFAULT (now()) +); + +CREATE TABLE "accounts" ( + "id" bigserial PRIMARY KEY, + "owner" varchar NOT NULL, + "balance" bigint NOT NULL, + "currency" varchar NOT NULL, + "created_at" timestamptz NOT NULL DEFAULT (now()) +); + +CREATE TABLE "entries" ( + "id" bigserial PRIMARY KEY, + "account_id" bigint NOT NULL, + "amount" bigint NOT NULL, + "created_at" timestamptz NOT NULL DEFAULT (now()) +); + +CREATE TABLE "transfers" ( + "id" bigserial PRIMARY KEY, + "from_account_id" bigint NOT NULL, + "to_account_id" bigint NOT NULL, + "amount" bigint NOT NULL, + "created_at" timestamptz NOT NULL DEFAULT (now()) +); + +CREATE TABLE "sessions" ( + "id" uuid PRIMARY KEY, + "username" varchar NOT NULL, + "refresh_token" varchar NOT NULL, + "user_agent" varchar NOT NULL, + "client_ip" varchar NOT NULL, + "is_blocked" boolean NOT NULL DEFAULT false, + "expires_at" timestamptz NOT NULL, + "created_at" timestamptz NOT NULL DEFAULT (now()) +); + +CREATE INDEX ON "accounts" ("owner"); + +CREATE UNIQUE INDEX ON "accounts" ("owner", "currency"); + +CREATE INDEX ON "entries" ("account_id"); + +CREATE INDEX ON "transfers" ("from_account_id"); + +CREATE INDEX ON "transfers" ("to_account_id"); + +CREATE INDEX ON "transfers" ("from_account_id", "to_account_id"); + +COMMENT ON COLUMN "entries"."amount" IS 'can be negative or positive'; + +COMMENT ON COLUMN "transfers"."amount" IS 'must be positive'; + +ALTER TABLE "accounts" ADD FOREIGN KEY ("owner") REFERENCES "users" ("username"); + +ALTER TABLE "entries" ADD FOREIGN KEY ("account_id") REFERENCES "accounts" ("id"); + +ALTER TABLE "transfers" ADD FOREIGN KEY ("from_account_id") REFERENCES "accounts" ("id"); + +ALTER TABLE "transfers" ADD FOREIGN KEY ("to_account_id") REFERENCES "accounts" ("id"); + +ALTER TABLE "sessions" ADD FOREIGN KEY ("username") REFERENCES "users" ("username");