Merged in feature/logVersioning (pull request #40)
Can Sync Versioning * started * client * jobcansync * tests
This commit is contained in:
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func (s *Service) Create(ctx context.Context, name string) (uuid.UUID, error) {
|
||||
name, err := normalizeName(name)
|
||||
err := normalizeName(&name)
|
||||
if err != nil {
|
||||
return uuid.Nil, err
|
||||
}
|
||||
|
||||
+33
-16
@@ -16,40 +16,57 @@ type Client struct {
|
||||
CanSync bool
|
||||
}
|
||||
|
||||
func (c *Client) getCanSyncUpdate(n *bool) bool {
|
||||
if n == nil {
|
||||
return c.CanSync
|
||||
func (c *Client) normalizeCanSyncUpdate(n **bool) {
|
||||
if n == nil || *n == nil {
|
||||
return
|
||||
}
|
||||
|
||||
return *n
|
||||
if c.CanSync == **n {
|
||||
*n = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) getNameUpdate(n *string) (string, error) {
|
||||
if n == nil {
|
||||
return c.Name, nil
|
||||
func (c *Client) normalizeNameUpdate(n **string) error {
|
||||
if n == nil || *n == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return normalizeName(*n)
|
||||
err := normalizeName(*n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Name == **n {
|
||||
*n = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeName(name string) (string, error) {
|
||||
name = strings.TrimSpace(name)
|
||||
func normalizeName(name *string) error {
|
||||
if name == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
return "", errors.New("name required")
|
||||
uname := strings.TrimSpace(*name)
|
||||
|
||||
if uname == "" {
|
||||
return errors.New("name required")
|
||||
}
|
||||
|
||||
spacere := regexp.MustCompile(`\s+`)
|
||||
name = spacere.ReplaceAllString(name, " ")
|
||||
uname = spacere.ReplaceAllString(uname, " ")
|
||||
|
||||
reg := `^[a-zA-Z0-9\_\- ]+$`
|
||||
|
||||
alphanumeric := regexp.MustCompile(reg)
|
||||
if !alphanumeric.MatchString(name) {
|
||||
return "", fmt.Errorf("name must have regex: %s", reg)
|
||||
if !alphanumeric.MatchString(uname) {
|
||||
return fmt.Errorf("name must have regex: %s", reg)
|
||||
}
|
||||
|
||||
return name, nil
|
||||
*name = uname
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
|
||||
@@ -8,67 +8,92 @@ import (
|
||||
)
|
||||
|
||||
func TestNormalizeName(t *testing.T) {
|
||||
name, err := normalizeName("name")
|
||||
name := "name"
|
||||
err := normalizeName(&name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "name", name)
|
||||
|
||||
_, err = normalizeName("")
|
||||
name = ""
|
||||
err = normalizeName(&name)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
name, err = normalizeName(" name\t")
|
||||
name = " name\t"
|
||||
err = normalizeName(&name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "name", name)
|
||||
|
||||
name, err = normalizeName("name second")
|
||||
name = "name second"
|
||||
err = normalizeName(&name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "name second", name)
|
||||
|
||||
name, err = normalizeName("name\t second")
|
||||
name = "name\t second"
|
||||
err = normalizeName(&name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "name second", name)
|
||||
|
||||
name, err = normalizeName("name_second")
|
||||
name = "name_second"
|
||||
err = normalizeName(&name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "name_second", name)
|
||||
|
||||
name, err = normalizeName("name-second")
|
||||
name = "name-second"
|
||||
err = normalizeName(&name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "name-second", name)
|
||||
|
||||
name, err = normalizeName("name123")
|
||||
name = "name123"
|
||||
err = normalizeName(&name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "name123", name)
|
||||
}
|
||||
|
||||
func TestGetCanSyncUpdate(t *testing.T) {
|
||||
func TestNormalizeCanSyncUpdate(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))
|
||||
c.normalizeCanSyncUpdate(nil)
|
||||
var val *bool
|
||||
c.normalizeCanSyncUpdate(&val)
|
||||
assert.Nil(t, val)
|
||||
|
||||
v := true
|
||||
val = &v
|
||||
c.normalizeCanSyncUpdate(&val)
|
||||
assert.Nil(t, val)
|
||||
|
||||
v = false
|
||||
val = &v
|
||||
c.normalizeCanSyncUpdate(&val)
|
||||
assert.NotNil(t, *val)
|
||||
}
|
||||
|
||||
func TestGetNameUpdate(t *testing.T) {
|
||||
func TestNormalizeNameUpdate(t *testing.T) {
|
||||
c := Client{
|
||||
ID: uuid.New(),
|
||||
Name: "example_name",
|
||||
}
|
||||
|
||||
name, err := c.getNameUpdate(nil)
|
||||
err := c.normalizeNameUpdate(nil)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "example_name", name)
|
||||
|
||||
val := "update_name"
|
||||
name, err = c.getNameUpdate(&val)
|
||||
v := "update_name"
|
||||
val := &v
|
||||
err = c.normalizeNameUpdate(&val)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "update_name", name)
|
||||
assert.NotNil(t, val)
|
||||
assert.Equal(t, "update_name", *val)
|
||||
|
||||
val = "###"
|
||||
_, err = c.getNameUpdate(&val)
|
||||
v = c.Name
|
||||
val = &v
|
||||
err = c.normalizeNameUpdate(&val)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, val)
|
||||
|
||||
v = "###"
|
||||
val = &v
|
||||
err = c.normalizeNameUpdate(&val)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
+44
-16
@@ -21,12 +21,12 @@ func (s *Service) Update(ctx context.Context, entity *Update) error {
|
||||
return err
|
||||
}
|
||||
|
||||
params, err := s.getUpdateParams(current, entity)
|
||||
err = s.normalizeUpdateParams(current, entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.db.Queries.UpdateClient(ctx, params)
|
||||
err = s.submitUpdate(ctx, entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -34,21 +34,49 @@ func (s *Service) Update(ctx context.Context, entity *Update) error {
|
||||
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")
|
||||
}
|
||||
func (s *Service) submitUpdate(ctx context.Context, entity *Update) error {
|
||||
return database.ExecuteTransaction(ctx, s.db, func(ctx context.Context, q *repository.Queries) error {
|
||||
id := database.MustToDBUUID(entity.ID)
|
||||
|
||||
name, err := current.getNameUpdate(entity.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if entity.Name != nil {
|
||||
err := q.UpdateClient(ctx, &repository.UpdateClientParams{
|
||||
ID: id,
|
||||
Name: *entity.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
canSync := current.getCanSyncUpdate(entity.CanSync)
|
||||
if entity.CanSync != nil {
|
||||
err := q.AddClientCanSync(ctx, &repository.AddClientCanSyncParams{
|
||||
Clientid: id,
|
||||
Cansync: *entity.CanSync,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return &repository.UpdateClientParams{
|
||||
ID: database.MustToDBUUID(current.ID),
|
||||
Name: name,
|
||||
Cansync: canSync,
|
||||
}, nil
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) normalizeUpdateParams(current *Client, entity *Update) error {
|
||||
if entity == nil || current == nil || current.ID != entity.ID {
|
||||
return errors.New("no updates presented")
|
||||
}
|
||||
|
||||
err := current.normalizeNameUpdate(&entity.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
current.normalizeCanSyncUpdate(&entity.CanSync)
|
||||
|
||||
if entity.Name == nil && entity.CanSync == nil {
|
||||
return errors.New("no updates presented")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+102
-12
@@ -1,8 +1,7 @@
|
||||
package client_test
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/client"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"testing"
|
||||
@@ -25,14 +24,14 @@ func TestUpdate(t *testing.T) {
|
||||
Pool: pool,
|
||||
}
|
||||
|
||||
svc := client.New(db)
|
||||
svc := New(db)
|
||||
|
||||
c := client.Client{
|
||||
c := Client{
|
||||
ID: uuid.New(),
|
||||
Name: "example_name",
|
||||
CanSync: false,
|
||||
}
|
||||
update := client.Update{
|
||||
update := Update{
|
||||
ID: c.ID,
|
||||
}
|
||||
|
||||
@@ -41,11 +40,9 @@ func TestUpdate(t *testing.T) {
|
||||
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)
|
||||
assert.Error(t, err)
|
||||
|
||||
c.CanSync = false
|
||||
update.CanSync = &c.CanSync
|
||||
@@ -55,11 +52,9 @@ func TestUpdate(t *testing.T) {
|
||||
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)
|
||||
assert.Error(t, err)
|
||||
|
||||
c.Name = "updated_name"
|
||||
update.Name = &c.Name
|
||||
@@ -69,9 +64,104 @@ func TestUpdate(t *testing.T) {
|
||||
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)).
|
||||
pool.ExpectExec("name: UpdateClient :exec").WithArgs(*update.Name, database.MustToDBUUID(update.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
|
||||
err = svc.Update(ctx, &update)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNormalizeUpdateParams(t *testing.T) {
|
||||
svc := Service{}
|
||||
|
||||
err := svc.normalizeUpdateParams(nil, nil)
|
||||
assert.Error(t, err)
|
||||
|
||||
current := &Client{
|
||||
ID: uuid.New(),
|
||||
Name: "client",
|
||||
}
|
||||
update := &Update{}
|
||||
|
||||
err = svc.normalizeUpdateParams(current, update)
|
||||
assert.Error(t, err)
|
||||
|
||||
n := "updated_client"
|
||||
cs := true
|
||||
update = &Update{
|
||||
ID: current.ID,
|
||||
Name: &n,
|
||||
CanSync: &cs,
|
||||
}
|
||||
err = svc.normalizeUpdateParams(current, update)
|
||||
assert.Nil(t, err)
|
||||
n = "updated_client"
|
||||
cs = true
|
||||
assert.EqualExportedValues(t, Update{
|
||||
ID: current.ID,
|
||||
Name: &n,
|
||||
CanSync: &cs,
|
||||
}, *update)
|
||||
|
||||
update = &Update{
|
||||
ID: current.ID,
|
||||
Name: ¤t.Name,
|
||||
CanSync: ¤t.CanSync,
|
||||
}
|
||||
err = svc.normalizeUpdateParams(current, update)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestSubmitUpdate(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 := New(db)
|
||||
|
||||
c := Client{
|
||||
ID: uuid.New(),
|
||||
Name: "example_name",
|
||||
CanSync: false,
|
||||
}
|
||||
update := Update{
|
||||
ID: c.ID,
|
||||
}
|
||||
|
||||
pool.ExpectBegin()
|
||||
pool.ExpectCommit()
|
||||
|
||||
err = svc.submitUpdate(ctx, &update)
|
||||
assert.Nil(t, err)
|
||||
|
||||
c.CanSync = true
|
||||
update.CanSync = &c.CanSync
|
||||
|
||||
pool.ExpectBegin()
|
||||
pool.ExpectExec("name: AddClientCanSync :exec").WithArgs(*update.CanSync, database.MustToDBUUID(update.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectCommit()
|
||||
|
||||
err = svc.submitUpdate(ctx, &update)
|
||||
assert.Nil(t, err)
|
||||
|
||||
c.Name = "updated_name"
|
||||
update.Name = &c.Name
|
||||
update.CanSync = nil
|
||||
|
||||
pool.ExpectBegin()
|
||||
pool.ExpectExec("name: UpdateClient :exec").WithArgs(*update.Name, database.MustToDBUUID(update.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectCommit()
|
||||
|
||||
err = svc.submitUpdate(ctx, &update)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestDBConn(t *testing.T) {
|
||||
assert.NotNil(t, pool)
|
||||
}
|
||||
|
||||
func TestExecuteTransation(t *testing.T) {
|
||||
func TestExecuteTransaction(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
pool, err := pgxmock.NewPool()
|
||||
|
||||
@@ -11,6 +11,23 @@ import (
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const addClientCanSync = `-- name: AddClientCanSync :exec
|
||||
INSERT INTO clientCanSync (canSync, clientId) VALUES ($1, $2)
|
||||
`
|
||||
|
||||
type AddClientCanSyncParams struct {
|
||||
Cansync bool `db:"cansync"`
|
||||
Clientid pgtype.UUID `db:"clientid"`
|
||||
}
|
||||
|
||||
// AddClientCanSync
|
||||
//
|
||||
// INSERT INTO clientCanSync (canSync, clientId) VALUES ($1, $2)
|
||||
func (q *Queries) AddClientCanSync(ctx context.Context, arg *AddClientCanSyncParams) error {
|
||||
_, err := q.db.Exec(ctx, addClientCanSync, arg.Cansync, arg.Clientid)
|
||||
return err
|
||||
}
|
||||
|
||||
const createClient = `-- name: CreateClient :one
|
||||
INSERT INTO clients (name) VALUES ($1) RETURNING id
|
||||
`
|
||||
@@ -26,33 +43,56 @@ func (q *Queries) CreateClient(ctx context.Context, name string) (pgtype.UUID, e
|
||||
}
|
||||
|
||||
const getClient = `-- name: GetClient :one
|
||||
SELECT id, name, canSync FROM clients WHERE id = $1
|
||||
SELECT c.id, c.name, coalesce(cs.canSync, false) as canSync
|
||||
FROM clients as c
|
||||
LEFT JOIN (
|
||||
SELECT clientId, canSync
|
||||
FROM clientCanSync
|
||||
WHERE clientId = $1
|
||||
ORDER BY addedAt DESC
|
||||
LIMIT 1
|
||||
) as cs on cs.clientId = c.id
|
||||
WHERE c.id = $1
|
||||
`
|
||||
|
||||
type GetClientRow struct {
|
||||
ID pgtype.UUID `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Cansync bool `db:"cansync"`
|
||||
}
|
||||
|
||||
// GetClient
|
||||
//
|
||||
// SELECT id, name, canSync FROM clients WHERE id = $1
|
||||
func (q *Queries) GetClient(ctx context.Context, id pgtype.UUID) (*Client, error) {
|
||||
row := q.db.QueryRow(ctx, getClient, id)
|
||||
var i Client
|
||||
// SELECT c.id, c.name, coalesce(cs.canSync, false) as canSync
|
||||
// FROM clients as c
|
||||
// LEFT JOIN (
|
||||
// SELECT clientId, canSync
|
||||
// FROM clientCanSync
|
||||
// WHERE clientId = $1
|
||||
// ORDER BY addedAt DESC
|
||||
// LIMIT 1
|
||||
// ) as cs on cs.clientId = c.id
|
||||
// WHERE c.id = $1
|
||||
func (q *Queries) GetClient(ctx context.Context, clientid pgtype.UUID) (*GetClientRow, error) {
|
||||
row := q.db.QueryRow(ctx, getClient, clientid)
|
||||
var i GetClientRow
|
||||
err := row.Scan(&i.ID, &i.Name, &i.Cansync)
|
||||
return &i, err
|
||||
}
|
||||
|
||||
const updateClient = `-- name: UpdateClient :exec
|
||||
UPDATE clients SET name = $1, canSync = $2 WHERE id = $3
|
||||
UPDATE clients SET name = $1 WHERE id = $2
|
||||
`
|
||||
|
||||
type UpdateClientParams struct {
|
||||
Name string `db:"name"`
|
||||
Cansync bool `db:"cansync"`
|
||||
ID pgtype.UUID `db:"id"`
|
||||
Name string `db:"name"`
|
||||
ID pgtype.UUID `db:"id"`
|
||||
}
|
||||
|
||||
// UpdateClient
|
||||
//
|
||||
// UPDATE clients SET name = $1, canSync = $2 WHERE id = $3
|
||||
// UPDATE clients SET name = $1 WHERE id = $2
|
||||
func (q *Queries) UpdateClient(ctx context.Context, arg *UpdateClientParams) error {
|
||||
_, err := q.db.Exec(ctx, updateClient, arg.Name, arg.Cansync, arg.ID)
|
||||
_, err := q.db.Exec(ctx, updateClient, arg.Name, arg.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -28,22 +28,35 @@ func TestClient(t *testing.T) {
|
||||
|
||||
client, err := queries.GetClient(ctx, id)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualExportedValues(t, &repository.Client{
|
||||
assert.EqualExportedValues(t, &repository.GetClientRow{
|
||||
ID: id,
|
||||
Name: "example_client",
|
||||
Cansync: false,
|
||||
}, client)
|
||||
|
||||
err = queries.UpdateClient(ctx, &repository.UpdateClientParams{
|
||||
ID: id,
|
||||
Name: "updated_client",
|
||||
Cansync: true,
|
||||
ID: id,
|
||||
Name: "updated_client",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
client, err = queries.GetClient(ctx, id)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualExportedValues(t, &repository.Client{
|
||||
assert.EqualExportedValues(t, &repository.GetClientRow{
|
||||
ID: id,
|
||||
Name: "updated_client",
|
||||
Cansync: false,
|
||||
}, client)
|
||||
|
||||
err = queries.AddClientCanSync(ctx, &repository.AddClientCanSyncParams{
|
||||
Clientid: id,
|
||||
Cansync: true,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
client, err = queries.GetClient(ctx, id)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualExportedValues(t, &repository.GetClientRow{
|
||||
ID: id,
|
||||
Name: "updated_client",
|
||||
Cansync: true,
|
||||
|
||||
@@ -11,6 +11,23 @@ import (
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const addJobCanSync = `-- name: AddJobCanSync :exec
|
||||
INSERT INTO jobCanSync (canSync, jobId) VALUES ($1, $2)
|
||||
`
|
||||
|
||||
type AddJobCanSyncParams struct {
|
||||
Cansync bool `db:"cansync"`
|
||||
Jobid pgtype.UUID `db:"jobid"`
|
||||
}
|
||||
|
||||
// AddJobCanSync
|
||||
//
|
||||
// INSERT INTO jobCanSync (canSync, jobId) VALUES ($1, $2)
|
||||
func (q *Queries) AddJobCanSync(ctx context.Context, arg *AddJobCanSyncParams) error {
|
||||
_, err := q.db.Exec(ctx, addJobCanSync, arg.Cansync, arg.Jobid)
|
||||
return err
|
||||
}
|
||||
|
||||
const createJob = `-- name: CreateJob :one
|
||||
INSERT INTO jobs (clientId) VALUES ($1) RETURNING id
|
||||
`
|
||||
@@ -26,32 +43,39 @@ func (q *Queries) CreateJob(ctx context.Context, clientid pgtype.UUID) (pgtype.U
|
||||
}
|
||||
|
||||
const getJob = `-- name: GetJob :one
|
||||
SELECT id, clientId, canSync FROM jobs WHERE id = $1 LIMIT 1
|
||||
SELECT j.id, j.clientId, coalesce(cs.canSync, false) as canSync
|
||||
FROM jobs as j
|
||||
LEFT JOIN (
|
||||
SELECT jobId, canSync
|
||||
FROM jobCanSync
|
||||
WHERE jobId = $1
|
||||
ORDER BY addedAt DESC
|
||||
LIMIT 1
|
||||
) as cs on cs.jobId = j.id
|
||||
WHERE j.id = $1
|
||||
`
|
||||
|
||||
type GetJobRow struct {
|
||||
ID pgtype.UUID `db:"id"`
|
||||
Clientid pgtype.UUID `db:"clientid"`
|
||||
Cansync bool `db:"cansync"`
|
||||
}
|
||||
|
||||
// GetJob
|
||||
//
|
||||
// SELECT id, clientId, canSync FROM jobs WHERE id = $1 LIMIT 1
|
||||
func (q *Queries) GetJob(ctx context.Context, id pgtype.UUID) (*Job, error) {
|
||||
row := q.db.QueryRow(ctx, getJob, id)
|
||||
var i Job
|
||||
// SELECT j.id, j.clientId, coalesce(cs.canSync, false) as canSync
|
||||
// FROM jobs as j
|
||||
// LEFT JOIN (
|
||||
// SELECT jobId, canSync
|
||||
// FROM jobCanSync
|
||||
// WHERE jobId = $1
|
||||
// ORDER BY addedAt DESC
|
||||
// LIMIT 1
|
||||
// ) as cs on cs.jobId = j.id
|
||||
// WHERE j.id = $1
|
||||
func (q *Queries) GetJob(ctx context.Context, jobid pgtype.UUID) (*GetJobRow, error) {
|
||||
row := q.db.QueryRow(ctx, getJob, jobid)
|
||||
var i GetJobRow
|
||||
err := row.Scan(&i.ID, &i.Clientid, &i.Cansync)
|
||||
return &i, err
|
||||
}
|
||||
|
||||
const updateJob = `-- name: UpdateJob :exec
|
||||
UPDATE jobs SET canSync = $1 WHERE id = $2
|
||||
`
|
||||
|
||||
type UpdateJobParams struct {
|
||||
Cansync bool `db:"cansync"`
|
||||
ID pgtype.UUID `db:"id"`
|
||||
}
|
||||
|
||||
// UpdateJob
|
||||
//
|
||||
// UPDATE jobs SET canSync = $1 WHERE id = $2
|
||||
func (q *Queries) UpdateJob(ctx context.Context, arg *UpdateJobParams) error {
|
||||
_, err := q.db.Exec(ctx, updateJob, arg.Cansync, arg.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -31,21 +31,21 @@ func TestJob(t *testing.T) {
|
||||
|
||||
job, err := queries.GetJob(ctx, id)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualExportedValues(t, &repository.Job{
|
||||
assert.EqualExportedValues(t, &repository.GetJobRow{
|
||||
ID: id,
|
||||
Clientid: clientId,
|
||||
Cansync: false,
|
||||
}, job)
|
||||
|
||||
err = queries.UpdateJob(ctx, &repository.UpdateJobParams{
|
||||
err = queries.AddJobCanSync(ctx, &repository.AddJobCanSyncParams{
|
||||
Cansync: true,
|
||||
ID: id,
|
||||
Jobid: id,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
job, err = queries.GetJob(ctx, id)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualExportedValues(t, &repository.Job{
|
||||
assert.EqualExportedValues(t, &repository.GetJobRow{
|
||||
ID: id,
|
||||
Clientid: clientId,
|
||||
Cansync: true,
|
||||
|
||||
@@ -63,9 +63,15 @@ func (e Querytype) Valid() bool {
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
ID pgtype.UUID `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Cansync bool `db:"cansync"`
|
||||
ID pgtype.UUID `db:"id"`
|
||||
Name string `db:"name"`
|
||||
}
|
||||
|
||||
type Clientcansync struct {
|
||||
ID pgtype.UUID `db:"id"`
|
||||
Clientid pgtype.UUID `db:"clientid"`
|
||||
Cansync bool `db:"cansync"`
|
||||
Addedat pgtype.Timestamp `db:"addedat"`
|
||||
}
|
||||
|
||||
type Collector struct {
|
||||
@@ -130,7 +136,13 @@ type Fullactivequery struct {
|
||||
type Job struct {
|
||||
ID pgtype.UUID `db:"id"`
|
||||
Clientid pgtype.UUID `db:"clientid"`
|
||||
Cansync bool `db:"cansync"`
|
||||
}
|
||||
|
||||
type Jobcansync struct {
|
||||
ID pgtype.UUID `db:"id"`
|
||||
Jobid pgtype.UUID `db:"jobid"`
|
||||
Cansync bool `db:"cansync"`
|
||||
Addedat pgtype.Timestamp `db:"addedat"`
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
|
||||
+38
-10
@@ -24,7 +24,21 @@ func (s *Service) Update(ctx context.Context, update *Update) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.normalizeCanSync(ctx, current, update)
|
||||
err = s.normalizeUpdate(ctx, current, update)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.submitUpdate(ctx, update)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) normalizeUpdate(ctx context.Context, current *Job, update *Update) error {
|
||||
err := s.normalizeCanSync(ctx, current, update)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -33,17 +47,27 @@ func (s *Service) Update(ctx context.Context, update *Update) error {
|
||||
return errors.New("no changes")
|
||||
}
|
||||
|
||||
err = s.db.Queries.UpdateJob(ctx, &repository.UpdateJobParams{
|
||||
ID: database.MustToDBUUID(update.ID),
|
||||
Cansync: *update.CanSync,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) submitUpdate(ctx context.Context, update *Update) error {
|
||||
err := database.ExecuteTransaction(ctx, s.db, func(ctx context.Context, q *repository.Queries) error {
|
||||
if update.CanSync != nil {
|
||||
err := q.AddJobCanSync(ctx, &repository.AddJobCanSyncParams{
|
||||
Jobid: database.MustToDBUUID(update.ID),
|
||||
Cansync: *update.CanSync,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) normalizeCanSync(ctx context.Context, current *Job, update *Update) error {
|
||||
if update.CanSync == nil {
|
||||
return nil
|
||||
@@ -52,10 +76,14 @@ func (s *Service) normalizeCanSync(ctx context.Context, current *Job, update *Up
|
||||
return nil
|
||||
}
|
||||
|
||||
if !*update.CanSync {
|
||||
return nil
|
||||
}
|
||||
|
||||
client, err := s.svc.Client.Get(ctx, current.ClientID)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !client.CanSync && *update.CanSync {
|
||||
} else if !client.CanSync {
|
||||
return errors.New("client not allowing sync")
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,11 @@ func TestUpdate(t *testing.T) {
|
||||
ClientID: uuid.New(),
|
||||
CanSync: true,
|
||||
}
|
||||
ucs := !j.CanSync
|
||||
u := &job.Update{
|
||||
ID: j.ID,
|
||||
CanSync: &ucs,
|
||||
}
|
||||
|
||||
pool.ExpectQuery("name: GetJob :one").WithArgs(database.MustToDBUUID(j.ID)).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "clientId", "canSync"}).
|
||||
@@ -45,18 +50,11 @@ func TestUpdate(t *testing.T) {
|
||||
pgxmock.NewRows([]string{"id", "name", "canSync"}).
|
||||
AddRow(database.MustToDBUUID(j.ClientID), "client_name", true),
|
||||
)
|
||||
pool.ExpectQuery("name: GetClient :one").WithArgs(database.MustToDBUUID(j.ClientID)).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "name", "canSync"}).
|
||||
AddRow(database.MustToDBUUID(j.ClientID), "client_name", true),
|
||||
)
|
||||
ucs := !j.CanSync
|
||||
pool.ExpectExec("name: UpdateJob :exec").WithArgs(ucs, database.MustToDBUUID(j.ID)).
|
||||
pool.ExpectBegin()
|
||||
pool.ExpectExec("name: AddJobCanSync :exec").WithArgs(*u.CanSync, database.MustToDBUUID(j.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectCommit()
|
||||
|
||||
err = svc.Update(ctx, &job.Update{
|
||||
ID: j.ID,
|
||||
CanSync: &ucs,
|
||||
})
|
||||
err = svc.Update(ctx, u)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
@@ -91,3 +91,83 @@ func TestNormalizeCanSync(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, update.CanSync)
|
||||
}
|
||||
|
||||
func TestNormalizeUpdate(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 := New(db, &Services{
|
||||
Client: client.New(db),
|
||||
})
|
||||
|
||||
j := Job{
|
||||
ID: uuid.New(),
|
||||
ClientID: uuid.New(),
|
||||
CanSync: true,
|
||||
}
|
||||
|
||||
ucs := false
|
||||
update := Update{
|
||||
ID: j.ID,
|
||||
CanSync: &ucs,
|
||||
}
|
||||
|
||||
err = svc.normalizeUpdate(ctx, &j, &update)
|
||||
assert.Nil(t, err)
|
||||
ucs = !ucs
|
||||
assert.EqualExportedValues(t, Update{ID: update.ID, CanSync: &ucs}, update)
|
||||
}
|
||||
|
||||
func TestSubmitUpdate(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 := Service{
|
||||
db: db,
|
||||
}
|
||||
|
||||
j := Job{
|
||||
ID: uuid.New(),
|
||||
}
|
||||
u := &Update{
|
||||
ID: j.ID,
|
||||
}
|
||||
|
||||
pool.ExpectBegin()
|
||||
pool.ExpectCommit()
|
||||
|
||||
err = svc.submitUpdate(ctx, u)
|
||||
assert.Nil(t, err)
|
||||
|
||||
ucs := true
|
||||
u = &Update{
|
||||
ID: j.ID,
|
||||
CanSync: &ucs,
|
||||
}
|
||||
|
||||
pool.ExpectBegin()
|
||||
pool.ExpectExec("name: AddJobCanSync :exec").WithArgs(*u.CanSync, database.MustToDBUUID(j.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectCommit()
|
||||
|
||||
err = svc.submitUpdate(ctx, u)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user