mirror of
https://github.com/absmach/supermq.git
synced 2026-06-23 07:40:17 +00:00
MG-94 - Add backend support for reports (#107)
* initial implementation Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix missing variable Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix api and add report config to rule engine Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix repo command Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix failing linter Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix download request Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix download api Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix failing linter Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix add report config Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove unused parameters Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * add limit field to config Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * add test and address comments Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove unused code Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * add logger Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove logger Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * uncomment code Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * add status check Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * address comments Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * resolve conflicts Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix failing linter Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * rebase code Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix startdate when zero Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove unused code Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * address comments Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * add time expression parser and logics Signed-off-by: Arvindh <arvindh91@gmail.com> * fix postgres methods Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix failing linter Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix pdf and csv generation Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix failing linter Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * add description for reports Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove aggregation field Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove unused code Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove logs Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix go mod file Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix endpoint and postgres methods Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * address comments Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * update report config update methods Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix failing linter Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix service test Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove unnecessary check Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * address comments Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove endpoints Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove unused code Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix generate PDF and CSV Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove unused code Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * address comments Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix failing linter Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * revert UI variable Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * add empty line Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix go mod file Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * update download api Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * revert UI variable Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix download endpoint Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * update generateREport method Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix failing tests Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * refactor generate api Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix failing linter Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix failing linter Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix csv column Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * fix csv generator Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * remove logs Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> * updated reports logic and api Signed-off-by: Arvindh <arvindh91@gmail.com> * fix time conversion Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> --------- Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> Signed-off-by: Arvindh <arvindh91@gmail.com> Co-authored-by: Arvindh <arvindh91@gmail.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package reltime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
re = regexp.MustCompile(`(?i)^now\(\)([\+\-])(.+)$`)
|
||||
|
||||
ErrInvalidDuration = errors.New("invalid duration format")
|
||||
ErrInvalidExpression = errors.New("invalid time expression")
|
||||
ErrUnsupportedUnit = errors.New("unsupported unit")
|
||||
)
|
||||
|
||||
func Parse(expr string) (time.Time, error) {
|
||||
now := time.Now()
|
||||
expr = strings.ReplaceAll(expr, " ", "")
|
||||
|
||||
if strings.EqualFold(expr, "now()") {
|
||||
return now, nil
|
||||
}
|
||||
|
||||
matches := re.FindStringSubmatch(expr)
|
||||
if len(matches) != 3 {
|
||||
return time.Time{}, errors.Wrap(ErrInvalidExpression, fmt.Errorf("%s", expr))
|
||||
}
|
||||
|
||||
sign := matches[1]
|
||||
durStr := matches[2]
|
||||
if strings.ContainsAny(durStr, "+-") {
|
||||
return time.Time{}, errors.Wrap(ErrInvalidExpression, fmt.Errorf("%s", expr))
|
||||
}
|
||||
|
||||
dur, err := parseComplexDuration(durStr)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
if sign == "-" {
|
||||
return now.Add(-dur), nil
|
||||
}
|
||||
return now.Add(dur), nil
|
||||
}
|
||||
|
||||
func parseComplexDuration(s string) (time.Duration, error) {
|
||||
var total time.Duration
|
||||
re := regexp.MustCompile(`(\d+)([smhdwMY])`)
|
||||
matches := re.FindAllStringSubmatch(s, -1)
|
||||
|
||||
if matches == nil {
|
||||
return 0, errors.Wrap(ErrInvalidDuration, fmt.Errorf("%s", s))
|
||||
}
|
||||
|
||||
for _, match := range matches {
|
||||
val, _ := strconv.Atoi(match[1])
|
||||
unit := match[2]
|
||||
|
||||
var d time.Duration
|
||||
switch unit {
|
||||
case "s":
|
||||
d = time.Duration(val) * time.Second
|
||||
case "m":
|
||||
d = time.Duration(val) * time.Minute
|
||||
case "h":
|
||||
d = time.Duration(val) * time.Hour
|
||||
case "d":
|
||||
d = time.Duration(val) * 24 * time.Hour
|
||||
case "w":
|
||||
d = time.Duration(val) * 7 * 24 * time.Hour
|
||||
default:
|
||||
return 0, errors.Wrap(ErrUnsupportedUnit, fmt.Errorf("%s", unit))
|
||||
}
|
||||
|
||||
total += d
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package reltime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
now := time.Now()
|
||||
|
||||
tests := []struct {
|
||||
desc string
|
||||
expr string
|
||||
expected time.Time
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "testing expression now()-5d",
|
||||
expr: "now()-5d",
|
||||
expected: now.Add(-5 * 24 * time.Hour),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "testing expression now()+2h30m",
|
||||
expr: "now()+2h30m",
|
||||
expected: now.Add(2*time.Hour + 30*time.Minute),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "testing expression now()-1w3d10h40m",
|
||||
expr: "now()-1w3d10h40m",
|
||||
expected: now.Add(-(7*24+3*24+10)*time.Hour - 40*time.Minute),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "testing expression yesterday",
|
||||
expr: "yesterday",
|
||||
err: ErrInvalidExpression,
|
||||
},
|
||||
{
|
||||
desc: "testing expression now()--5d",
|
||||
expr: "now()--5d",
|
||||
err: ErrInvalidExpression,
|
||||
},
|
||||
{
|
||||
desc: "testing expression now()+",
|
||||
expr: "now()+",
|
||||
err: ErrInvalidExpression,
|
||||
},
|
||||
{
|
||||
desc: "testing expression now()+5r",
|
||||
expr: "now()+5r",
|
||||
err: ErrInvalidDuration,
|
||||
},
|
||||
{
|
||||
desc: "testing expression now()+5M",
|
||||
expr: "now()+5M",
|
||||
err: ErrUnsupportedUnit,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
got, err := Parse(tc.expr)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %v got %v and response time %v\n", tc.desc, tc.err, err, got))
|
||||
if err == nil {
|
||||
assert.WithinDuration(t, tc.expected, got, time.Duration(10*time.Second))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user