zitadel/internal/api/grpc/execution/v3alpha/query.go
Stefan Benz fb3c6f791b
feat: query side for executions and targets for actions v2 (#7524)
* feat: add projections and query side to executions and targets

* feat: add list and get endpoints for targets

* feat: add integration tests for query endpoints target and execution

* fix: linting

* fix: linting

* fix: review changes, renames and corrections

* fix: review changes, renames and corrections

* fix: review changes, renames and corrections

* fix: review changes, renames and corrections

* fix: review changes, renames and corrections

* fix: review changes, renames and corrections

* fix: remove position from list details
2024-03-14 09:56:23 +00:00

287 lines
9.1 KiB
Go

package execution
import (
"context"
"google.golang.org/protobuf/types/known/durationpb"
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/zerrors"
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha"
)
func (s *Server) ListTargets(ctx context.Context, req *execution.ListTargetsRequest) (*execution.ListTargetsResponse, error) {
queries, err := listTargetsRequestToModel(req)
if err != nil {
return nil, err
}
resp, err := s.query.SearchTargets(ctx, queries)
if err != nil {
return nil, err
}
return &execution.ListTargetsResponse{
Result: targetsToPb(resp.Targets),
Details: object.ToListDetails(resp.SearchResponse),
}, nil
}
func listTargetsRequestToModel(req *execution.ListTargetsRequest) (*query.TargetSearchQueries, error) {
offset, limit, asc := object.ListQueryToQuery(req.Query)
queries, err := targetQueriesToQuery(req.Queries)
if err != nil {
return nil, err
}
return &query.TargetSearchQueries{
SearchRequest: query.SearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
SortingColumn: targetFieldNameToSortingColumn(req.SortingColumn),
},
Queries: queries,
}, nil
}
func targetFieldNameToSortingColumn(field execution.TargetFieldName) query.Column {
switch field {
case execution.TargetFieldName_FIELD_NAME_UNSPECIFIED:
return query.TargetColumnID
case execution.TargetFieldName_FIELD_NAME_ID:
return query.TargetColumnID
case execution.TargetFieldName_FIELD_NAME_CREATION_DATE:
return query.TargetColumnCreationDate
case execution.TargetFieldName_FIELD_NAME_CHANGE_DATE:
return query.TargetColumnChangeDate
case execution.TargetFieldName_FIELD_NAME_NAME:
return query.TargetColumnName
case execution.TargetFieldName_FIELD_NAME_TARGET_TYPE:
return query.TargetColumnTargetType
case execution.TargetFieldName_FIELD_NAME_URL:
return query.TargetColumnURL
case execution.TargetFieldName_FIELD_NAME_TIMEOUT:
return query.TargetColumnTimeout
case execution.TargetFieldName_FIELD_NAME_ASYNC:
return query.TargetColumnAsync
case execution.TargetFieldName_FIELD_NAME_INTERRUPT_ON_ERROR:
return query.TargetColumnInterruptOnError
default:
return query.TargetColumnID
}
}
func targetQueriesToQuery(queries []*execution.TargetSearchQuery) (_ []query.SearchQuery, err error) {
q := make([]query.SearchQuery, len(queries))
for i, query := range queries {
q[i], err = targetQueryToQuery(query)
if err != nil {
return nil, err
}
}
return q, nil
}
func targetQueryToQuery(query *execution.TargetSearchQuery) (query.SearchQuery, error) {
switch q := query.Query.(type) {
case *execution.TargetSearchQuery_TargetNameQuery:
return targetNameQueryToQuery(q.TargetNameQuery)
case *execution.TargetSearchQuery_InTargetIdsQuery:
return targetInTargetIdsQueryToQuery(q.InTargetIdsQuery)
default:
return nil, zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid")
}
}
func targetNameQueryToQuery(q *execution.TargetNameQuery) (query.SearchQuery, error) {
return query.NewTargetNameSearchQuery(object.TextMethodToQuery(q.Method), q.GetTargetName())
}
func targetInTargetIdsQueryToQuery(q *execution.InTargetIDsQuery) (query.SearchQuery, error) {
return query.NewTargetInIDsSearchQuery(q.GetTargetIds())
}
func (s *Server) GetTargetByID(ctx context.Context, req *execution.GetTargetByIDRequest) (_ *execution.GetTargetByIDResponse, err error) {
resp, err := s.query.GetTargetByID(ctx, req.GetTargetId())
if err != nil {
return nil, err
}
return &execution.GetTargetByIDResponse{
Target: targetToPb(resp),
}, nil
}
func targetsToPb(targets []*query.Target) []*execution.Target {
t := make([]*execution.Target, len(targets))
for i, target := range targets {
t[i] = targetToPb(target)
}
return t
}
func targetToPb(t *query.Target) *execution.Target {
target := &execution.Target{
Details: object.DomainToDetailsPb(&t.ObjectDetails),
TargetId: t.ID,
Name: t.Name,
Timeout: durationpb.New(t.Timeout),
}
if t.Async {
target.ExecutionType = &execution.Target_IsAsync{IsAsync: t.Async}
}
if t.InterruptOnError {
target.ExecutionType = &execution.Target_InterruptOnError{InterruptOnError: t.InterruptOnError}
}
switch t.TargetType {
case domain.TargetTypeWebhook:
target.TargetType = &execution.Target_RestWebhook{RestWebhook: &execution.SetRESTWebhook{Url: t.URL}}
case domain.TargetTypeRequestResponse:
target.TargetType = &execution.Target_RestRequestResponse{RestRequestResponse: &execution.SetRESTRequestResponse{Url: t.URL}}
default:
target.TargetType = nil
}
return target
}
func (s *Server) ListExecutions(ctx context.Context, req *execution.ListExecutionsRequest) (*execution.ListExecutionsResponse, error) {
queries, err := listExecutionsRequestToModel(req)
if err != nil {
return nil, err
}
resp, err := s.query.SearchExecutions(ctx, queries)
if err != nil {
return nil, err
}
return &execution.ListExecutionsResponse{
Result: executionsToPb(resp.Executions),
Details: object.ToListDetails(resp.SearchResponse),
}, nil
}
func listExecutionsRequestToModel(req *execution.ListExecutionsRequest) (*query.ExecutionSearchQueries, error) {
offset, limit, asc := object.ListQueryToQuery(req.Query)
queries, err := executionQueriesToQuery(req.Queries)
if err != nil {
return nil, err
}
return &query.ExecutionSearchQueries{
SearchRequest: query.SearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
},
Queries: queries,
}, nil
}
func executionQueriesToQuery(queries []*execution.SearchQuery) (_ []query.SearchQuery, err error) {
q := make([]query.SearchQuery, len(queries))
for i, query := range queries {
q[i], err = executionQueryToQuery(query)
if err != nil {
return nil, err
}
}
return q, nil
}
func executionQueryToQuery(searchQuery *execution.SearchQuery) (query.SearchQuery, error) {
switch q := searchQuery.Query.(type) {
case *execution.SearchQuery_InConditionsQuery:
return inConditionsQueryToQuery(q.InConditionsQuery)
case *execution.SearchQuery_ExecutionTypeQuery:
return executionTypeToQuery(q.ExecutionTypeQuery)
case *execution.SearchQuery_TargetQuery:
return query.NewExecutionTargetSearchQuery(q.TargetQuery.GetTargetId())
case *execution.SearchQuery_IncludeQuery:
return query.NewExecutionIncludeSearchQuery(q.IncludeQuery.GetInclude())
default:
return nil, zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid")
}
}
func executionTypeToQuery(q *execution.ExecutionTypeQuery) (query.SearchQuery, error) {
switch q.ExecutionType {
case execution.ExecutionType_EXECUTION_TYPE_UNSPECIFIED:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeUnspecified)
case execution.ExecutionType_EXECUTION_TYPE_REQUEST:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeRequest)
case execution.ExecutionType_EXECUTION_TYPE_RESPONSE:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeResponse)
case execution.ExecutionType_EXECUTION_TYPE_EVENT:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeEvent)
case execution.ExecutionType_EXECUTION_TYPE_FUNCTION:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeFunction)
default:
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeUnspecified)
}
}
func inConditionsQueryToQuery(q *execution.InConditionsQuery) (query.SearchQuery, error) {
values := make([]string, len(q.GetConditions()))
for i, condition := range q.GetConditions() {
id, err := conditionToID(condition)
if err != nil {
return nil, err
}
values[i] = id
}
return query.NewExecutionInIDsSearchQuery(values)
}
func conditionToID(q *execution.Condition) (string, error) {
switch t := q.GetConditionType().(type) {
case *execution.Condition_Request:
cond := &command.ExecutionAPICondition{
Method: t.Request.GetMethod(),
Service: t.Request.GetService(),
All: t.Request.GetAll(),
}
return cond.ID(domain.ExecutionTypeRequest), nil
case *execution.Condition_Response:
cond := &command.ExecutionAPICondition{
Method: t.Response.GetMethod(),
Service: t.Response.GetService(),
All: t.Response.GetAll(),
}
return cond.ID(domain.ExecutionTypeResponse), nil
case *execution.Condition_Event:
cond := &command.ExecutionEventCondition{
Event: t.Event.GetEvent(),
Group: t.Event.GetGroup(),
All: t.Event.GetAll(),
}
return cond.ID(), nil
case *execution.Condition_Function:
return t.Function, nil
default:
return "", zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid")
}
}
func executionsToPb(executions []*query.Execution) []*execution.Execution {
e := make([]*execution.Execution, len(executions))
for i, execution := range executions {
e[i] = executionToPb(execution)
}
return e
}
func executionToPb(e *query.Execution) *execution.Execution {
var targets, includes []string
if len(e.Targets) > 0 {
targets = e.Targets
}
if len(e.Includes) > 0 {
includes = e.Includes
}
return &execution.Execution{
Details: object.DomainToDetailsPb(&e.ObjectDetails),
ExecutionId: e.ID,
Targets: targets,
Includes: includes,
}
}