Skip to content
This repository has been archived by the owner on Dec 25, 2024. It is now read-only.

Commit

Permalink
Merge pull request #9 from walnuts1018/initDB
Browse files Browse the repository at this point in the history
Init db
  • Loading branch information
walnuts1018 authored Nov 3, 2023
2 parents 2c8d01a + 27d383f commit a21b801
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 52 deletions.
110 changes: 110 additions & 0 deletions back/infra/psql/init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
-- 公開タイプの列挙型を定義
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'public_type') THEN
CREATE TYPE public_type AS ENUM ('private', 'public', 'restricted');
END IF;
END$$;

-- ユーザーテーブル
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY
);

-- ユーザーグループテーブル
CREATE TABLE IF NOT EXISTS user_groups (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
creator_id BIGINT NOT NULL,
FOREIGN KEY (creator_id) REFERENCES users(id)
);

-- マネープールテーブル
CREATE TABLE IF NOT EXISTS money_pool (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
type public_type NOT NULL,
owner_id BIGINT NOT NULL,
FOREIGN KEY (owner_id) REFERENCES users(id)
);

-- マネープロバイダーテーブル
CREATE TABLE IF NOT EXISTS money_provider (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
creator_id BIGINT NOT NULL,
balance DECIMAL(19,4) NOT NULL CHECK (balance >= 0),
FOREIGN KEY (creator_id) REFERENCES users(id)
);

-- 店舗テーブル
CREATE TABLE IF NOT EXISTS store (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
creator_id BIGINT NOT NULL,
FOREIGN KEY (creator_id) REFERENCES users(id)
);

-- 商品テーブル
CREATE TABLE IF NOT EXISTS item (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
creator_id BIGINT NOT NULL,
FOREIGN KEY (creator_id) REFERENCES users(id)
);

-- ラベルテーブル
CREATE TABLE IF NOT EXISTS label (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
creator_id BIGINT NOT NULL,
FOREIGN KEY (creator_id) REFERENCES users(id)
);

-- 取引テーブル
CREATE TABLE IF NOT EXISTS payment (
id BIGSERIAL PRIMARY KEY,
money_pool_id BIGINT NOT NULL,
date DATE NOT NULL,
title VARCHAR(255) NOT NULL,
amount DECIMAL(19,4) NOT NULL,
description TEXT,
is_planned BOOLEAN NOT NULL,
store_id BIGINT,
FOREIGN KEY (money_pool_id) REFERENCES money_pool(id),
FOREIGN KEY (store_id) REFERENCES store(id)
);

-- 商品取引テーブル
CREATE TABLE IF NOT EXISTS item_payment (
payment_id BIGINT NOT NULL,
item_id BIGINT NOT NULL,
quantity BIGINT NOT NULL CHECK (quantity > 0),
PRIMARY KEY (payment_id, item_id),
FOREIGN KEY (payment_id) REFERENCES payment(id),
FOREIGN KEY (item_id) REFERENCES item(id)
);

-- ユーザーグループ所属テーブル
CREATE TABLE IF NOT EXISTS user_group_membership (
group_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
PRIMARY KEY (group_id, user_id),
FOREIGN KEY (group_id) REFERENCES user_groups(id),
FOREIGN KEY (user_id) REFERENCES users(id)
);

-- 限定公開範囲テーブル
CREATE TABLE IF NOT EXISTS restricted_publication_scope (
pool_id BIGINT NOT NULL,
group_id BIGINT NOT NULL,
PRIMARY KEY (pool_id, group_id),
FOREIGN KEY (pool_id) REFERENCES money_pool(id) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (group_id) REFERENCES user_groups(id)
);

-- 制約:限定公開範囲のプールIDに対応するマネープールの公開タイプは限定公開である
ALTER TABLE restricted_publication_scope
ADD CONSTRAINT fk_money_pool_restricted
CHECK ((SELECT type FROM money_pool WHERE id = pool_id) = 'restricted');
124 changes: 73 additions & 51 deletions back/infra/psql/psql.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package psql

