Skip to content

Commit 2d4e9bb

Browse files
feat: implementing the database for tinyurls (#7)
* feat: schema design with mermaid * feat: setting up postgres connection, schema and migrations * fix: set fetch-depth and use checkout@v4
1 parent e78c9f0 commit 2d4e9bb

File tree

11 files changed

+364
-29
lines changed

11 files changed

+364
-29
lines changed

.github/workflows/makefile.yml

+15-3
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,28 @@ jobs:
1212
runs-on: ubuntu-latest
1313

1414
steps:
15-
- uses: actions/checkout@v3
15+
- uses: actions/checkout@v4
16+
with:
17+
fetch-depth: 0
1618
- uses: actions/setup-go@v4
1719
with:
1820
go-version: '^1.21.3' # The Go version to download (if necessary) and use.
1921

2022
- name: Run OAPI-Generate
2123
run: make gen
2224

23-
- name: Run Lint
24-
run: make lint
25+
- name: Run Lint Go
26+
run: make lint-go
27+
28+
- name: Find modified migrations
29+
run: |
30+
modified_migrations=$(git diff --name-only origin/$GITHUB_BASE_REF...origin/$GITHUB_HEAD_REF 'migrations/*.sql')
31+
echo "$modified_migrations"
32+
echo "::set-output name=file_names::$modified_migrations"
33+
id: modified-migrations
34+
- uses: sbdchd/squawk-action@v1
35+
with:
36+
pattern: ${{ steps.modified-migrations.outputs.file_names }}
2537

2638
- name: Run Format
2739
run: make fmt

Makefile

+21
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ ifeq (, $(shell which goimports))
2222
go install -v golang.org/x/tools/cmd/goimports@v$(GO_IMPORTS_VERSION)
2323
endif
2424

25+
_install-squawk-cli:
26+
ifeq (, $(shell which squawk))
27+
npm install -g [email protected]
28+
endif
29+
30+
2531
all: gen fmt lint build
2632

2733
ru: run-up
@@ -43,6 +49,11 @@ run-down-volumes:
4349
docker compose -f devenv/docker-compose.yaml down --volumes
4450
rm -rf tmp/*
4551

52+
docker-prune:
53+
$(info Running docker-prune...)
54+
docker system prune -a --force
55+
docker builder prune -a --force
56+
4657
psql:
4758
$(info Running exec into postgres...)
4859
docker exec -it devenv-postgres-1 psql -d tiny -U postgres
@@ -70,9 +81,19 @@ fmt:
7081

7182
lint:
7283
$(info Running lint...)
84+
@$(MAKE) lint-go
85+
@$(MAKE) lint-sql
86+
87+
lint-go:
88+
$(info Running lint-go...)
7389
@$(MAKE) --quiet _install-golangci-lint
7490
time $(GO_LINT_BIN) run ./...
7591

92+
lint-sql:
93+
$(info Running lint-sql...)
94+
@$(MAKE) --quiet _install-squawk-cli
95+
time squawk internal/tiny/db/migrations/*
96+
7697
gen:
7798
@$(MAKE) generate
7899

cmd/tiny/main.go

+63-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,71 @@
11
package main
22

33
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
"os"
8+
"os/signal"
9+
"syscall"
10+
"time"
11+
12+
"github.com/spf13/cobra"
413
"sanathk.com/tinyurl/internal/tiny"
14+
"sanathk.com/tinyurl/internal/tiny/db"
15+
"sanathk.com/tinyurl/pkg/postgres"
516
)
617

718
func main() {
8-
tiny.Hello()
19+
if err := cmd(); err != nil {
20+
os.Exit(1)
21+
}
22+
}
23+
24+
func cmd() error {
25+
rootCmd := &cobra.Command{
26+
Use: "tiny",
27+
Short: "TinyURL Service",
28+
RunE: func(cmd *cobra.Command, args []string) error {
29+
return run()
30+
},
31+
}
32+
return rootCmd.Execute()
33+
}
34+
35+
func run() error {
36+
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
37+
defer cancel()
38+
39+
// TODO: remove hardcoded url, get from env vars and into a config
40+
rawURL := "postgres://postgres:admin@postgres:5432/tiny"
41+
pgURL, err := url.Parse(rawURL)
42+
if err != nil {
43+
return err
44+
}
45+
46+
pg, err := postgres.NewPostgres(ctx, pgURL)
47+
if err != nil {
48+
return fmt.Errorf("creating postgres: %w", err)
49+
}
50+
51+
err = pg.Migrate(db.Migrations, db.MigrationsPath)
52+
if err != nil {
53+
return err
54+
}
55+
56+
svc, err := tiny.NewService(ctx, pg)
57+
if err != nil {
58+
return err
59+
}
60+
61+
ticker := time.NewTicker(10 * time.Second)
62+
for {
63+
select {
64+
case <-ticker.C:
65+
svc.Hello()
66+
case <-time.After(5 * time.Minute):
67+
ticker.Stop()
68+
return nil
69+
}
70+
}
971
}

devenv/docker-compose.yaml

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
services:
22
tiny:
33
working_dir: /app
4-
image: devenv-tiny
5-
build:
6-
context: ./..
7-
dockerfile: ./packaging/services/tiny/Dockerfile
4+
image: tiny
85
volumes:
96
- ../:/app
7+
depends_on:
8+
postgres:
9+
condition: service_healthy
1010
postgres:
1111
image: postgres:16.1
12+
healthcheck:
13+
test: ["CMD-SHELL", "pg_isready", "-d", "tiny"]
14+
interval: 5s
15+
# timeout for each health check request, should be lower than interval
16+
timeout: 2s
17+
retries: 5
18+
start_period: 10s
1219
volumes:
1320
- postgres-persisted:/var/lib/postgresql/data
1421
environment:
22+
POSTGRES_USER: postgres
1523
POSTGRES_PASSWORD: admin
1624
POSTGRES_DB: tiny
1725
ports:

docs/design.md

+47-18
Original file line numberDiff line numberDiff line change
@@ -86,28 +86,57 @@ TBD: Use OpenAPI Schema definition if possible?
8686
* Methods: POST
8787
* Encoding: JSON
8888

89-
Request Data:
89+
**Request Body**
90+
91+
TinyURLRequest:
92+
type: object
93+
required:
94+
- original
95+
properties:
96+
original:
97+
type: string
98+
example: "https://www.sanathk.com/some/random/page?with=queryparams"
99+
expiry:
100+
type: string
101+
format: date
102+
example: "2025-01-01"
103+
104+
**Response**
105+
106+
TinyURLResponse:
107+
type: object
108+
required:
109+
- original
110+
- tinyurl
111+
- expiry
112+
properties:
113+
original:
114+
type: string
115+
example: "https://www.sanathk.com/some/random/page?with=queryparams"
116+
tinyurl:
117+
type: string
118+
example: "https://tinyurl.sanath.com/randHash"
119+
expiry:
120+
type: string
121+
format: date
122+
example: "2025-01-01"
90123

91-
request:
92-
object: generateURLRequest
93-
94-
generateURLRequest:
95-
required:
96-
url: string
97-
optional:
98-
expiry: date
124+
### Persistence
125+
The TinyURL data will be persisted in the `postgres` datastore for long-term storage. A table schema design will be added here for reference.
126+
The go application will interact with the database using `pgx` and `sqlc`, the reasons behind choosing this combination is eloquently written [here](https://brandur.org/sqlc) and [here](https://jbrandhorst.com/post/postgres/).
99127

100-
response:
101-
object: generateURLResponse
128+
**Database Schema**
102129

103-
generateURLResponse:
104-
required:
105-
url: string
106-
short: string
107-
expiry: date
130+
The datastore will keep a mapping of original URLs to their hashed URLs with their expirations.
108131

109-
### Persistence
110-
The TinyURL data will be persisted in the `postgres` datastore for long-term storage. A table schema design will be added here for reference.
132+
```mermaid
133+
erDiagram
134+
tinyurls {
135+
original varchar
136+
hash varchar(PK)
137+
expiry date
138+
}
139+
```
111140

112141
We will use various caching strategies to provide low latency environment, and, details around the same will be provided here as well.
113142

go.mod

+14
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,40 @@ go 1.21.3
44

55
require (
66
github.com/getkin/kin-openapi v0.122.0
7+
github.com/golang-migrate/migrate/v4 v4.17.0
8+
github.com/jackc/pgx/v5 v5.5.1
79
github.com/labstack/echo/v4 v4.11.4
810
github.com/oapi-codegen/runtime v1.1.1
11+
github.com/spf13/cobra v1.8.0
912
)
1013

1114
require (
1215
github.com/go-openapi/jsonpointer v0.19.6 // indirect
1316
github.com/go-openapi/swag v0.22.4 // indirect
1417
github.com/google/uuid v1.5.0 // indirect
18+
github.com/hashicorp/errwrap v1.1.0 // indirect
19+
github.com/hashicorp/go-multierror v1.1.1 // indirect
20+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
1521
github.com/invopop/yaml v0.2.0 // indirect
22+
github.com/jackc/pgpassfile v1.0.0 // indirect
23+
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
24+
github.com/jackc/puddle/v2 v2.2.1 // indirect
1625
github.com/josharian/intern v1.0.0 // indirect
1726
github.com/labstack/gommon v0.4.2 // indirect
27+
github.com/lib/pq v1.10.9 // indirect
1828
github.com/mailru/easyjson v0.7.7 // indirect
1929
github.com/mattn/go-colorable v0.1.13 // indirect
2030
github.com/mattn/go-isatty v0.0.20 // indirect
2131
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
2232
github.com/perimeterx/marshmallow v1.1.5 // indirect
33+
github.com/rogpeppe/go-internal v1.12.0 // indirect
34+
github.com/spf13/pflag v1.0.5 // indirect
2335
github.com/valyala/bytebufferpool v1.0.0 // indirect
2436
github.com/valyala/fasttemplate v1.2.2 // indirect
37+
go.uber.org/atomic v1.7.0 // indirect
2538
golang.org/x/crypto v0.17.0 // indirect
2639
golang.org/x/net v0.19.0 // indirect
40+
golang.org/x/sync v0.5.0 // indirect
2741
golang.org/x/sys v0.15.0 // indirect
2842
golang.org/x/text v0.14.0 // indirect
2943
gopkg.in/yaml.v3 v3.0.1 // indirect

0 commit comments

Comments
 (0)