Merged in feature/client (pull request #31)

Client Entity

* repolevel

* servicefunctions

* openapiclientget

* openapiupdate

* client

* vendor
This commit is contained in:
Michael McGuinness
2025-01-21 18:24:14 +00:00
parent 4ccb980593
commit 04d8eaf52c
39 changed files with 1532 additions and 432 deletions
+22
View File
@@ -0,0 +1,22 @@
package client
import (
"context"
"queryorchestration/internal/database"
"github.com/google/uuid"
)
func (s *Service) Create(ctx context.Context, name string) (uuid.UUID, error) {
name, err := normalizeName(name)
if err != nil {
return uuid.Nil, err
}
id, err := s.db.Queries.CreateClient(ctx, name)
if err != nil {
return uuid.Nil, err
}
return database.MustToUUID(id), nil
}
+42
View File
@@ -0,0 +1,42 @@
package client_test
import (
"context"
"queryorchestration/internal/client"
"queryorchestration/internal/database"
"queryorchestration/internal/database/repository"
"testing"
"github.com/google/uuid"
"github.com/pashagolub/pgxmock/v3"
"github.com/stretchr/testify/assert"
)
func TestCreate(t *testing.T) {
ctx := context.Background()
pool, err := pgxmock.NewPool()
if err != nil {
t.Fatalf("failed to open pgxmock database: %v", err)
}
queries := repository.New(pool)
db := &database.Connection{
Queries: queries,
Pool: pool,
}
svc := client.New(db)
name := "client_name"
aid := uuid.New()
pool.ExpectQuery("name: CreateClient :one").WithArgs(name).
WillReturnRows(
pgxmock.NewRows([]string{"id"}).
AddRow(database.MustToDBUUID(aid)),
)
id, err := svc.Create(ctx, name)
assert.Nil(t, err)
assert.Equal(t, aid, id)
}
+21
View File
@@ -0,0 +1,21 @@
package client
import (
"context"
"queryorchestration/internal/database"
"github.com/google/uuid"
)
func (s *Service) Get(ctx context.Context, id uuid.UUID) (*Client, error) {
client, err := s.db.Queries.GetClient(ctx, database.MustToDBUUID(id))
if err != nil {
return nil, err
}
return &Client{
ID: database.MustToUUID(client.ID),
Name: client.Name,
CanSync: client.Cansync,
}, nil
}
+53
View File
@@ -0,0 +1,53 @@
package client_test
import (
"context"
"errors"
"queryorchestration/internal/client"
"queryorchestration/internal/database"
"queryorchestration/internal/database/repository"
"testing"
"github.com/google/uuid"
"github.com/pashagolub/pgxmock/v3"
"github.com/stretchr/testify/assert"
)
func TestGet(t *testing.T) {
ctx := context.Background()
pool, err := pgxmock.NewPool()
if err != nil {
t.Fatalf("failed to open pgxmock database: %v", err)
}
queries := repository.New(pool)
db := &database.Connection{
Queries: queries,
Pool: pool,
}
svc := client.New(db)
id := uuid.New()
pool.ExpectQuery("name: GetClient :one").WithArgs(database.MustToDBUUID(id)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "name", "canSync"}).
AddRow(database.MustToDBUUID(id), "client_name", false),
)
cli, err := svc.Get(ctx, id)
assert.Nil(t, err)
assert.EqualExportedValues(t, &client.Client{
ID: id,
Name: "client_name",
CanSync: false,
}, cli)
dberr := "database failure"
pool.ExpectQuery("name: GetClient :one").WithArgs(database.MustToDBUUID(id)).
WillReturnError(errors.New(dberr))
_, err = svc.Get(ctx, id)
assert.EqualError(t, err, dberr)
}
+63
View File
@@ -0,0 +1,63 @@
package client
import (
"errors"
"fmt"
"queryorchestration/internal/database"
"regexp"
"strings"
"github.com/google/uuid"
)
type Client struct {
ID uuid.UUID
Name string
CanSync bool
}
func (c *Client) getCanSyncUpdate(n *bool) bool {
if n == nil {
return c.CanSync
}
return *n
}
func (c *Client) getNameUpdate(n *string) (string, error) {
if n == nil {
return c.Name, nil
}
return normalizeName(*n)
}
func normalizeName(name string) (string, error) {
name = strings.TrimSpace(name)
if name == "" {
return "", errors.New("name required")
}
spacere := regexp.MustCompile(`\s+`)
name = spacere.ReplaceAllString(name, " ")
reg := `^[a-zA-Z0-9\_\- ]+$`
alphanumeric := regexp.MustCompile(reg)
if !alphanumeric.MatchString(name) {
return "", fmt.Errorf("name must have regex: %s", reg)
}
return name, nil
}
type Service struct {
db *database.Connection
}
func New(db *database.Connection) *Service {
return &Service{
db,
}
}
+26
View File
@@ -0,0 +1,26 @@
package client_test
import (
"queryorchestration/internal/client"
"queryorchestration/internal/database"
"queryorchestration/internal/database/repository"
"testing"
"github.com/pashagolub/pgxmock/v3"
"github.com/stretchr/testify/assert"
)
func TestService(t *testing.T) {
pool, err := pgxmock.NewPool()
if err != nil {
t.Fatalf("failed to open pgxmock database: %v", err)
}
queries := repository.New(pool)
db := &database.Connection{
Queries: queries,
Pool: pool,
}
svc := client.New(db)
assert.NotNil(t, svc)
}
+74
View File
@@ -0,0 +1,74 @@
package client
import (
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
)
func TestNormalizeName(t *testing.T) {
name, err := normalizeName("name")
assert.Nil(t, err)
assert.Equal(t, "name", name)
_, err = normalizeName("")
assert.NotNil(t, err)
name, err = normalizeName(" name\t")
assert.Nil(t, err)
assert.Equal(t, "name", name)
name, err = normalizeName("name second")
assert.Nil(t, err)
assert.Equal(t, "name second", name)
name, err = normalizeName("name\t second")
assert.Nil(t, err)
assert.Equal(t, "name second", name)
name, err = normalizeName("name_second")
assert.Nil(t, err)
assert.Equal(t, "name_second", name)
name, err = normalizeName("name-second")
assert.Nil(t, err)
assert.Equal(t, "name-second", name)
name, err = normalizeName("name123")
assert.Nil(t, err)
assert.Equal(t, "name123", name)
}
func TestGetCanSyncUpdate(t *testing.T) {
c := Client{
ID: uuid.New(),
CanSync: true,
}
assert.Equal(t, true, c.getCanSyncUpdate(nil))
val := false
assert.Equal(t, false, c.getCanSyncUpdate(&val))
val = true
assert.Equal(t, true, c.getCanSyncUpdate(&val))
}
func TestGetNameUpdate(t *testing.T) {
c := Client{
ID: uuid.New(),
Name: "example_name",
}
name, err := c.getNameUpdate(nil)
assert.Nil(t, err)
assert.Equal(t, "example_name", name)
val := "update_name"
name, err = c.getNameUpdate(&val)
assert.Nil(t, err)
assert.Equal(t, "update_name", name)
val = "###"
_, err = c.getNameUpdate(&val)
assert.Error(t, err)
}
+54
View File
@@ -0,0 +1,54 @@
package client
import (
"context"
"errors"
"queryorchestration/internal/database"
"queryorchestration/internal/database/repository"
"github.com/google/uuid"
)
type Update struct {
ID uuid.UUID
Name *string
CanSync *bool
}
func (s *Service) Update(ctx context.Context, entity *Update) error {
current, err := s.Get(ctx, entity.ID)
if err != nil {
return err
}
params, err := s.getUpdateParams(current, entity)
if err != nil {
return err
}
err = s.db.Queries.UpdateClient(ctx, params)
if err != nil {
return err
}
return nil
}
func (s *Service) getUpdateParams(current *Client, entity *Update) (*repository.UpdateClientParams, error) {
if entity == nil || current == nil || current.ID != entity.ID {
return nil, errors.New("no updates presented")
}
name, err := current.getNameUpdate(entity.Name)
if err != nil {
return nil, err
}
canSync := current.getCanSyncUpdate(entity.CanSync)
return &repository.UpdateClientParams{
ID: database.MustToDBUUID(current.ID),
Name: name,
Cansync: canSync,
}, nil
}
+77
View File
@@ -0,0 +1,77 @@
package client_test
import (
"context"
"queryorchestration/internal/client"
"queryorchestration/internal/database"
"queryorchestration/internal/database/repository"
"testing"
"github.com/google/uuid"
"github.com/pashagolub/pgxmock/v3"
"github.com/stretchr/testify/assert"
)
func TestUpdate(t *testing.T) {
ctx := context.Background()
pool, err := pgxmock.NewPool()
if err != nil {
t.Fatalf("failed to open pgxmock database: %v", err)
}
queries := repository.New(pool)
db := &database.Connection{
Queries: queries,
Pool: pool,
}
svc := client.New(db)
c := client.Client{
ID: uuid.New(),
Name: "example_name",
CanSync: false,
}
update := client.Update{
ID: c.ID,
}
pool.ExpectQuery("name: GetClient :one").WithArgs(database.MustToDBUUID(c.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "name", "canSync"}).
AddRow(database.MustToDBUUID(c.ID), c.Name, c.CanSync),
)
pool.ExpectExec("name: UpdateClient :exec").WithArgs(c.Name, c.CanSync, database.MustToDBUUID(update.ID)).
WillReturnResult(pgxmock.NewResult("", 1))
err = svc.Update(ctx, &update)
assert.Nil(t, err)
c.CanSync = false
update.CanSync = &c.CanSync
pool.ExpectQuery("name: GetClient :one").WithArgs(database.MustToDBUUID(c.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "name", "canSync"}).
AddRow(database.MustToDBUUID(c.ID), c.Name, c.CanSync),
)
pool.ExpectExec("name: UpdateClient :exec").WithArgs(c.Name, *update.CanSync, database.MustToDBUUID(update.ID)).
WillReturnResult(pgxmock.NewResult("", 1))
err = svc.Update(ctx, &update)
assert.Nil(t, err)
c.Name = "updated_name"
update.Name = &c.Name
pool.ExpectQuery("name: GetClient :one").WithArgs(database.MustToDBUUID(c.ID)).
WillReturnRows(
pgxmock.NewRows([]string{"id", "name", "canSync"}).
AddRow(database.MustToDBUUID(c.ID), c.Name, c.CanSync),
)
pool.ExpectExec("name: UpdateClient :exec").WithArgs(*update.Name, *update.CanSync, database.MustToDBUUID(update.ID)).
WillReturnResult(pgxmock.NewResult("", 1))
err = svc.Update(ctx, &update)
assert.Nil(t, err)
}