import (
"bufio"
"fmt"
"os"
"strings"
"database/sql"

"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
Expand All @@ -15,18 +19,28 @@ const (
type DB struct {
db *sqlx.DB
}

func dbInit() error {
db, err := sqlx.Open("postgres", fmt.Sprintf("host=%v port=%v user=%v password=%v sslmode=%v", config.Config.PostgresHost, config.Config.PostgresPort, config.Config.PostgresAdminUser, config.Config.PostgresAdminPassword, sslmode))
if err != nil {
return fmt.Errorf("failed to open db: %w", err)
}
_, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %v", config.Config.PostgresDb))
if err != nil {
return fmt.Errorf("failed to create db: %w", err)
}

return nil
db, err := sqlx.Open("postgres", fmt.Sprintf("host=%v port=%v user=%v password=%v sslmode=%v", config.Config.PostgresHost, config.Config.PostgresPort, config.Config.PostgresAdminUser, config.Config.PostgresAdminPassword, sslmode))
if err != nil {
return fmt.Errorf("failed to open db: %w", err)
}
defer db.Close()

var dbName string
err = db.Get(&dbName, "SELECT datname FROM pg_database WHERE datname = $1", config.Config.PostgresDb)
if err != nil && err != sql.ErrNoRows {
return fmt.Errorf("error checking for database existence: %w", err)
}

// If the database does not exist, create it
if dbName == "" {
_, err = db.Exec(fmt.Sprintf("CREATE DATABASE %v OWNER %v", config.Config.PostgresDb, config.Config.PostgresUser))
if err != nil {
return fmt.Errorf("failed to create db: %w", err)
}
}

return nil
}

func NewDB() (*DB, error) {
Expand All @@ -35,56 +49,64 @@ func NewDB() (*DB, error) {
return nil, fmt.Errorf("failed to init db: %w", err)
}

db, err := sqlx.Open("postgres", fmt.Sprintf("host=%v port=%v user=%v password=%v dbname=%v sslmode=%v", config.Config.PostgresHost, config.Config.PostgresPort, config.Config.PostgresUser, config.Config.PostgresPassword, config.Config.PostgresDb, sslmode))
db, err := sqlx.Open("postgres", fmt.Sprintf("host=%v port=%v user=%v password=%v dbname=%v sslmode=%v", config.Config.PostgresHost, config.Config.PostgresPort, config.Config.PostgresUser, config.Config.PostgresPassword, config.Config.PostgresDb, sslmode))
if err != nil {
return nil, fmt.Errorf("failed to open db: %w", err)
}

// SQLファイルからテーブルを作成
err = executeSQLFile(db, "/app/infra/psql/init.sql")
if err != nil {
return nil, fmt.Errorf("failed to open db: %w", err)
return nil, err
}

createTables(db)

return &DB{db: db}, nil
}

func createTables(db *sqlx.DB) error {

_, err := db.Exec(`CREATE TABLE IF NOT EXISTS users(id text PRIMARY KEY)`)
if err != nil {
return fmt.Errorf("failed to create table users: %w", err)
}

_, err = db.Exec(`CREATE TABLE IF NOT EXISTS money_pools(id BIGSERIAL PRIMARY KEY, name text NOT NULL, description text, is_world_public boolean NOT NULL DEFAULT false, owner_id BIGINT NOT NULL, version BIGINT NOT NULL DEFAULT 1)`)
if err != nil {
return fmt.Errorf("failed to create table money_pools: %w", err)
}

_, err = db.Exec(`CREATE TABLE IF NOT EXISTS share_users(id BIGSERIAL PRIMARY KEY, money_pool_id BIGINT NOT NULL, user_id BIGINT NOT NULL)`)
if err != nil {
return fmt.Errorf("failed to create table share_users: %w", err)
}

_, err = db.Exec(`CREATE TABLE IF NOT EXISTS money_transactions(id BIGSERIAL PRIMARY KEY, money_pool_id BIGINT NOT NULL, money_transaction_date date NOT NULL, title text NOT NULL, amount float8 NOT NULL, description text, is_expectation boolean NOT NULL DEFAULT false, store_id BIGINT, version BIGINT NOT NULL DEFAULT 1)`)
if err != nil {
return fmt.Errorf("failed to create table money_transactions: %w", err)
}

_, err = db.Exec(`CREATE TABLE IF NOT EXISTS stores(id BIGSERIAL PRIMARY KEY, name text NOT NULL, user_id BIGINT NOT NULL)`)
func executeSQLFile(db *sqlx.DB, filepath string) error {
file, err := os.Open(filepath)
if err != nil {
return fmt.Errorf("failed to create table stores: %w", err)
return fmt.Errorf("failed to open SQL file: %w", err)
}

_, err = db.Exec(`CREATE TABLE IF NOT EXISTS items(id BIGSERIAL PRIMARY KEY, name text NOT NULL, price_per_unit float8 NOT NULL, user_id BIGINT NOT NULL, version BIGINT NOT NULL DEFAULT 1)`)
if err != nil {
return fmt.Errorf("failed to create table items: %w", err)
defer file.Close()

scanner := bufio.NewScanner(file)
var sqlStatement string
var inDOBlock bool

for scanner.Scan() {
line := scanner.Text()
trimmedLine := strings.TrimSpace(line)

// コメントを無視
if strings.HasPrefix(trimmedLine, "--") {
continue
}

// DOブロックの開始を検出
if strings.HasPrefix(trimmedLine, "DO") {
inDOBlock = true
}

// DOブロック内では、END; まで読み込む
if inDOBlock && strings.HasPrefix(trimmedLine, "END;") {
inDOBlock = false
}

sqlStatement += line + "\n" // SQLステートメントを行ごとに追加

// SQLステートメントが終わったかどうか(セミコロンかDOブロックの終わり)
if (!inDOBlock && strings.HasSuffix(trimmedLine, ";")) || (!inDOBlock && strings.HasPrefix(trimmedLine, "END;")) {
_, err = db.Exec(sqlStatement)
if err != nil {
return fmt.Errorf("failed to exec SQL statement: %w", err)
}
sqlStatement = "" // ステートメントをリセット
}
}

_, err = db.Exec(`CREATE TABLE IF NOT EXISTS money_transaction_items(id BIGSERIAL PRIMARY KEY, money_transaction_id BIGINT NOT NULL, item_id BIGINT NOT NULL, amount float8 NOT NULL)`)
if err != nil {
return fmt.Errorf("failed to create table money_transaction_items: %w", err)
}

_, err = db.Exec(`CREATE TABLE IF NOT EXISTS money_provider(id BIGSERIAL PRIMARY KEY, name text NOT NULL, user_id BIGINT NOT NULL, balance float8 NOT NULL, version BIGINT NOT NULL DEFAULT 1)`)
if err != nil {
return fmt.Errorf("failed to create table money_provider: %w", err)
if err := scanner.Err(); err != nil {
return fmt.Errorf("error while reading SQL file: %w", err)
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ services:
POSTGRES_ADMIN_PASSWORD: passwd
POSTGRES_USER: openchokin
POSTGRES_PASSWORD: passwd
POSTGRES_DB: sample-db
POSTGRES_DB: chokindb
POSTGRES_HOST: openchokin-db
POSTGRES_PORT: 5432
volumes:
Expand Down

0 comments on commit a21b801

Please sign in to comment.