Skip to content

Commit

Permalink
DB Migration (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
rusher2004 authored Apr 14, 2024
1 parent de8824a commit 870748c
Show file tree
Hide file tree
Showing 12 changed files with 226 additions and 54 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
dev:
make -j docker-up

dev-stop:
docker compose down

docker-up:
docker compose up -d

Expand Down
6 changes: 5 additions & 1 deletion api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
FROM golang:1.22.2 as build
FROM golang:1.22.2-alpine as build

ARG CGO_ENABLED=0
WORKDIR /app

RUN apk update && apk upgrade && apk add --no-cache ca-certificates
RUN update-ca-certificates

COPY go.mod go.sum ./
RUN go mod download
COPY . .
Expand All @@ -11,5 +14,6 @@ RUN go build -C ./api

FROM scratch
COPY --from=build /app/api/api /api
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

ENTRYPOINT ["/api"]
2 changes: 1 addition & 1 deletion api/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (a *AuthStore) apiOverrides(ogImplementation tpepmodels.APIInterface) tpepm
// here we just let supertokens to its normal thing.
resp, err := ogEPSignUp(formFields, tenantId, options, uc)
if err != nil {
return tpepmodels.SignUpPOSTResponse{}, err
return tpepmodels.SignUpPOSTResponse{}, fmt.Errorf("error calling original email password sign up: %w", err)
}

if resp.OK != nil {
Expand Down
20 changes: 18 additions & 2 deletions api/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,37 @@ package db
import (
"context"
"fmt"
"net/url"

"github.com/jackc/pgx/v5/pgxpool"
_ "github.com/lib/pq"
)

type Client struct {
db *pgxpool.Pool
}

func NewDB(ctx context.Context, connString string) (Client, error) {
p, err := pgxpool.New(ctx, connString)
u, err := url.Parse(connString)
if err != nil {
return Client{}, fmt.Errorf("error parsing db url: %w", err)
}

// explicitly set this because fly.io create another default db
u.Path = "/board"
cfg, err := pgxpool.ParseConfig(u.String())
if err != nil {
return Client{}, fmt.Errorf("error parsing db config: %w", err)
}

p, err := pgxpool.NewWithConfig(ctx, cfg)
if err != nil {
return Client{}, fmt.Errorf("error creating db pool: %w", err)
}

if err := p.Ping(ctx); err != nil {
return Client{}, fmt.Errorf("error pinging db: %w", err)
}

return Client{p}, nil
}

Expand Down
11 changes: 11 additions & 0 deletions bruno/Sac Tech Job Board API/Health.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
meta {
name: Health
type: http
seq: 1
}

get {
url: /health
body: none
auth: none
}
16 changes: 16 additions & 0 deletions db/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Database Migrations

The production db is hosted in a fly.io app, so to run a migration, we must do it locally by creating
a proxy connection to the fly.io Postgres app.

Create the proxy

```sh
fly proxy 5432 -a sac-tech-job-board-db
```

Then, in another terminal window

```sh
go run main.go
```
29 changes: 29 additions & 0 deletions db/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package main

import (
"log"
"os"

"github.com/golang-migrate/migrate/v4"
_ "github.com/golang-migrate/migrate/v4/database/postgres"
_ "github.com/golang-migrate/migrate/v4/source/file"
_ "github.com/joho/godotenv/autoload"
)

func main() {
dbURL, ok := os.LookupEnv("POSTGRES_URL")
if !ok {
log.Fatal("POSTGRES_URL is not set")
}

m, err := migrate.New("file://migrations", dbURL)
if err != nil {
log.Fatalf("error creating migrator: %v\n", err)
}

if err := m.Up(); err != nil {
log.Fatalf("error applying migrations: %v\n", err)
}

log.Println("migrations applied")
}
11 changes: 11 additions & 0 deletions db/migrations/000001_init.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
DROP schema IF EXISTS users CASCADE;

DROP schema IF EXISTS organizations CASCADE;

DROP schema IF EXISTS jobs CASCADE;

DROP TYPE IF EXISTS public.employment_type CASCADE;

DROP TYPE IF EXISTS public.pay_type CASCADE;

DROP FUNCTION IF EXISTS public.updated_timestamp() CASCADE;
119 changes: 73 additions & 46 deletions db/schema.sql → db/migrations/000001_init.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ CREATE SCHEMA IF NOT EXISTS users;

-- user table
CREATE TABLE IF NOT EXISTS users.user (
id SERIAL PRIMARY KEY,
user_id SERIAL PRIMARY KEY,
user_uuid UUID DEFAULT uuid_generate_v4() NOT NULL UNIQUE,
username VARCHAR(255) NOT NULL UNIQUE,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
username VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Expand All @@ -35,10 +35,9 @@ UPDATE ON users.user FOR EACH ROW EXECUTE FUNCTION updated_timestamp();

-- email table
CREATE TABLE IF NOT EXISTS users.email (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users.user(id) NOT NULL,
email_id SERIAL PRIMARY KEY,
user_id INT REFERENCES users.user(user_id) NOT NULL,
address VARCHAR(255) NOT NULL UNIQUE,
primary_address BOOLEAN NOT NULL DEFAULT FALSE,
verified BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
Expand All @@ -48,76 +47,74 @@ CREATE OR REPLACE TRIGGER users_email_updated_trigger BEFORE
UPDATE ON users.email FOR EACH ROW EXECUTE FUNCTION updated_timestamp();

/*
companies scema
organizations scema
*/
CREATE SCHEMA IF NOT EXISTS companies;
CREATE SCHEMA IF NOT EXISTS organizations;

-- company table
CREATE TABLE IF NOT EXISTS companies.company (
id SERIAL PRIMARY KEY,
company_uuid UUID DEFAULT uuid_generate_v4() NOT NULL UNIQUE,
-- organization table
CREATE TABLE IF NOT EXISTS organizations.organization (
organization_id SERIAL PRIMARY KEY,
organization_uuid UUID DEFAULT uuid_generate_v4() NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE OR REPLACE TRIGGER companies_company_updated_trigger BEFORE
UPDATE ON companies.company FOR EACH ROW EXECUTE FUNCTION updated_timestamp();
CREATE OR REPLACE TRIGGER organizations_organization_updated_trigger BEFORE
UPDATE ON organizations.organization FOR EACH ROW EXECUTE FUNCTION updated_timestamp();

-- representative table
CREATE TABLE IF NOT EXISTS companies.representative (
id SERIAL PRIMARY KEY,
CREATE TABLE IF NOT EXISTS organizations.representative (
representative_id SERIAL PRIMARY KEY,
representative_uuid UUID DEFAULT uuid_generate_v4() NOT NULL UNIQUE,
company_id INT REFERENCES companies.company(id) NOT NULL,
user_uuid UUID REFERENCES users.user(user_uuid) NOT NULL,
organization_id INT REFERENCES organizations.organization(organization_id) NOT NULL,
user_id INT REFERENCES users.user(user_id) NOT NULL,
active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE OR REPLACE TRIGGER companies_representative_updated_trigger BEFORE
UPDATE ON companies.representative FOR EACH ROW EXECUTE FUNCTION updated_timestamp();
CREATE OR REPLACE TRIGGER organizations_representative_updated_trigger BEFORE
UPDATE ON organizations.representative FOR EACH ROW EXECUTE FUNCTION updated_timestamp();

ALTER TABLE companies.company
ADD COLUMN IF NOT EXISTS created_by INT REFERENCES companies.representative(id) NOT NULL,
ADD COLUMN IF NOT EXISTS owned_by INT REFERENCES companies.representative(id) NOT NULL;
ALTER TABLE organizations.organization
ADD COLUMN IF NOT EXISTS created_by INT REFERENCES organizations.representative(representative_id) NOT NULL,
ADD COLUMN IF NOT EXISTS owned_by INT REFERENCES organizations.representative(representative_id) NOT NULL;

-- email table
CREATE TABLE IF NOT EXISTS companies.email (
id SERIAL PRIMARY KEY,
CREATE TABLE IF NOT EXISTS organizations.email (
email_id SERIAL PRIMARY KEY,
email_uuid UUID DEFAULT uuid_generate_v4() NOT NULL UNIQUE,
representative_id INT REFERENCES companies.representative(id) NOT NULL,
representative_id INT REFERENCES organizations.representative(representative_id) NOT NULL,
address VARCHAR(255) NOT NULL UNIQUE,
primary_address BOOLEAN NOT NULL DEFAULT FALSE,
verified BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE OR REPLACE TRIGGER companies_email_updated_trigger BEFORE
UPDATE ON companies.email FOR EACH ROW EXECUTE FUNCTION updated_timestamp();
CREATE OR REPLACE TRIGGER organizations_email_updated_trigger BEFORE
UPDATE ON organizations.email FOR EACH ROW EXECUTE FUNCTION updated_timestamp();

-- profile table
CREATE TABLE IF NOT EXISTS companies.profile (
id SERIAL PRIMARY KEY,
profile_uuid UUID DEFAULT uuid_generate_v4() NOT NULL UNIQUE,
company_uuid UUID REFERENCES companies.company(company_uuid) NOT NULL,
CREATE TABLE IF NOT EXISTS organizations.profile (
profile_id SERIAL PRIMARY KEY,
organization_id INT REFERENCES organizations.organization(organization_id) NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
website_url VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE OR REPLACE TRIGGER companies_profile_updated_trigger BEFORE
UPDATE ON companies.profile FOR EACH ROW EXECUTE FUNCTION updated_timestamp();
CREATE OR REPLACE TRIGGER organizations_profile_updated_trigger BEFORE
UPDATE ON organizations.profile FOR EACH ROW EXECUTE FUNCTION updated_timestamp();

-- permissions table
CREATE TABLE IF NOT EXISTS companies.permissions (
id SERIAL PRIMARY KEY,
permission_uuid UUID DEFAULT uuid_generate_v4() NOT NULL UNIQUE,
company_uuid UUID REFERENCES companies.company(company_uuid) NOT NULL,
user_uuid UUID REFERENCES users.user(user_uuid) NOT NULL,
CREATE TABLE IF NOT EXISTS organizations.permissions (
permissions_id SERIAL PRIMARY KEY,
organization_id INT REFERENCES organizations.organization(organization_id) NOT NULL,
user_id INT REFERENCES users.user(user_id) NOT NULL,
update_profile BOOLEAN NOT NULL DEFAULT FALSE,
create_job BOOLEAN NOT NULL DEFAULT FALSE,
post_job BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
Expand All @@ -128,13 +125,45 @@ CREATE TABLE IF NOT EXISTS companies.permissions (
*/
CREATE SCHEMA IF NOT EXISTS jobs;

-- enums
CREATE TYPE employment_type AS ENUM (
'full-time',
'part-time',
'contract',
'temporary',
'internship',
'volunteer',
'per-diem',
'other'
);

CREATE TYPE pay_type AS ENUM (
'hourly',
'salary',
'commission',
'other'
);

-- job table
CREATE TABLE IF NOT EXISTS jobs.job (
id SERIAL PRIMARY KEY,
job_id SERIAL PRIMARY KEY,
job_uuid UUID DEFAULT uuid_generate_v4() NOT NULL UNIQUE,
company_id INT REFERENCES companies.company(id) NOT NULL,
organization_id INT REFERENCES organizations.organization(organization_id) NOT NULL,
title VARCHAR(255) NOT NULL,
description TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE OR REPLACE TRIGGER jobs_job_updated_trigger BEFORE
UPDATE ON jobs.job FOR EACH ROW EXECUTE FUNCTION updated_timestamp();

CREATE TABLE IF NOT EXISTS jobs.job_posting (
job_posting_id SERIAL PRIMARY KEY,
job_id INT REFERENCES jobs.job(job_id) NOT NULL,
employment_type employment_type [] NOT NULL CHECK (employment_type <> '{}'::employment_type []),
pay_rate NUMERIC(10, 2) CHECK (pay_rate >= 0) NOT NULL DEFAULT 0,
pay_type pay_type NOT NULL,
publish_start_date TIMESTAMP NOT NULL,
publish_end_date TIMESTAMP NOT NULL,
publish_override BOOLEAN NOT NULL DEFAULT FALSE,
Expand All @@ -143,16 +172,14 @@ CREATE TABLE IF NOT EXISTS jobs.job (
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE OR REPLACE TRIGGER jobs_job_updated_trigger BEFORE
UPDATE ON jobs.job FOR EACH ROW EXECUTE FUNCTION updated_timestamp();

-- permissions table
CREATE TABLE IF NOT EXISTS jobs.job_permissions (
id SERIAL PRIMARY KEY,
job_id INT REFERENCES jobs.job(id) NOT NULL UNIQUE,
user_id INT REFERENCES users.user(id) NOT NULL,
job_id INT REFERENCES jobs.job(job_id) NOT NULL UNIQUE,
user_id INT REFERENCES users.user(user_id) NOT NULL,
update_job BOOLEAN NOT NULL DEFAULT FALSE,
delete_job BOOLEAN NOT NULL DEFAULT FALSE,
post_job BOOLEAN NOT NULL DEFAULT FALSE,
publish BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
Expand Down
9 changes: 7 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ go 1.22.2
require (
github.com/go-chi/chi/v5 v5.0.12
github.com/go-chi/cors v1.2.1
github.com/golang-migrate/migrate/v4 v4.17.0
github.com/google/uuid v1.6.0
github.com/jackc/pgx/v5 v5.5.5
github.com/joho/godotenv v1.5.1
github.com/lib/pq v1.10.9
github.com/supertokens/supertokens-golang v0.17.5
)

Expand All @@ -18,21 +18,26 @@ require (
github.com/derekstavis/go-qs v0.0.0-20180720192143-9eef69e6c4e7 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/nyaruka/phonenumbers v1.0.73 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/twilio/twilio-go v0.26.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/h2non/gock.v1 v1.1.2 // indirect
Expand Down
Loading

0 comments on commit 870748c

Please sign in to comment.