Skip to content

Commit e42fadc

Browse files
committed
use postgres and different schema migrator
1 parent 7a1ccd4 commit e42fadc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+7384
-7230
lines changed

.bundle/config

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
BUNDLE_PATH: "bundle"

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.env
22
bin
33
!bin/README.md
4+
bundle

Gemfile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# frozen_string_literal: true
2+
3+
# gems's source
4+
source 'http://rubygems.org/'
5+
6+
gem 'dotenv'
7+
gem 'standalone_migrations'
8+
gem 'postgresql'
9+
10+
## uncomment if using mysql with lhm
11+
# gem 'mysql2'
12+
# gem 'lhm'

Gemfile.lock

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
GEM
2+
remote: http://rubygems.org/
3+
specs:
4+
actionpack (6.0.3.2)
5+
actionview (= 6.0.3.2)
6+
activesupport (= 6.0.3.2)
7+
rack (~> 2.0, >= 2.0.8)
8+
rack-test (>= 0.6.3)
9+
rails-dom-testing (~> 2.0)
10+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
11+
actionview (6.0.3.2)
12+
activesupport (= 6.0.3.2)
13+
builder (~> 3.1)
14+
erubi (~> 1.4)
15+
rails-dom-testing (~> 2.0)
16+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
17+
activemodel (6.0.3.2)
18+
activesupport (= 6.0.3.2)
19+
activerecord (6.0.3.2)
20+
activemodel (= 6.0.3.2)
21+
activesupport (= 6.0.3.2)
22+
activesupport (6.0.3.2)
23+
concurrent-ruby (~> 1.0, >= 1.0.2)
24+
i18n (>= 0.7, < 2)
25+
minitest (~> 5.1)
26+
tzinfo (~> 1.1)
27+
zeitwerk (~> 2.2, >= 2.2.2)
28+
builder (3.2.4)
29+
concurrent-ruby (1.1.6)
30+
crass (1.0.6)
31+
dotenv (2.7.5)
32+
erubi (1.9.0)
33+
i18n (1.8.3)
34+
concurrent-ruby (~> 1.0)
35+
loofah (2.6.0)
36+
crass (~> 1.0.2)
37+
nokogiri (>= 1.5.9)
38+
method_source (1.0.0)
39+
mini_portile2 (2.4.0)
40+
minitest (5.14.1)
41+
nokogiri (1.10.9)
42+
mini_portile2 (~> 2.4.0)
43+
pg (1.2.3)
44+
postgresql (1.0.0)
45+
pg
46+
rack (2.2.3)
47+
rack-test (1.1.0)
48+
rack (>= 1.0, < 3)
49+
rails-dom-testing (2.0.3)
50+
activesupport (>= 4.2.0)
51+
nokogiri (>= 1.6)
52+
rails-html-sanitizer (1.3.0)
53+
loofah (~> 2.3)
54+
railties (6.0.3.2)
55+
actionpack (= 6.0.3.2)
56+
activesupport (= 6.0.3.2)
57+
method_source
58+
rake (>= 0.8.7)
59+
thor (>= 0.20.3, < 2.0)
60+
rake (13.0.1)
61+
standalone_migrations (6.0.0)
62+
activerecord (>= 4.2.7, < 6.1.0, != 5.2.3.rc1, != 5.2.3)
63+
railties (>= 4.2.7, < 6.1.0, != 5.2.3.rc1, != 5.2.3)
64+
rake (>= 10.0)
65+
thor (1.0.1)
66+
thread_safe (0.3.6)
67+
tzinfo (1.2.7)
68+
thread_safe (~> 0.1)
69+
zeitwerk (2.3.0)
70+
71+
PLATFORMS
72+
ruby
73+
74+
DEPENDENCIES
75+
dotenv
76+
postgresql
77+
standalone_migrations
78+
79+
BUNDLED WITH
80+
1.17.2

