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
+130 -61
View File
@@ -43,6 +43,21 @@ const (
JSONEXTRACTOR QueryType = "JSON_EXTRACTOR"
)
// ClientCreate defines model for ClientCreate.
type ClientCreate struct {
// Name The client name
Name string `json:"name"`
}
// ClientUpdate defines model for ClientUpdate.
type ClientUpdate struct {
// CanSync If the client is allowing active syncs
CanSync *bool `json:"can_sync,omitempty"`
// Name The client name
Name *string `json:"name,omitempty"`
}
// ExportDetails Payload for export trigger response.
type ExportDetails struct {
// JobId The job id relative to the export.
@@ -97,6 +112,18 @@ type IdMessage struct {
Id string `json:"id"`
}
// JobClient defines model for JobClient.
type JobClient struct {
// CanSync If the client is allowing active syncs
CanSync bool `json:"can_sync"`
// Id The client id
Id string `json:"id"`
// Name The client name
Name string `json:"name"`
}
// JobCollector JobCollector model.
type JobCollector struct {
// ActiveVersion The active version of the collector.
@@ -211,6 +238,12 @@ type QueryUpdate struct {
RequiredQueries *[]string `json:"required_queries,omitempty"`
}
// CreateClientJSONRequestBody defines body for CreateClient for application/json ContentType.
type CreateClientJSONRequestBody = ClientCreate
// UpdateClientJSONRequestBody defines body for UpdateClient for application/json ContentType.
type UpdateClientJSONRequestBody = ClientUpdate
// TriggerExportJSONRequestBody defines body for TriggerExport for application/json ContentType.
type TriggerExportJSONRequestBody = ExportTrigger
@@ -228,6 +261,15 @@ type TestQueryJSONRequestBody = QueryTestRequest
// ServerInterface represents all server handlers.
type ServerInterface interface {
// Create a new client
// (POST /clients)
CreateClient(ctx echo.Context) error
// Get a client by ID
// (GET /clients/{id})
GetClient(ctx echo.Context, id string) error
// Update a client
// (PATCH /clients/{id})
UpdateClient(ctx echo.Context, id string) error
// Trigger an export
// (POST /job/export)
TriggerExport(ctx echo.Context) error
@@ -246,12 +288,9 @@ type ServerInterface interface {
// Create a new query
// (POST /queries)
CreateQuery(ctx echo.Context) error
// Deprecate a query
// (DELETE /queries/{id})
DeprecateQuery(ctx echo.Context, id string) error
// Get a query by ID
// (GET /queries/{id})
GetQueryById(ctx echo.Context, id string) error
GetQuery(ctx echo.Context, id string) error
// Update a query
// (PATCH /queries/{id})
UpdateQuery(ctx echo.Context, id string) error
@@ -265,6 +304,47 @@ type ServerInterfaceWrapper struct {
Handler ServerInterface
}
// CreateClient converts echo context to params.
func (w *ServerInterfaceWrapper) CreateClient(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.CreateClient(ctx)
return err
}
// GetClient converts echo context to params.
func (w *ServerInterfaceWrapper) GetClient(ctx echo.Context) error {
var err error
// ------------- Path parameter "id" -------------
var id string
err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.GetClient(ctx, id)
return err
}
// UpdateClient converts echo context to params.
func (w *ServerInterfaceWrapper) UpdateClient(ctx echo.Context) error {
var err error
// ------------- Path parameter "id" -------------
var id string
err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.UpdateClient(ctx, id)
return err
}
// TriggerExport converts echo context to params.
func (w *ServerInterfaceWrapper) TriggerExport(ctx echo.Context) error {
var err error
@@ -340,8 +420,8 @@ func (w *ServerInterfaceWrapper) CreateQuery(ctx echo.Context) error {
return err
}
// DeprecateQuery converts echo context to params.
func (w *ServerInterfaceWrapper) DeprecateQuery(ctx echo.Context) error {
// GetQuery converts echo context to params.
func (w *ServerInterfaceWrapper) GetQuery(ctx echo.Context) error {
var err error
// ------------- Path parameter "id" -------------
var id string
@@ -352,23 +432,7 @@ func (w *ServerInterfaceWrapper) DeprecateQuery(ctx echo.Context) error {
}
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.DeprecateQuery(ctx, id)
return err
}
// GetQueryById converts echo context to params.
func (w *ServerInterfaceWrapper) GetQueryById(ctx echo.Context) error {
var err error
// ------------- Path parameter "id" -------------
var id string
err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.GetQueryById(ctx, id)
err = w.Handler.GetQuery(ctx, id)
return err
}
@@ -432,14 +496,16 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
Handler: si,
}
router.POST(baseURL+"/clients", wrapper.CreateClient)
router.GET(baseURL+"/clients/:id", wrapper.GetClient)
router.PATCH(baseURL+"/clients/:id", wrapper.UpdateClient)
router.POST(baseURL+"/job/export", wrapper.TriggerExport)
router.GET(baseURL+"/job/export/:id", wrapper.ExportState)
router.GET(baseURL+"/job/:id/collector", wrapper.GetJobCollectorByJobId)
router.PATCH(baseURL+"/job/:id/collector", wrapper.UpdateJobCollectorByJobId)
router.GET(baseURL+"/queries", wrapper.ListQueries)
router.POST(baseURL+"/queries", wrapper.CreateQuery)
router.DELETE(baseURL+"/queries/:id", wrapper.DeprecateQuery)
router.GET(baseURL+"/queries/:id", wrapper.GetQueryById)
router.GET(baseURL+"/queries/:id", wrapper.GetQuery)
router.PATCH(baseURL+"/queries/:id", wrapper.UpdateQuery)
router.POST(baseURL+"/queries/:id/test", wrapper.TestQuery)
@@ -448,42 +514,45 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"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",
"UleSoTLDcCUS1p6q7L7u/h8AAP//+pSl8AgsAAA=",
"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",
"AA==",
}
// GetSwagger returns the content of the embedded swagger specification file
+67
View File
@@ -0,0 +1,67 @@
package queryservice
import (
"fmt"
"net/http"
"queryorchestration/internal/client"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
)
func (s *Controllers) CreateClient(ctx echo.Context) error {
req := ClientCreate{}
if err := ctx.Bind(&req); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err)
}
id, err := s.svc.Client.Create(ctx.Request().Context(), req.Name)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unable to create client: %s", err))
}
return ctx.JSON(http.StatusCreated, IdMessage{
Id: id.String(),
})
}
func (s *Controllers) GetClient(ctx echo.Context, id string) error {
uid, err := uuid.Parse(id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid ID")
}
client, err := s.svc.Client.Get(ctx.Request().Context(), uid)
if err != nil {
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("Unable to get client: %s", err))
}
return ctx.JSON(http.StatusOK, JobClient{
Id: client.ID.String(),
Name: client.Name,
CanSync: client.CanSync,
})
}
func (s *Controllers) UpdateClient(ctx echo.Context, id string) error {
req := ClientUpdate{}
if err := ctx.Bind(&req); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err)
}
uid, err := uuid.Parse(id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid ID")
}
err = s.svc.Client.Update(ctx.Request().Context(), &client.Update{
ID: uid,
Name: req.Name,
CanSync: req.CanSync,
})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unable to update query: %s", err))
}
return ctx.NoContent(http.StatusOK)
}
+146
View File
@@ -0,0 +1,146 @@
package queryservice_test
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
queryservice "queryorchestration/api/queryService"
"queryorchestration/internal/client"
"queryorchestration/internal/database"
"queryorchestration/internal/database/repository"
"strings"
"testing"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"github.com/pashagolub/pgxmock/v3"
"github.com/stretchr/testify/assert"
)
func TestCreateClient(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,
}
cons := queryservice.NewControllers(validator.New(), &queryservice.Services{
Client: client.New(db),
})
body := queryservice.ClientCreate{
Name: "example_name",
}
bodyBytes, err := json.Marshal(body)
assert.Nil(t, err)
e := echo.New()
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(string(bodyBytes)))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
ctx := e.NewContext(req, rec)
id := uuid.New()
pool.ExpectQuery("-- name: CreateClient :one").WithArgs(body.Name).WillReturnRows(
pgxmock.NewRows([]string{"id"}).
AddRow(database.MustToDBUUID(id)),
)
err = cons.CreateClient(ctx)
assert.Nil(t, err)
assert.Equal(t, http.StatusCreated, rec.Code)
assert.Equal(t, fmt.Sprintf("{\"id\":\"%s\"}\n", id), rec.Body.String())
}
func TestGetClient(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,
}
cons := queryservice.NewControllers(validator.New(), &queryservice.Services{
Client: client.New(db),
})
e := echo.New()
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(""))
rec := httptest.NewRecorder()
ctx := e.NewContext(req, rec)
id := uuid.New()
ctx.Set("id", id)
pool.ExpectQuery("-- name: GetClient :one").WithArgs(database.MustToDBUUID(id)).WillReturnRows(
pgxmock.NewRows([]string{"id", "name", "canSync"}).
AddRow(database.MustToDBUUID(id), "client_name", true),
)
err = cons.GetClient(ctx, id.String())
assert.Nil(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
var res queryservice.JobClient
err = json.Unmarshal(rec.Body.Bytes(), &res)
assert.Nil(t, err)
assert.EqualExportedValues(t, queryservice.JobClient{
Id: id.String(),
Name: "client_name",
CanSync: true,
}, res)
}
func TestUpdateClient(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,
}
cons := queryservice.NewControllers(validator.New(), &queryservice.Services{
Client: client.New(db),
})
body := queryservice.QueryUpdate{}
bodyBytes, err := json.Marshal(body)
assert.Nil(t, err)
e := echo.New()
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(string(bodyBytes)))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
ctx := e.NewContext(req, rec)
id := uuid.New()
ctx.Set("id", id)
pool.ExpectQuery("-- name: GetClient :one").WithArgs(database.MustToDBUUID(id)).WillReturnRows(
pgxmock.NewRows([]string{"id", "name", "canSync"}).
AddRow(database.MustToDBUUID(id), "client_name", true),
)
pool.ExpectExec("name: UpdateClient :exec").WithArgs("client_name", true, database.MustToDBUUID(id)).
WillReturnResult(pgxmock.NewResult("", 1))
err = cons.UpdateClient(ctx, id.String())
assert.Nil(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
assert.Empty(t, rec.Body.String())
}
+2
View File
@@ -1,6 +1,7 @@
package queryservice
import (
"queryorchestration/internal/client"
"queryorchestration/internal/export"
"queryorchestration/internal/job/collector"
"queryorchestration/internal/query"
@@ -12,6 +13,7 @@ type Services struct {
Export *export.Service
JobCollector *collector.Service
Query *query.Service
Client *client.Service
}
type Controllers struct {
+1 -15
View File
@@ -28,7 +28,7 @@ func (s *Controllers) ListQueries(ctx echo.Context) error {
})
}
func (s *Controllers) GetQueryById(ctx echo.Context, id string) error {
func (s *Controllers) GetQuery(ctx echo.Context, id string) error {
uid, err := uuid.Parse(id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid ID")
@@ -106,20 +106,6 @@ func (s *Controllers) UpdateQuery(ctx echo.Context, id string) error {
return ctx.NoContent(http.StatusOK)
}
func (s *Controllers) DeprecateQuery(ctx echo.Context, id string) error {
uid, err := uuid.Parse(id)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid ID")
}
err = s.svc.Query.Deprecate(ctx.Request().Context(), uid)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unable to deprecate query: %s", err))
}
return ctx.NoContent(http.StatusOK)
}
func (s *Controllers) TestQuery(ctx echo.Context, id string) error {
queryId, err := uuid.Parse(id)
if err != nil {
+2 -35
View File
@@ -21,39 +21,6 @@ import (
"github.com/stretchr/testify/assert"
)
func TestDeprecateQuery(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,
}
cons := queryservice.NewControllers(validator.New(), &queryservice.Services{
Query: query.New(db),
})
id := uuid.New()
e := echo.New()
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(""))
rec := httptest.NewRecorder()
ctx := e.NewContext(req, rec)
pool.ExpectQuery("-- name: IsQueryDeprecated :one").WithArgs(database.MustToDBUUID(id)).WillReturnRows(
pgxmock.NewRows([]string{"isdeprecated"}).
AddRow(true),
)
err = cons.DeprecateQuery(ctx, id.String())
assert.Nil(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
assert.Empty(t, rec.Body.String())
}
func TestCreateQuery(t *testing.T) {
pool, err := pgxmock.NewPool()
if err != nil {
@@ -141,7 +108,7 @@ func TestListQueries(t *testing.T) {
})
}
func TestGetQueryById(t *testing.T) {
func TestGetQuery(t *testing.T) {
pool, err := pgxmock.NewPool()
if err != nil {
t.Fatalf("failed to open pgxmock database: %v", err)
@@ -170,7 +137,7 @@ func TestGetQueryById(t *testing.T) {
AddRow(database.MustToDBUUID(id), repository.QuerytypeContextFull, int32(1), int32(2), nil, []pgtype.UUID{}),
)
err = cons.GetQueryById(ctx, id.String())
err = cons.GetQuery(ctx, id.String())
assert.Nil(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
+3
View File
@@ -4,6 +4,7 @@ import (
"context"
"log"
queryservice "queryorchestration/api/queryService"
"queryorchestration/internal/client"
"queryorchestration/internal/export"
"queryorchestration/internal/job/collector"
"queryorchestration/internal/query"
@@ -21,11 +22,13 @@ func main() {
exp := export.New(cfg.Database)
col := collector.New(cfg.Database)
que := query.New(cfg.Database)
cli := client.New(cfg.Database)
services := &queryservice.Services{
Export: exp,
JobCollector: col,
Query: que,
Client: cli,
}
cons := queryservice.NewControllers(cfg.Validator, services)
@@ -0,0 +1 @@
DROP TABLE clients;
@@ -0,0 +1,6 @@
CREATE TABLE clients (
id uuid primary key DEFAULT gen_random_uuid(),
name TEXT not null,
canSync boolean not null default false,
UNIQUE (name)
);
@@ -1 +0,0 @@
DROP TABLE queryDeprecations;
@@ -1,8 +0,0 @@
CREATE TABLE queryDeprecations (
id uuid primary key DEFAULT gen_random_uuid(),
queryId uuid not null,
time timestamp not null DEFAULT NOW(),
removedAt timestamp,
foreign key (queryId) references queries(id),
unique (queryId, removedAt)
);
+8
View File
@@ -0,0 +1,8 @@
-- name: CreateClient :one
INSERT INTO clients (name) VALUES ($1) RETURNING id;
-- name: GetClient :one
SELECT id, name, canSync FROM clients WHERE id = $1;
-- name: UpdateClient :exec
UPDATE clients SET name = $1, canSync = $2 WHERE id = $3;
-8
View File
@@ -1,14 +1,6 @@
-- name: GetQueryConfig :one
SELECT id, config FROM queryConfigs where queryId = $1 and addedVersion >= $2 and COALESCE(removedVersion, $2 - 1) < $2;
-- name: DeprecateQuery :exec
INSERT INTO queryDeprecations (queryId) VALUES ($1);
-- name: IsQueryDeprecated :one
SELECT EXISTS (
SELECT 1 FROM queryDeprecations where queryId = $1 and removedAt is null LIMIT 1
);
-- name: GetQuery :one
SELECT * FROM fullActiveQueries WHERE id = $1;
+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)
}
@@ -0,0 +1,58 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: client.sql
package repository
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const createClient = `-- name: CreateClient :one
INSERT INTO clients (name) VALUES ($1) RETURNING id
`
// CreateClient
//
// INSERT INTO clients (name) VALUES ($1) RETURNING id
func (q *Queries) CreateClient(ctx context.Context, name string) (pgtype.UUID, error) {
row := q.db.QueryRow(ctx, createClient, name)
var id pgtype.UUID
err := row.Scan(&id)
return id, err
}
const getClient = `-- name: GetClient :one
SELECT id, name, canSync FROM clients WHERE id = $1
`
// 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
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
`
type UpdateClientParams struct {
Name string `db:"name"`
Cansync bool `db:"cansync"`
ID pgtype.UUID `db:"id"`
}
// UpdateClient
//
// UPDATE clients SET name = $1, canSync = $2 WHERE id = $3
func (q *Queries) UpdateClient(ctx context.Context, arg *UpdateClientParams) error {
_, err := q.db.Exec(ctx, updateClient, arg.Name, arg.Cansync, arg.ID)
return err
}
@@ -0,0 +1,51 @@
package repository_test
import (
"context"
"os"
"path"
"queryorchestration/internal/database"
"queryorchestration/internal/database/repository"
"queryorchestration/internal/test"
"testing"
"github.com/stretchr/testify/assert"
)
func TestClient(t *testing.T) {
ctx := context.Background()
db, cleanup := test.CreateDB(t, ctx, &test.CreateDatabaseConfig{
Migrations: &database.MigrationConfig{
BasePath: path.Join(os.Getenv("PWD"), "../../.."),
}})
defer cleanup()
queries := repository.New(db.Pool)
id, err := queries.CreateClient(ctx, "example_client")
assert.Nil(t, err)
assert.NotEmpty(t, id)
client, err := queries.GetClient(ctx, id)
assert.Nil(t, err)
assert.EqualExportedValues(t, &repository.Client{
ID: id,
Name: "example_client",
Cansync: false,
}, client)
err = queries.UpdateClient(ctx, &repository.UpdateClientParams{
ID: id,
Name: "updated_client",
Cansync: true,
})
assert.Nil(t, err)
client, err = queries.GetClient(ctx, id)
assert.Nil(t, err)
assert.EqualExportedValues(t, &repository.Client{
ID: id,
Name: "updated_client",
Cansync: true,
}, client)
}
@@ -49,25 +49,25 @@ func TestCollector(t *testing.T) {
coll, err := queries.GetCollector(ctx, collId)
assert.Nil(t, err)
assert.EqualExportedValues(t, repository.Fullactivecollector{
assert.EqualExportedValues(t, &repository.Fullactivecollector{
ID: collId,
Jobid: jobId,
Mincleanversion: minCleanVersion,
Mintextversion: minTextVersion,
Activeversion: 1,
Latestversion: 1,
}, *coll)
}, coll)
coll, err = queries.GetCollectorByJobID(ctx, jobId)
assert.Nil(t, err)
assert.EqualExportedValues(t, repository.Fullactivecollector{
assert.EqualExportedValues(t, &repository.Fullactivecollector{
ID: collId,
Jobid: jobId,
Mincleanversion: minCleanVersion,
Mintextversion: minTextVersion,
Activeversion: 1,
Latestversion: 1,
}, *coll)
}, coll)
err = queries.AddCollectorQuery(ctx, &repository.AddCollectorQueryParams{
Collectorid: collId,
@@ -79,7 +79,7 @@ func TestCollector(t *testing.T) {
coll, err = queries.GetCollector(ctx, collId)
assert.Nil(t, err)
assert.EqualExportedValues(t, repository.Fullactivecollector{
assert.EqualExportedValues(t, &repository.Fullactivecollector{
ID: collId,
Jobid: jobId,
Mincleanversion: minCleanVersion,
@@ -87,7 +87,7 @@ func TestCollector(t *testing.T) {
Activeversion: 1,
Latestversion: 1,
Fields: []byte(fmt.Sprintf("{\"example_key\": \"%s\"}", database.MustToUUID(jsonId).String())),
}, *coll)
}, coll)
qs, err := queries.ListCollectorQueries(ctx, collId)
assert.Nil(t, err)
+6 -7
View File
@@ -68,6 +68,12 @@ type Activecollectorswithrequiredid struct {
Queryids interface{} `db:"queryids"`
}
type Client struct {
ID pgtype.UUID `db:"id"`
Name string `db:"name"`
Cansync bool `db:"cansync"`
}
type Collector struct {
ID pgtype.UUID `db:"id"`
Jobid pgtype.UUID `db:"jobid"`
@@ -128,13 +134,6 @@ type Queryconfig struct {
Removedversion *int32 `db:"removedversion"`
}
type Querydeprecation struct {
ID pgtype.UUID `db:"id"`
Queryid pgtype.UUID `db:"queryid"`
Time pgtype.Timestamp `db:"time"`
Removedat pgtype.Timestamp `db:"removedat"`
}
type Requiredquery struct {
ID pgtype.UUID `db:"id"`
Queryid pgtype.UUID `db:"queryid"`
-30
View File
@@ -79,18 +79,6 @@ func (q *Queries) CreateQuery(ctx context.Context, type_ Querytype) (pgtype.UUID
return id, err
}
const deprecateQuery = `-- name: DeprecateQuery :exec
INSERT INTO queryDeprecations (queryId) VALUES ($1)
`
// DeprecateQuery
//
// INSERT INTO queryDeprecations (queryId) VALUES ($1)
func (q *Queries) DeprecateQuery(ctx context.Context, queryid pgtype.UUID) error {
_, err := q.db.Exec(ctx, deprecateQuery, queryid)
return err
}
const getQuery = `-- name: GetQuery :one
SELECT id, type, activeversion, latestversion, config, requiredids FROM fullActiveQueries WHERE id = $1
`
@@ -136,24 +124,6 @@ func (q *Queries) GetQueryConfig(ctx context.Context, arg *GetQueryConfigParams)
return &i, err
}
const isQueryDeprecated = `-- name: IsQueryDeprecated :one
SELECT EXISTS (
SELECT 1 FROM queryDeprecations where queryId = $1 and removedAt is null LIMIT 1
)
`
// IsQueryDeprecated
//
// SELECT EXISTS (
// SELECT 1 FROM queryDeprecations where queryId = $1 and removedAt is null LIMIT 1
// )
func (q *Queries) IsQueryDeprecated(ctx context.Context, queryid pgtype.UUID) (bool, error) {
row := q.db.QueryRow(ctx, isQueryDeprecated, queryid)
var exists bool
err := row.Scan(&exists)
return exists, err
}
const listQueries = `-- name: ListQueries :many
SELECT id, type, activeversion, latestversion, config, requiredids FROM fullActiveQueries
`
+6 -17
View File
@@ -35,14 +35,14 @@ func TestQueries(t *testing.T) {
jsonQuery, err := queries.GetQuery(ctx, jsonQueryID)
assert.Nil(t, err)
assert.EqualExportedValues(t, repository.Fullactivequery{
assert.EqualExportedValues(t, &repository.Fullactivequery{
ID: jsonQueryID,
Type: repository.QuerytypeJsonExtractor,
Activeversion: 1,
Latestversion: 1,
Config: nil,
Requiredids: []pgtype.UUID{database.MustToDBUUID(uuid.Nil)},
}, *jsonQuery)
}, jsonQuery)
err = queries.UpdateQuery(ctx, &repository.UpdateQueryParams{
Latestversion: 2,
@@ -97,14 +97,14 @@ func TestQueries(t *testing.T) {
jsonQuery, err = queries.GetQuery(ctx, jsonQueryID)
assert.Nil(t, err)
assert.EqualExportedValues(t, repository.Fullactivequery{
assert.EqualExportedValues(t, &repository.Fullactivequery{
ID: jsonQueryID,
Type: repository.QuerytypeJsonExtractor,
Activeversion: 1,
Latestversion: 2,
Config: jsonConfig,
Requiredids: []pgtype.UUID{contextQueryID},
}, *jsonQuery)
}, jsonQuery)
err = queries.UpdateQuery(ctx, &repository.UpdateQueryParams{
Activeversion: 2,
@@ -115,14 +115,14 @@ func TestQueries(t *testing.T) {
jsonQuery, err = queries.GetQuery(ctx, jsonQueryID)
assert.Nil(t, err)
assert.EqualExportedValues(t, repository.Fullactivequery{
assert.EqualExportedValues(t, &repository.Fullactivequery{
ID: jsonQueryID,
Type: repository.QuerytypeJsonExtractor,
Activeversion: 2,
Latestversion: 2,
Config: nil,
Requiredids: []pgtype.UUID{database.MustToDBUUID(uuid.Nil)},
}, *jsonQuery)
}, jsonQuery)
all_exist, err := queries.AllQueriesExist(ctx, []pgtype.UUID{})
assert.Nil(t, err)
@@ -143,17 +143,6 @@ func TestQueries(t *testing.T) {
all_exist, err = queries.AllQueriesExist(ctx, []pgtype.UUID{jsonQueryID, database.MustToDBUUID(uuid.New())})
assert.Nil(t, err)
assert.False(t, all_exist)
isDeprecated, err := queries.IsQueryDeprecated(ctx, jsonQueryID)
assert.Nil(t, err)
assert.False(t, isDeprecated)
err = queries.DeprecateQuery(ctx, jsonQueryID)
assert.Nil(t, err)
isDeprecated, err = queries.IsQueryDeprecated(ctx, jsonQueryID)
assert.Nil(t, err)
assert.True(t, isDeprecated)
}
func TestQueriesList(t *testing.T) {
-2
View File
@@ -176,10 +176,8 @@ func TestNormalizeCreate(t *testing.T) {
}
svc := New(db)
cfg := "{}"
create := &queryprocessor.Create{
Type: queryprocessor.TypeJsonExtractor,
Config: &cfg,
RequiredQueryIDs: &[]uuid.UUID{},
}
-26
View File
@@ -1,26 +0,0 @@
package query
import (
"context"
"queryorchestration/internal/database"
"github.com/google/uuid"
)
func (s *Service) Deprecate(ctx context.Context, id uuid.UUID) error {
dbId := database.MustToDBUUID(id)
exists, err := s.db.Queries.IsQueryDeprecated(ctx, dbId)
if err != nil {
return err
} else if exists {
return nil
}
err = s.db.Queries.DeprecateQuery(ctx, dbId)
if err != nil {
return err
}
return nil
}
-66
View File
@@ -1,66 +0,0 @@
package query_test
import (
"context"
"errors"
"queryorchestration/internal/database"
"queryorchestration/internal/database/repository"
"queryorchestration/internal/query"
"testing"
"github.com/google/uuid"
"github.com/pashagolub/pgxmock/v3"
"github.com/stretchr/testify/assert"
)
func TestDeprecate(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 := query.New(db)
id := uuid.New()
pool.ExpectQuery("name: IsQueryDeprecated :one").WithArgs(database.MustToDBUUID(id)).WillReturnRows(
pgxmock.NewRows([]string{"exists"}).
AddRow(false),
)
pool.ExpectExec("name: DeprecateQuery :exec").WithArgs(database.MustToDBUUID(id)).
WillReturnResult(pgxmock.NewResult("", 1))
err = svc.Deprecate(ctx, id)
assert.Nil(t, err)
pool.ExpectQuery("name: IsQueryDeprecated :one").WithArgs(database.MustToDBUUID(id)).WillReturnRows(
pgxmock.NewRows([]string{"exists"}).
AddRow(true),
)
err = svc.Deprecate(ctx, id)
assert.Nil(t, err)
pool.ExpectQuery("name: IsQueryDeprecated :one").WithArgs(database.MustToDBUUID(id)).WillReturnRows(
pgxmock.NewRows([]string{"exists"}),
)
err = svc.Deprecate(ctx, id)
assert.NotNil(t, err)
pool.ExpectQuery("name: IsQueryDeprecated :one").WithArgs(database.MustToDBUUID(id)).WillReturnRows(
pgxmock.NewRows([]string{"exists"}).
AddRow(false),
)
pool.ExpectExec("name: DeprecateQuery :exec").WithArgs(database.MustToDBUUID(id)).
WillReturnError(errors.New("unable to deprecate query"))
err = svc.Deprecate(ctx, id)
assert.NotNil(t, err)
}
+1 -5
View File
@@ -45,11 +45,7 @@ func (s *Service) normalizeConfig(config Config) error {
strJSON := string(prettyJSON)
if strJSON == "{}" {
config.SetConfig(nil)
} else {
config.SetConfig(&strJSON)
}
config.SetConfig(&strJSON)
return nil
}
+1 -1
View File
@@ -42,7 +42,7 @@ func TestNormalizeConfig(t *testing.T) {
entity.Config = &cfg
err = s.normalizeConfig(&entity)
assert.Nil(t, err)
assert.Nil(t, entity.Config)
assert.Equal(t, "{}", *(entity.Config))
cfg = "{\"hello\":\"bye\"}"
entity.Config = &cfg
+1 -1
View File
@@ -297,7 +297,7 @@ func TestNormalizeUpdate(t *testing.T) {
assert.EqualExportedValues(t, queryprocessor.Update{
ID: current.ID,
ActiveVersion: &aV,
Config: nil,
Config: &cfg,
RequiredQueryIDs: nil,
}, *update)
}
+434 -116
View File
@@ -41,6 +41,21 @@ const (
JSONEXTRACTOR QueryType = "JSON_EXTRACTOR"
)
// ClientCreate defines model for ClientCreate.
type ClientCreate struct {
// Name The client name
Name string `json:"name"`
}
// ClientUpdate defines model for ClientUpdate.
type ClientUpdate struct {
// CanSync If the client is allowing active syncs
CanSync *bool `json:"can_sync,omitempty"`
// Name The client name
Name *string `json:"name,omitempty"`
}
// ExportDetails Payload for export trigger response.
type ExportDetails struct {
// JobId The job id relative to the export.
@@ -95,6 +110,18 @@ type IdMessage struct {
Id string `json:"id"`
}
// JobClient defines model for JobClient.
type JobClient struct {
// CanSync If the client is allowing active syncs
CanSync bool `json:"can_sync"`
// Id The client id
Id string `json:"id"`
// Name The client name
Name string `json:"name"`
}
// JobCollector JobCollector model.
type JobCollector struct {
// ActiveVersion The active version of the collector.
@@ -209,6 +236,12 @@ type QueryUpdate struct {
RequiredQueries *[]string `json:"required_queries,omitempty"`
}
// CreateClientJSONRequestBody defines body for CreateClient for application/json ContentType.
type CreateClientJSONRequestBody = ClientCreate
// UpdateClientJSONRequestBody defines body for UpdateClient for application/json ContentType.
type UpdateClientJSONRequestBody = ClientUpdate
// TriggerExportJSONRequestBody defines body for TriggerExport for application/json ContentType.
type TriggerExportJSONRequestBody = ExportTrigger
@@ -297,6 +330,19 @@ func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
// The interface specification for the client above.
type ClientInterface interface {
// CreateClientWithBody request with any body
CreateClientWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
CreateClient(ctx context.Context, body CreateClientJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
// GetClient request
GetClient(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error)
// UpdateClientWithBody request with any body
UpdateClientWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
UpdateClient(ctx context.Context, id string, body UpdateClientJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
// TriggerExportWithBody request with any body
TriggerExportWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -321,11 +367,8 @@ type ClientInterface interface {
CreateQuery(ctx context.Context, body CreateQueryJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
// DeprecateQuery request
DeprecateQuery(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error)
// GetQueryById request
GetQueryById(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error)
// GetQuery request
GetQuery(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error)
// UpdateQueryWithBody request with any body
UpdateQueryWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -338,6 +381,66 @@ type ClientInterface interface {
TestQuery(ctx context.Context, id string, body TestQueryJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
}
func (c *Client) CreateClientWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewCreateClientRequestWithBody(c.Server, contentType, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *Client) CreateClient(ctx context.Context, body CreateClientJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewCreateClientRequest(c.Server, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *Client) GetClient(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetClientRequest(c.Server, id)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *Client) UpdateClientWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewUpdateClientRequestWithBody(c.Server, id, contentType, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *Client) UpdateClient(ctx context.Context, id string, body UpdateClientJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewUpdateClientRequest(c.Server, id, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *Client) TriggerExportWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewTriggerExportRequestWithBody(c.Server, contentType, body)
if err != nil {
@@ -446,20 +549,8 @@ func (c *Client) CreateQuery(ctx context.Context, body CreateQueryJSONRequestBod
return c.Client.Do(req)
}
func (c *Client) DeprecateQuery(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewDeprecateQueryRequest(c.Server, id)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *Client) GetQueryById(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetQueryByIdRequest(c.Server, id)
func (c *Client) GetQuery(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetQueryRequest(c.Server, id)
if err != nil {
return nil, err
}
@@ -518,6 +609,127 @@ func (c *Client) TestQuery(ctx context.Context, id string, body TestQueryJSONReq
return c.Client.Do(req)
}
// NewCreateClientRequest calls the generic CreateClient builder with application/json body
func NewCreateClientRequest(server string, body CreateClientJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
buf, err := json.Marshal(body)
if err != nil {
return nil, err
}
bodyReader = bytes.NewReader(buf)
return NewCreateClientRequestWithBody(server, "application/json", bodyReader)
}
// NewCreateClientRequestWithBody generates requests for CreateClient with any type of body
func NewCreateClientRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
var err error
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
operationPath := fmt.Sprintf("/clients")
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", queryURL.String(), body)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", contentType)
return req, nil
}
// NewGetClientRequest generates requests for GetClient
func NewGetClientRequest(server string, id string) (*http.Request, error) {
var err error
var pathParam0 string
pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id)
if err != nil {
return nil, err
}
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
operationPath := fmt.Sprintf("/clients/%s", pathParam0)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
req, err := http.NewRequest("GET", queryURL.String(), nil)
if err != nil {
return nil, err
}
return req, nil
}
// NewUpdateClientRequest calls the generic UpdateClient builder with application/json body
func NewUpdateClientRequest(server string, id string, body UpdateClientJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
buf, err := json.Marshal(body)
if err != nil {
return nil, err
}
bodyReader = bytes.NewReader(buf)
return NewUpdateClientRequestWithBody(server, id, "application/json", bodyReader)
}
// NewUpdateClientRequestWithBody generates requests for UpdateClient with any type of body
func NewUpdateClientRequestWithBody(server string, id string, contentType string, body io.Reader) (*http.Request, error) {
var err error
var pathParam0 string
pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id)
if err != nil {
return nil, err
}
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
operationPath := fmt.Sprintf("/clients/%s", pathParam0)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
req, err := http.NewRequest("PATCH", queryURL.String(), body)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", contentType)
return req, nil
}
// NewTriggerExportRequest calls the generic TriggerExport builder with application/json body
func NewTriggerExportRequest(server string, body TriggerExportJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
@@ -740,42 +952,8 @@ func NewCreateQueryRequestWithBody(server string, contentType string, body io.Re
return req, nil
}
// NewDeprecateQueryRequest generates requests for DeprecateQuery
func NewDeprecateQueryRequest(server string, id string) (*http.Request, error) {
var err error
var pathParam0 string
pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id)
if err != nil {
return nil, err
}
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
operationPath := fmt.Sprintf("/queries/%s", pathParam0)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
req, err := http.NewRequest("DELETE", queryURL.String(), nil)
if err != nil {
return nil, err
}
return req, nil
}
// NewGetQueryByIdRequest generates requests for GetQueryById
func NewGetQueryByIdRequest(server string, id string) (*http.Request, error) {
// NewGetQueryRequest generates requests for GetQuery
func NewGetQueryRequest(server string, id string) (*http.Request, error) {
var err error
var pathParam0 string
@@ -945,6 +1123,19 @@ func WithBaseURL(baseURL string) ClientOption {
// ClientWithResponsesInterface is the interface specification for the client with responses above.
type ClientWithResponsesInterface interface {
// CreateClientWithBodyWithResponse request with any body
CreateClientWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateClientResponse, error)
CreateClientWithResponse(ctx context.Context, body CreateClientJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateClientResponse, error)
// GetClientWithResponse request
GetClientWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetClientResponse, error)
// UpdateClientWithBodyWithResponse request with any body
UpdateClientWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error)
UpdateClientWithResponse(ctx context.Context, id string, body UpdateClientJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error)
// TriggerExportWithBodyWithResponse request with any body
TriggerExportWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*TriggerExportResponse, error)
@@ -969,11 +1160,8 @@ type ClientWithResponsesInterface interface {
CreateQueryWithResponse(ctx context.Context, body CreateQueryJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateQueryResponse, error)
// DeprecateQueryWithResponse request
DeprecateQueryWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeprecateQueryResponse, error)
// GetQueryByIdWithResponse request
GetQueryByIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetQueryByIdResponse, error)
// GetQueryWithResponse request
GetQueryWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetQueryResponse, error)
// UpdateQueryWithBodyWithResponse request with any body
UpdateQueryWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateQueryResponse, error)
@@ -986,6 +1174,71 @@ type ClientWithResponsesInterface interface {
TestQueryWithResponse(ctx context.Context, id string, body TestQueryJSONRequestBody, reqEditors ...RequestEditorFn) (*TestQueryResponse, error)
}
type CreateClientResponse struct {
Body []byte
HTTPResponse *http.Response
JSON201 *IdMessage
}
// Status returns HTTPResponse.Status
func (r CreateClientResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
return http.StatusText(0)
}
// StatusCode returns HTTPResponse.StatusCode
func (r CreateClientResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
type GetClientResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *JobClient
}
// Status returns HTTPResponse.Status
func (r GetClientResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
return http.StatusText(0)
}
// StatusCode returns HTTPResponse.StatusCode
func (r GetClientResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
type UpdateClientResponse struct {
Body []byte
HTTPResponse *http.Response
}
// Status returns HTTPResponse.Status
func (r UpdateClientResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
return http.StatusText(0)
}
// StatusCode returns HTTPResponse.StatusCode
func (r UpdateClientResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
type TriggerExportResponse struct {
Body []byte
HTTPResponse *http.Response
@@ -1117,35 +1370,14 @@ func (r CreateQueryResponse) StatusCode() int {
return 0
}
type DeprecateQueryResponse struct {
Body []byte
HTTPResponse *http.Response
}
// Status returns HTTPResponse.Status
func (r DeprecateQueryResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
return http.StatusText(0)
}
// StatusCode returns HTTPResponse.StatusCode
func (r DeprecateQueryResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
type GetQueryByIdResponse struct {
type GetQueryResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *Query
}
// Status returns HTTPResponse.Status
func (r GetQueryByIdResponse) Status() string {
func (r GetQueryResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -1153,7 +1385,7 @@ func (r GetQueryByIdResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
func (r GetQueryByIdResponse) StatusCode() int {
func (r GetQueryResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
@@ -1203,6 +1435,49 @@ func (r TestQueryResponse) StatusCode() int {
return 0
}
// CreateClientWithBodyWithResponse request with arbitrary body returning *CreateClientResponse
func (c *ClientWithResponses) CreateClientWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateClientResponse, error) {
rsp, err := c.CreateClientWithBody(ctx, contentType, body, reqEditors...)
if err != nil {
return nil, err
}
return ParseCreateClientResponse(rsp)
}
func (c *ClientWithResponses) CreateClientWithResponse(ctx context.Context, body CreateClientJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateClientResponse, error) {
rsp, err := c.CreateClient(ctx, body, reqEditors...)
if err != nil {
return nil, err
}
return ParseCreateClientResponse(rsp)
}
// GetClientWithResponse request returning *GetClientResponse
func (c *ClientWithResponses) GetClientWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetClientResponse, error) {
rsp, err := c.GetClient(ctx, id, reqEditors...)
if err != nil {
return nil, err
}
return ParseGetClientResponse(rsp)
}
// UpdateClientWithBodyWithResponse request with arbitrary body returning *UpdateClientResponse
func (c *ClientWithResponses) UpdateClientWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error) {
rsp, err := c.UpdateClientWithBody(ctx, id, contentType, body, reqEditors...)
if err != nil {
return nil, err
}
return ParseUpdateClientResponse(rsp)
}
func (c *ClientWithResponses) UpdateClientWithResponse(ctx context.Context, id string, body UpdateClientJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error) {
rsp, err := c.UpdateClient(ctx, id, body, reqEditors...)
if err != nil {
return nil, err
}
return ParseUpdateClientResponse(rsp)
}
// TriggerExportWithBodyWithResponse request with arbitrary body returning *TriggerExportResponse
func (c *ClientWithResponses) TriggerExportWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*TriggerExportResponse, error) {
rsp, err := c.TriggerExportWithBody(ctx, contentType, body, reqEditors...)
@@ -1281,22 +1556,13 @@ func (c *ClientWithResponses) CreateQueryWithResponse(ctx context.Context, body
return ParseCreateQueryResponse(rsp)
}
// DeprecateQueryWithResponse request returning *DeprecateQueryResponse
func (c *ClientWithResponses) DeprecateQueryWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*DeprecateQueryResponse, error) {
rsp, err := c.DeprecateQuery(ctx, id, reqEditors...)
// GetQueryWithResponse request returning *GetQueryResponse
func (c *ClientWithResponses) GetQueryWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetQueryResponse, error) {
rsp, err := c.GetQuery(ctx, id, reqEditors...)
if err != nil {
return nil, err
}
return ParseDeprecateQueryResponse(rsp)
}
// GetQueryByIdWithResponse request returning *GetQueryByIdResponse
func (c *ClientWithResponses) GetQueryByIdWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetQueryByIdResponse, error) {
rsp, err := c.GetQueryById(ctx, id, reqEditors...)
if err != nil {
return nil, err
}
return ParseGetQueryByIdResponse(rsp)
return ParseGetQueryResponse(rsp)
}
// UpdateQueryWithBodyWithResponse request with arbitrary body returning *UpdateQueryResponse
@@ -1333,6 +1599,74 @@ func (c *ClientWithResponses) TestQueryWithResponse(ctx context.Context, id stri
return ParseTestQueryResponse(rsp)
}
// ParseCreateClientResponse parses an HTTP response from a CreateClientWithResponse call
func ParseCreateClientResponse(rsp *http.Response) (*CreateClientResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &CreateClientResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 201:
var dest IdMessage
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON201 = &dest
}
return response, nil
}
// ParseGetClientResponse parses an HTTP response from a GetClientWithResponse call
func ParseGetClientResponse(rsp *http.Response) (*GetClientResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &GetClientResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
var dest JobClient
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON200 = &dest
}
return response, nil
}
// ParseUpdateClientResponse parses an HTTP response from a UpdateClientWithResponse call
func ParseUpdateClientResponse(rsp *http.Response) (*UpdateClientResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &UpdateClientResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
return response, nil
}
// ParseTriggerExportResponse parses an HTTP response from a TriggerExportWithResponse call
func ParseTriggerExportResponse(rsp *http.Response) (*TriggerExportResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -1479,31 +1813,15 @@ func ParseCreateQueryResponse(rsp *http.Response) (*CreateQueryResponse, error)
return response, nil
}
// ParseDeprecateQueryResponse parses an HTTP response from a DeprecateQueryWithResponse call
func ParseDeprecateQueryResponse(rsp *http.Response) (*DeprecateQueryResponse, error) {
// ParseGetQueryResponse parses an HTTP response from a GetQueryWithResponse call
func ParseGetQueryResponse(rsp *http.Response) (*GetQueryResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &DeprecateQueryResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
return response, nil
}
// ParseGetQueryByIdResponse parses an HTTP response from a GetQueryByIdWithResponse call
func ParseGetQueryByIdResponse(rsp *http.Response) (*GetQueryByIdResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &GetQueryByIdResponse{
response := &GetQueryResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
+2 -2
View File
@@ -9,7 +9,7 @@ vars:
tasks:
generate:
cmds:
- task db:mig:run
- task db:mig
- sqlc generate --file sqlc.yml
lint:
cmds:
@@ -22,7 +22,7 @@ tasks:
read -p "Migration Name: " name
test -z "$name" && echo "Error: Name is required." && exit 1
migrate create -ext sql -dir {{.MIGRATIONS}} $name
mig:run:
mig:
cmds:
- task compose:up:bg
- sleep 2
+116 -21
View File
@@ -8,14 +8,91 @@ servers:
- url: https://api.example.com/v1
description: Production server
tags:
- name: QueryService
description: Operations related to queries
- name: ClientService
description: Operations related to clients
- name: JobCollectorService
description: Operations related to job collectors
- name: QueryService
description: Operations related to queries
- name: ExportService
description: Operations related to exports
paths:
/clients:
post:
operationId: createClient
tags:
- ClientService
summary: Create a new client
description: Creates a new client with the provided details.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ClientCreate'
responses:
'201':
description: Client created successfully.
content:
application/json:
schema:
$ref: '#/components/schemas/IdMessage'
'400':
description: Invalid request body.
/clients/{id}:
get:
operationId: getClient
tags:
- ClientService
summary: Get a client by ID
description: Retrieves a specific client by its ID.
parameters:
- in: path
name: id
required: true
schema:
type: string
description: The ID of the client to retrieve.
responses:
'200':
description: Client details.
content:
application/json:
schema:
$ref: '#/components/schemas/JobClient'
'400':
description: Invalid request parameters.
'404':
description: Client not found.
patch:
operationId: updateClient
tags:
- ClientService
summary: Update a client
description: Updates an existing client with new details.
parameters:
- in: path
name: id
required: true
schema:
type: string
description: The ID of the client to update.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ClientUpdate'
responses:
'200':
description: Client updated successfully.
'400':
description: Invalid request body.
'404':
description: Client not found
/queries:
get:
operationId: listQueries
@@ -58,7 +135,7 @@ paths:
/queries/{id}:
get:
operationId: getQueryById
operationId: getQuery
tags:
- QueryService
summary: Get a query by ID
@@ -105,24 +182,6 @@ paths:
description: Query updated successfully.
'400':
description: Invalid request body.
delete:
operationId: deprecateQuery
tags:
- QueryService
summary: Deprecate a query
description: Deprecates a specific query by its ID.
parameters:
- in: path
name: id
required: true
schema:
type: string
description: The ID of the query to deprecate.
responses:
'200':
description: Query deprecated successfully.
'400':
description: Invalid request body.
'404':
description: Query not found.
@@ -363,6 +422,42 @@ components:
required:
- value
JobClient:
type: object
properties:
id:
type: string
description: The client id
name:
type: string
description: The client name
can_sync:
type: boolean
description: If the client is allowing active syncs
required:
- id
- name
- can_sync
ClientCreate:
type: object
properties:
name:
type: string
description: The client name
required:
- name
ClientUpdate:
type: object
properties:
name:
type: string
description: The client name
can_sync:
type: boolean
description: If the client is allowing active syncs
IdMessage:
type: object
properties:
+50
View File
@@ -0,0 +1,50 @@
package integration_test
import (
"context"
"queryorchestration/internal/test"
queryservice "queryorchestration/pkg/queryService"
"testing"
"github.com/stretchr/testify/assert"
)
func TestClient(t *testing.T) {
ctx := context.Background()
address, cleanup := test.CreateAPIWithDependencies(t, ctx, "queryService")
defer cleanup()
client, err := queryservice.NewClientWithResponses(address)
assert.Nil(t, err)
idRes, err := client.CreateClientWithResponse(ctx, queryservice.ClientCreate{
Name: "example_name",
})
assert.Nil(t, err)
assert.NotNil(t, idRes)
assert.NotNil(t, idRes.JSON201)
assert.NotNil(t, idRes.JSON201.Id)
id := idRes.JSON201.Id
clientRes, err := client.GetClientWithResponse(ctx, id)
assert.Nil(t, err)
assert.Equal(t, id, clientRes.JSON200.Id)
assert.Equal(t, "example_name", clientRes.JSON200.Name)
assert.False(t, clientRes.JSON200.CanSync)
updateName := "update_name"
updateCanSync := true
updateRes, err := client.UpdateClientWithResponse(ctx, id, queryservice.ClientUpdate{
Name: &updateName,
CanSync: &updateCanSync,
})
assert.Nil(t, err)
assert.NotNil(t, updateRes)
clientRes, err = client.GetClientWithResponse(ctx, id)
assert.Nil(t, err)
assert.Equal(t, id, clientRes.JSON200.Id)
assert.Equal(t, updateName, clientRes.JSON200.Name)
assert.True(t, clientRes.JSON200.CanSync)
}
+2 -4
View File
@@ -33,7 +33,7 @@ func TestQueryService(t *testing.T) {
assert.Nil(t, err)
jsonID := idRes.JSON201.Id
queryRes, err := client.GetQueryByIdWithResponse(ctx, jsonID)
queryRes, err := client.GetQueryWithResponse(ctx, jsonID)
assert.Nil(t, err)
assert.Equal(t, jsonID, queryRes.JSON200.Id)
assert.Equal(t, queryservice.JSONEXTRACTOR, queryRes.JSON200.Type)
@@ -46,10 +46,8 @@ func TestQueryService(t *testing.T) {
assert.Nil(t, err)
assert.Len(t, queriesRes.JSON200.Queries, 2)
cfg := "{}"
aV := int32(2)
res, err := client.UpdateQueryWithResponse(ctx, jsonID, queryservice.QueryUpdate{
Config: &cfg,
ActiveVersion: &aV,
RequiredQueries: &[]string{
contextID,
@@ -58,7 +56,7 @@ func TestQueryService(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, res)
queryRes, err = client.GetQueryByIdWithResponse(ctx, jsonID)
queryRes, err = client.GetQueryWithResponse(ctx, jsonID)
assert.Nil(t, err)
assert.Equal(t, jsonID, queryRes.JSON200.Id)
assert.Equal(t, queryservice.JSONEXTRACTOR, queryRes.JSON200.Type)