Skip to content

Commit 9bff9bf

Browse files
committed
wip(api,cli): first entity
1 parent 8d68a22 commit 9bff9bf

File tree

17 files changed

+455
-30
lines changed

17 files changed

+455
-30
lines changed

api/go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ require (
2020
github.com/spf13/cobra v1.9.1
2121
github.com/square/mongo-lock v0.0.0-20230808145049-cfcf499f6bf0
2222
github.com/stretchr/testify v1.10.0
23+
github.com/testcontainers/testcontainers-go v0.35.0
2324
github.com/testcontainers/testcontainers-go/modules/mongodb v0.35.0
25+
github.com/testcontainers/testcontainers-go/modules/postgres v0.35.0
2426
github.com/uptrace/bun v1.2.11
27+
github.com/uptrace/bun/dbfixture v1.2.11
2528
github.com/uptrace/bun/dialect/pgdialect v1.2.11
2629
github.com/xakep666/mongo-migrate v0.3.2
2730
go.mongodb.org/mongo-driver v1.17.3
@@ -112,7 +115,6 @@ require (
112115
github.com/spf13/cast v1.3.1 // indirect
113116
github.com/spf13/pflag v1.0.6 // indirect
114117
github.com/stretchr/objx v0.5.2 // indirect
115-
github.com/testcontainers/testcontainers-go v0.35.0 // indirect
116118
github.com/therootcompany/xz v1.0.1 // indirect
117119
github.com/tklauser/go-sysconf v0.3.13 // indirect
118120
github.com/tklauser/numcpus v0.7.0 // indirect

api/go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
246246
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
247247
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
248248
github.com/mattn/goveralls v0.0.9/go.mod h1:FRbM1PS8oVsOe9JtdzAAXM+DsvDMMHcM1C7drGJD8HY=
249+
github.com/mdelapenya/tlscert v0.1.0 h1:YTpF579PYUX475eOL+6zyEO3ngLTOUWck78NBuJVXaM=
250+
github.com/mdelapenya/tlscert v0.1.0/go.mod h1:wrbyM/DwbFCeCeqdPX/8c6hNOqQgbf0rUDErE1uD+64=
249251
github.com/mholt/archiver/v4 v4.0.0-alpha.8 h1:tRGQuDVPh66WCOelqe6LIGh0gwmfwxUrSSDunscGsRM=
250252
github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60VhnHxb2X3T1teMyv5A=
251253
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
@@ -361,6 +363,8 @@ github.com/testcontainers/testcontainers-go v0.35.0 h1:uADsZpTKFAtp8SLK+hMwSaa+X
361363
github.com/testcontainers/testcontainers-go v0.35.0/go.mod h1:oEVBj5zrfJTrgjwONs1SsRbnBtH9OKl+IGl3UMcr2B4=
362364
github.com/testcontainers/testcontainers-go/modules/mongodb v0.35.0 h1:i1Kh9fmXgHG9z3uzJv5Arz7pDKVaaNpLrqyd+0xhYMA=
363365
github.com/testcontainers/testcontainers-go/modules/mongodb v0.35.0/go.mod h1:SD8nVMK1m7b/K2YJqYjYNzfHmZfqHtqNOlI44nfxjdg=
366+
github.com/testcontainers/testcontainers-go/modules/postgres v0.35.0 h1:eEGx9kYzZb2cNhRbBrNOCL/YPOM7+RMJiy3bB+ie0/I=
367+
github.com/testcontainers/testcontainers-go/modules/postgres v0.35.0/go.mod h1:hfH71Mia/WWLBgMD2YctYcMlfsbnT0hflweL1dy8Q4s=
364368
github.com/testcontainers/testcontainers-go/modules/redis v0.32.0 h1:HW5Qo9qfLi5iwfS7cbXwG6qe8ybXGePcgGPEmVlVDlo=
365369
github.com/testcontainers/testcontainers-go/modules/redis v0.32.0/go.mod h1:5kltdxVKZG0aP1iegeqKz4K8HHyP0wbkW5o84qLyMjY=
366370
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
@@ -384,6 +388,8 @@ github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0o
384388
github.com/uptrace/bun v0.3.9/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw=
385389
github.com/uptrace/bun v1.2.11 h1:l9dTymsdZZAoSZ1+Qo3utms0RffgkDbIv+1UGk8N1wQ=
386390
github.com/uptrace/bun v1.2.11/go.mod h1:ww5G8h59UrOnCHmZ8O1I/4Djc7M/Z3E+EWFS2KLB6dQ=
391+
github.com/uptrace/bun/dbfixture v1.2.11 h1:9rKYVDwQCLdXtPkgzMgvDsHKHXelNlXmnpuNHvFz2w0=
392+
github.com/uptrace/bun/dbfixture v1.2.11/go.mod h1:E2H4A4/dx6+xB61qGsjVqV17Pqyb+Gg5QTmswy4hUpk=
387393
github.com/uptrace/bun/dialect/pgdialect v1.2.11 h1:n0VKWm1fL1dwJK5TRxYYLaRKRe14BOg2+AQgpvqzG/M=
388394
github.com/uptrace/bun/dialect/pgdialect v1.2.11/go.mod h1:NvV1S/zwtwBnW8yhJ3XEKAQEw76SkeH7yUhfrx3W1Eo=
389395
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=

api/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func (s *Server) Setup(ctx context.Context) error {
8484
log.Debug("Redis cache initialized successfully")
8585

8686
uri := pg.URI(s.env.PostgresHost, s.env.PostgresPort, s.env.PostgresUser, s.env.PostgresPassword, s.env.PostgresDB)
87-
store, err := pg.New(ctx, uri, options.Migrate(), options.Log("DEBUG", true))
87+
store, err := pg.New(ctx, uri, options.Migrate("/"), options.Log("DEBUG", true))
8888
if err != nil {
8989
return err
9090
}

api/store/entity/user.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package entity
2+
3+
import (
4+
"github.com/shellhub-io/shellhub/pkg/models"
5+
"github.com/uptrace/bun"
6+
)
7+
8+
type User struct {
9+
bun.BaseModel `bun:"table:users"`
10+
models.User `bun:"embed:"`
11+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package dbtest
2+
3+
import (
4+
"context"
5+
"io"
6+
"log"
7+
"time"
8+
9+
"github.com/testcontainers/testcontainers-go"
10+
"github.com/testcontainers/testcontainers-go/modules/postgres"
11+
"github.com/testcontainers/testcontainers-go/wait"
12+
)
13+
14+
// Server represents a Postgres test server instance.
15+
type Server struct {
16+
container *postgres.PostgresContainer
17+
}
18+
19+
// Up starts a new Postgres container. Use [Server.ConnectionString] to access the connection string.
20+
func (srv *Server) Up(ctx context.Context, verbose bool) error {
21+
if !verbose {
22+
testcontainers.Logger = log.New(io.Discard, "", 0)
23+
}
24+
25+
opts := []testcontainers.ContainerCustomizer{
26+
postgres.WithDatabase("test"),
27+
postgres.WithUsername("admin"),
28+
postgres.WithPassword("admin"),
29+
testcontainers.WithWaitStrategy(wait.ForLog("database system is ready to accept connections").WithOccurrence(2).WithStartupTimeout(5 * time.Second)),
30+
}
31+
32+
container, err := postgres.Run(ctx, "postgres:17", opts...)
33+
if err != nil {
34+
return err
35+
}
36+
37+
srv.container = container
38+
39+
return nil
40+
}
41+
42+
// Down gracefully terminates the Postgres container.
43+
func (srv *Server) Down(ctx context.Context) error {
44+
return srv.container.Terminate(ctx)
45+
}
46+
47+
func (srv *Server) ConnectionString(ctx context.Context) (string, error) {
48+
cIP, err := srv.container.ContainerIP(ctx)
49+
if err != nil {
50+
return "", err
51+
}
52+
53+
return "postgres://admin:admin@" + cIP + ":5432/test", nil
54+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package dbtest
2+
3+
import (
4+
"path/filepath"
5+
"runtime"
6+
)
7+
8+
func FixturesPath() string {
9+
_, file, _, _ := runtime.Caller(0)
10+
11+
return filepath.Join(filepath.Dir(file), "fixtures")
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
- model: User
2+
rows:
3+
- id: USR|9afd8f41-7920-45e2-90e0-88bd581fcd05
4+
created_at: 2025-01-15T10:30:00+00:00
5+
updated_at: 2025-01-15T10:30:00+00:00
6+
status: confirmed
7+
origin: local
8+
external_id: ""
9+
name: Jonh Doe
10+
11+
password: "$2y$12$VVm2ETx7AvaGlfMYqNYK9uzU2M45YZ70YnT..O.s1o2zdE1pekhq6"
12+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package options
2+
3+
import (
4+
"context"
5+
"io/fs"
6+
"os"
7+
8+
"github.com/uptrace/bun"
9+
"github.com/uptrace/bun/dbfixture"
10+
)
11+
12+
func ApplyFixtures(dir string) Option {
13+
return func(ctx context.Context, db *bun.DB) error {
14+
println("path: ", dir)
15+
16+
fixture := dbfixture.New(db)
17+
18+
fsys := os.DirFS(dir)
19+
files, err := fs.ReadDir(fsys, ".")
20+
if err != nil {
21+
return err
22+
}
23+
24+
names := make([]string, 0)
25+
for _, file := range files {
26+
println("\tname: ", file.Name)
27+
28+
if !file.IsDir() {
29+
names = append(names, file.Name())
30+
}
31+
}
32+
33+
return fixture.Load(ctx, fsys, names...)
34+
}
35+
}

api/store/pg/options/migrate.go

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ var (
1919
ErrFilePathEmpty = errors.New("no migration files found in directory")
2020
)
2121

22-
func Migrate() Option {
22+
func Migrate(basePath string) Option {
2323
return func(ctx context.Context, db *bun.DB) error {
2424
driver, err := postgres.WithInstance(db.DB, &postgres.Config{})
2525
if err != nil {
2626
return err
2727
}
2828

29-
migrationsPath, err := fetchMigrationsPath()
29+
migrationsPath, err := fetchMigrationsPath(basePath)
3030
if err != nil {
3131
return err
3232
}
@@ -61,30 +61,21 @@ func Migrate() Option {
6161
}
6262
}
6363

64-
func fetchMigrationsPath() (string, error) {
65-
migrationsPath := filepath.Join("/", "migrations")
66-
67-
_, err := os.Stat(migrationsPath)
68-
if err != nil {
69-
if !os.IsNotExist(err) {
70-
return "", err
71-
}
72-
73-
log.WithField("path", migrationsPath).Info("Migrations directory not found, creating it")
74-
if err := os.MkdirAll(migrationsPath, 0755); err != nil {
75-
return "", errors.New("failed to create migrations directory: " + err.Error())
76-
}
64+
func fetchMigrationsPath(basePath string) (string, error) {
65+
path := filepath.Join(basePath, "migrations")
66+
if _, err := os.Stat(path); err != nil {
67+
return "", err
7768
}
7869

79-
files, err := os.ReadDir(migrationsPath)
70+
files, err := os.ReadDir(path)
8071
if err != nil {
81-
log.WithError(err).WithField("path", migrationsPath).Error("failed to read migrations directory")
72+
log.WithError(err).WithField("path", path).Error("failed to read migrations directory")
8273
return "", err
8374
}
8475

8576
if len(files) == 0 {
8677
return "", ErrFilePathEmpty
8778
}
8879

89-
return migrationsPath, nil
80+
return path, nil
9081
}

api/store/pg/pg.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/jackc/pgx/v5/stdlib"
1010
"github.com/shellhub-io/shellhub/api/store"
1111
"github.com/shellhub-io/shellhub/api/store/pg/options"
12+
"github.com/shellhub-io/shellhub/pkg/models"
1213
"github.com/uptrace/bun"
1314
"github.com/uptrace/bun/dialect/pgdialect"
1415
)
@@ -39,6 +40,9 @@ func New(ctx context.Context, uri string, opts ...options.Option) (store.Store,
3940
return nil, err
4041
}
4142

43+
// We need to register models so we can apply fixtures and relations later
44+
pg.driver.RegisterModel((*models.User)(nil))
45+
4246
for _, opt := range opts {
4347
if err := opt(ctx, pg.driver); err != nil {
4448
return nil, err

0 commit comments

Comments
 (0)