From cf95d42b5bd64c55d156fdd5ef3b795099d2c83e Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Fri, 12 Feb 2021 11:20:04 +0100 Subject: [PATCH] Add record reporting --- compose/automation/records_handler.gen.go | 170 ++++++++++++++++++++++ compose/automation/records_handler.go | 17 +++ compose/automation/records_handler.yaml | 44 ++++++ 3 files changed, 231 insertions(+) diff --git a/compose/automation/records_handler.gen.go b/compose/automation/records_handler.gen.go index 829f837eb..3ad6a21e2 100644 --- a/compose/automation/records_handler.gen.go +++ b/compose/automation/records_handler.gen.go @@ -35,6 +35,7 @@ func (h recordsHandler) register() { h.Create(), h.Update(), h.Delete(), + h.Report(), ) } @@ -1052,3 +1053,172 @@ func (h recordsHandler) Delete() *atypes.Function { }, } } + +type ( + recordsReportArgs struct { + hasModule bool + Module interface{} + moduleID uint64 + moduleHandle string + moduleRes *types.Module + + hasNamespace bool + Namespace interface{} + namespaceID uint64 + namespaceHandle string + namespaceRes *types.Namespace + + hasMetrics bool + Metrics string + + hasDimensons bool + Dimensons string + + hasFilter bool + Filter string + } + + recordsReportResults struct { + Report interface{} + } +) + +func (a recordsReportArgs) GetModule() (bool, uint64, string, *types.Module) { + return a.hasModule, a.moduleID, a.moduleHandle, a.moduleRes +} + +func (a recordsReportArgs) GetNamespace() (bool, uint64, string, *types.Namespace) { + return a.hasNamespace, a.namespaceID, a.namespaceHandle, a.namespaceRes +} + +// Report function Searches for records and returns them +// +// expects implementation of report function: +// func (h recordsHandler) report(ctx context.Context, args *recordsReportArgs) (results *recordsReportResults, err error) { +// return +// } +func (h recordsHandler) Report() *atypes.Function { + return &atypes.Function{ + Ref: "composeRecordsReport", + Kind: "function", + Labels: map[string]string{"compose": "step,workflow", "record": "step,workflow"}, + Meta: &atypes.FunctionMeta{ + Short: "Searches for records and returns them", + }, + + Parameters: []*atypes.Param{ + { + Name: "module", + Types: []string{"ID", "Handle", "ComposeModule"}, Required: true, + Meta: &atypes.ParamMeta{ + Label: "Module to set record type", + Description: "Even with unique record ID across all modules, module needs to be known\nbefore doing any record operations. Mainly because records of different\nmodules can be located in different stores.", + }, + }, + { + Name: "namespace", + Types: []string{"ID", "Handle", "ComposeNamespace"}, Required: true, + }, + { + Name: "metrics", + Types: []string{"String"}, Required: true, + Meta: &atypes.ParamMeta{ + Label: "Metrics for records report", + Description: "List of comma delimited expressions with aggregation functions (count, sum, min, avg)", + }, + }, + { + Name: "dimensons", + Types: []string{"String"}, Required: true, + Meta: &atypes.ParamMeta{ + Label: "Dimensons for records report", + Description: "List of comma delimited dimension (i.e.: group by) expressions or fields", + }, + }, + { + Name: "filter", + Types: []string{"String"}, Required: true, + Meta: &atypes.ParamMeta{ + Label: "Filter for records report", + Description: "Filter in CortezaQL format", + }, + }, + }, + + Results: []*atypes.Param{ + + { + Name: "report", + Types: []string{"Any"}, + Meta: &atypes.ParamMeta{ + Label: "Complex structure holding complete records report", + Description: "Example of a result value\n[]map[string]interface{}{\n\t{\"count\": 3, \"dimension_0\": 1, \"metric_0\": 3},\n\t{\"count\": 2, \"dimension_0\": 2, \"metric_0\": 5},\n\t{\"count\": 1, \"dimension_0\": nil, \"metric_0\": nil},\n}", + }, + }, + }, + + Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) { + var ( + args = &recordsReportArgs{ + hasModule: in.Has("module"), + hasNamespace: in.Has("namespace"), + hasMetrics: in.Has("metrics"), + hasDimensons: in.Has("dimensons"), + hasFilter: in.Has("filter"), + } + ) + + if err = in.Decode(args); err != nil { + return + } + + // Converting Module argument + if args.hasModule { + aux := expr.Must(expr.Select(in, "module")) + switch aux.Type() { + case h.reg.Type("ID").Type(): + args.moduleID = aux.Get().(uint64) + case h.reg.Type("Handle").Type(): + args.moduleHandle = aux.Get().(string) + case h.reg.Type("ComposeModule").Type(): + args.moduleRes = aux.Get().(*types.Module) + } + } + + // Converting Namespace argument + if args.hasNamespace { + aux := expr.Must(expr.Select(in, "namespace")) + switch aux.Type() { + case h.reg.Type("ID").Type(): + args.namespaceID = aux.Get().(uint64) + case h.reg.Type("Handle").Type(): + args.namespaceHandle = aux.Get().(string) + case h.reg.Type("ComposeNamespace").Type(): + args.namespaceRes = aux.Get().(*types.Namespace) + } + } + + var results *recordsReportResults + if results, err = h.report(ctx, args); err != nil { + return + } + + out = &expr.Vars{} + + { + // converting results.Report (interface{}) to Any + var ( + tval expr.TypedValue + ) + + if tval, err = h.reg.Type("Any").Cast(results.Report); err != nil { + return + } else if err = expr.Assign(out, "report", tval); err != nil { + return + } + } + + return + }, + } +} diff --git a/compose/automation/records_handler.go b/compose/automation/records_handler.go index 2e7a3b5c9..5e0d101b5 100644 --- a/compose/automation/records_handler.go +++ b/compose/automation/records_handler.go @@ -17,6 +17,7 @@ type ( Create(ctx context.Context, record *types.Record) (*types.Record, error) Update(ctx context.Context, record *types.Record) (*types.Record, error) Bulk(ctx context.Context, oo ...*types.RecordBulkOperation) (types.RecordSet, error) + Report(ctx context.Context, namespaceID, moduleID uint64, metrics, dimensions, filter string) (out interface{}, err error) Validate(ctx context.Context, rec *types.Record) error @@ -199,6 +200,22 @@ func (h recordsHandler) delete(ctx context.Context, args *recordsDeleteArgs) err } } +func (h recordsHandler) report(ctx context.Context, args *recordsReportArgs) (*recordsReportResults, error) { + r := &recordsReportResults{} + + ns, mod, err := h.loadCombo(ctx, args) + if err != nil { + return nil, err + } + + r.Report, err = h.rec.Report(ctx, ns.ID, mod.ID, args.Metrics, args.Dimensons, args.Filter) + if err != nil { + return nil, err + } + + return r, nil +} + func (h recordsHandler) lookupRecord(ctx context.Context, args recordLookup) (record *types.Record, err error) { var ( namespace *types.Namespace diff --git a/compose/automation/records_handler.yaml b/compose/automation/records_handler.yaml index a76443d41..f040fda3b 100644 --- a/compose/automation/records_handler.yaml +++ b/compose/automation/records_handler.yaml @@ -191,3 +191,47 @@ functions: # short: Recovers deleted record by ID # params: # record: *recordLookup + + + + report: + meta: + short: Searches for records and returns them + labels: + <<: *labels + params: + module: *moduleLookup + namespace: *namespaceLookup + metrics: + required: true + types: [ { wf: String } ] + meta: + label: Metrics for records report + description: |- + List of comma delimited expressions with aggregation functions (count, sum, min, avg) + dimensons: + required: true + types: [ { wf: String } ] + meta: + label: Dimensons for records report + description: |- + List of comma delimited dimension (i.e.: group by) expressions or fields + filter: + required: true + types: [ { wf: String } ] + meta: + label: Filter for records report + description: |- + Filter in CortezaQL format + results: + report: + wf: Any + meta: + label: Complex structure holding complete records report + description: |- + Example of a result value + []map[string]interface{}{ + {"count": 3, "dimension_0": 1, "metric_0": 3}, + {"count": 2, "dimension_0": 2, "metric_0": 5}, + {"count": 1, "dimension_0": nil, "metric_0": nil}, + }