Merged in feature/client (pull request #31)
Client Entity * repolevel * servicefunctions * openapiclientget * openapiupdate * client * vendor
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user