Makefile

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
all: build start
2-
dep:
3-
go get github.com/Fs02/kamimai
4-
migrate:
5-
export $$(cat .env | grep -v ^\# | xargs) && \
6-
kamimai --driver=mysql --dsn="mysql://$$MYSQL_USERNAME:$$MYSQL_PASSWORD@($$MYSQL_HOST:$$MYSQL_PORT)/$$MYSQL_DATABASE" --directory=./db/migrations sync
7-
rollback:
8-
export $$(cat .env | grep -v ^\# | xargs) && \
9-
kamimai --driver=mysql --dsn="mysql://$$MYSQL_USERNAME:$$MYSQL_PASSWORD@($$MYSQL_HOST:$$MYSQL_PORT)/$$MYSQL_DATABASE" --directory=./db/migrations down
2+
bundle:
3+
bundle install --path bundle
4+
db-create: bundle
5+
bundle exec rake db:create
6+
db-migrate: bundle
7+
bundle exec rake db:migrate
8+
db-rollback: bundle
9+
bundle exec rake db:rollback
1010
gen:
1111
go generate ./...
1212
build: gen

README.md

+20-15
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,28 @@ Go Todo Backend Example Using Modular Project Layout for Product Microservice. I
44

55
This example uses [Chi](https://github.com/go-chi/chi) for http router and [REL](https://github.com/Fs02/rel) for database access.
66

7-
## Install
7+
## Installation
88

9-
```
10-
# Prepare .env
11-
cp .env.sample .env
9+
### Prerequisite
1210

13-
# Update dependencies
14-
make dep
11+
1. Install [migrate](https://github.com/golang-migrate/migrate/tree/master/cmd/migrate) for database migration.
12+
2. Install [mockery](https://github.com/vektra/mockery#installation) for interface mock generation.
1513

16-
# Migrate
17-
make migrate
14+
### Running
1815

19-
# Build and Running
20-
make
21-
```
16+
1. Prepare `.env`.
17+
```
18+
cp .env.sample .env
19+
```
20+
2. Create a database and update `.env`.
21+
2. Prepare database schema.
22+
```
23+
make migrate
24+
```
25+
3. Build and Running
26+
```
27+
make
28+
```
2229
2330
## Project Structure
2431
@@ -66,11 +73,9 @@ make
6673
6774
This project structure is based on a modular project structure, with loosely coupled dependencies between domain, Think of making libraries under a single repo that only exports certain functionality that used by other service and http handler. One of domain that present in this example is todos.
6875
69-
Loosely coupled dependency between domain is enforced by avoiding the use of shared entity package, therefore any entity struct should be included inside it's own respective domain. This will prevent cyclic dependency between entity.
70-
71-
In most cases, there shouldn't be a problem with this approach, as the case when you need cyclic dependency is mostly when the entity is belongs to the same domain.
76+
Loosely coupled dependency between domain is enforced by avoiding the use of shared entity package, therefore any entity struct should be included inside it's own respective domain. This will prevent cyclic dependency between entity. This shouldn't be a problem in most cases, becasause if you encounter cyclic dependency, there's huge chance that the entity should belongs to the same domain.
7277
73-
For example, consider three structs: user, transaction and transaction items: transaction and it's transaction items might need cyclic dependency and it doesn't works standalone, thus it should be on the same domain.
78+
For example, consider three structs: user, transaction and transaction items. transaction and its transaction items might need cyclic dependency and items doesn't works standalone (items without transaction should not exists), thus it should be on the same domain.
7479
In the other hand, user and transaction shouldn't require cyclic dependency, transaction might have a user field in the struct, but user shouldn't have a slice of transaction field, therefore it should be on a separate domain.
7580
7681
### Domain vs Client

Rakefile

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env rake
2+
3+
require 'yaml'
4+
require 'dotenv'
5+
require 'standalone_migrations'
6+
7+
Dotenv.load
8+
9+
# rake task for database migrations
10+
StandaloneMigrations::Tasks.load_tasks
11+
12+
## uncomment if using mysql with lhm
13+
# require 'lhm'
14+
# # ignore LHM (lhma and lhmn)
15+
# ActiveRecord::SchemaDumper.ignore_tables << /^lhma_/
16+
# ActiveRecord::SchemaDumper.ignore_tables << /^lhmn_/
17+
18+
# namespace :lhm do
19+
# desc "LHM Clean Up"
20+
# task cleanup: :environment do
21+
# Lhm.cleanup(:run)
22+
# end
23+
# end

cmd/api/main.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import (
1212

1313
"github.com/Fs02/go-todo-backend/api"
1414
"github.com/Fs02/rel"
15-
"github.com/Fs02/rel/adapter/mysql"
16-
_ "github.com/go-sql-driver/mysql" // TODO: use postgres
15+
"github.com/Fs02/rel/adapter/postgres"
16+
_ "github.com/lib/pq"
1717
"go.uber.org/zap"
1818
)
1919

@@ -48,15 +48,15 @@ func main() {
4848
func initRepository() rel.Repository {
4949
var (
5050
logger, _ = zap.NewProduction(zap.Fields(zap.String("type", "repository")))
51-
dsn = fmt.Sprintf("%s:%s@(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local",
52-
os.Getenv("MYSQL_USERNAME"),
53-
os.Getenv("MYSQL_PASSWORD"),
54-
os.Getenv("MYSQL_HOST"),
55-
os.Getenv("MYSQL_PORT"),
56-
os.Getenv("MYSQL_DATABASE"))
51+
dsn = fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable",
52+
os.Getenv("POSTGRESQL_USERNAME"),
53+
os.Getenv("POSTGRESQL_PASSWORD"),
54+
os.Getenv("POSTGRESQL_HOST"),
55+
os.Getenv("POSTGRESQL_PORT"),
56+
os.Getenv("POSTGRESQL_DATABASE"))
5757
)
5858

59-
adapter, err := mysql.Open(dsn)
59+
adapter, err := postgres.Open(dsn)
6060
if err != nil {
6161
logger.Fatal(err.Error(), zap.Error(err))
6262
}

db/README.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# db
2+
3+
Contains file required for building db schema. `schema.rb` is useful when your project already running for a long time and running migration file one by one takes a lot of time, which then you can just load the schema directly which is faster.
4+
5+
The reason I'm using ruby based solution is because there's no golang based solution that can generate schema and allows working on multiple branch with different not yet merged migration without having to rollback and migrate when switching branch.

db/config.yml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
default: &default
2+
adapter: postgresql
3+
reconnect: true
4+
encoding: utf8
5+
username: <%= ENV['POSTGRESQL_USERNAME'] %>
6+
password: <%= ENV['POSTGRESQL_PASSWORD'] %>
7+
host: <%= ENV['POSTGRESQL_HOST'] || '127.0.0.1' %>
8+
port: <%= ENV['POSTGRESQL_PORT'] %>
9+
10+
development:
11+
<<: *default
12+
database: <%= ENV['POSTGRESQL_DATABASE'] %>
13+
14+
test: &test
15+
<<: *default
16+
database: <%= ENV['POSTGRESQL_DATABASE_TEST'] %>
17+
18+
production:
19+
<<: *default
20+
database: <%= ENV['POSTGRESQL_DATABASE'] %>
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class CreateTodos < ActiveRecord::Migration[5.2]
2+
def change
3+
create_table :todos do |t|
4+
t.datetime :created_at
5+
t.datetime :updated_at
6+
t.string :title
7+
t.boolean :completed
8+
t.integer :order
9+
10+
t.index :order
11+
end
12+
end
13+
end

db/migrations/20180601143300_create_todos_down.sql

-1
This file was deleted.

db/migrations/20180601143300_create_todos_up.sql

-11
This file was deleted.

db/schema.rb

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# This file is auto-generated from the current state of the database. Instead
2+
# of editing this file, please use the migrations feature of Active Record to
3+
# incrementally modify your database, and then regenerate this schema definition.
4+
#
5+
# This file is the source Rails uses to define your schema when running `rails
6+
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
7+
# be faster and is potentially less error prone than running all of your
8+
# migrations from scratch. Old migrations may fail to apply correctly if those
9+
# migrations use external dependencies or application code.
10+
#
11+
# It's strongly recommended that you check this file into your version control system.
12+
13+
ActiveRecord::Schema.define(version: 2020_28_06_225100) do
14+
15+
# These are extensions that must be enabled in order to support this database
16+
enable_extension "plpgsql"
17+
18+
create_table "todos", force: :cascade do |t|
19+
t.datetime "created_at"
20+
t.datetime "updated_at"
21+
t.string "title"
22+
t.boolean "completed"
23+
t.integer "order"
24+
t.index ["order"], name: "index_todos_on_order"
25+
end
26+
27+
end

go.mod

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@ require (
66
github.com/Fs02/rel v0.5.0
77
github.com/azer/snakecase v1.0.0 // indirect
88
github.com/go-chi/chi v3.3.2+incompatible
9-
github.com/go-sql-driver/mysql v1.4.1
109
github.com/goware/cors v1.1.1
11-
github.com/mattn/go-sqlite3 v1.10.0 // indirect
10+
github.com/lib/pq v1.7.0
1211
github.com/stretchr/testify v1.4.0
1312
go.uber.org/zap v1.15.0
1413
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
1514
golang.org/x/mod v0.3.0 // indirect
1615
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 // indirect
16+
golang.org/x/text v0.3.2 // indirect
1717
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2 // indirect
18-
google.golang.org/appengine v1.6.6 // indirect
1918
honnef.co/go/tools v0.0.1-2020.1.4 // indirect
2019
)

go.sum

+4-8
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ github.com/go-chi/chi v3.3.2+incompatible h1:uQNcQN3NsV1j4ANsPh42P4ew4t6rnRbJb8f
1515
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
1616
github.com/go-sql-driver/mysql v1.3.0 h1:pgwjLi/dvffoP9aabwkT3AKpXQM93QARkjFhDDqC1UE=
1717
github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
18-
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
19-
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
20-
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
2118
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
2219
github.com/goware/cors v1.1.1 h1:70q2dL4qV2Gl5ZlPCH8VO2ZsANEcidqbpb6Pru6qKzs=
2320
github.com/goware/cors v1.1.1/go.mod h1:b14AZ0Wsjv3gNG3fr/TTDexvbEJyWljkGLKLVpe4vns=
@@ -29,10 +26,12 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
2926
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
3027
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
3128
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
29+
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
3230
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
31+
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
32+
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
33+
github.com/mattn/go-sqlite3 v1.6.0 h1:TDwTWbeII+88Qy55nWlof0DclgAtI4LqGujkYMzmQII=
3334
github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
34-
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
35-
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
3635
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
3736
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
3837
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -66,7 +65,6 @@ golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
6665
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
6766
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
6867
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
69-
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
7068
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
7169
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
7270
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
@@ -93,8 +91,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
9391
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
9492
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
9593
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
96-
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
97-
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
9894
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
9995
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
10096
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

vendor/README.md

-5
This file was deleted.

0 commit comments

Comments
 (0)