MF-1061 - Implement protocol, name, v, vb, vs, vd and from/to Postgres reader… (#1322)

* MF-1061 - Implement protocol, name, v, vb, vs, vd and from/to postgres-reader filters and tests

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix reviews

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
This commit is contained in:
Manuel Imperiale 2021-01-11 13:17:12 +01:00 committed by GitHub
parent a185855c06
commit 973ca177ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 192 additions and 67 deletions

View File

@ -141,27 +141,27 @@ func fmtCondition(chanID string, query map[string]string) string {
"protocol":
condition = fmt.Sprintf(`%s AND "%s"='%s'`, condition, name, value)
case "v":
condition = fmt.Sprintf(`%s AND "value" = %s`, condition, value)
condition = fmt.Sprintf(`%s AND value = %s`, condition, value)
case "vb":
condition = fmt.Sprintf(`%s AND "boolValue" = %s`, condition, value)
condition = fmt.Sprintf(`%s AND boolValue = %s`, condition, value)
case "vs":
condition = fmt.Sprintf(`%s AND "stringValue"='%s'`, condition, value)
condition = fmt.Sprintf(`%s AND stringValue = '%s'`, condition, value)
case "vd":
condition = fmt.Sprintf(`%s AND "dataValue"='%s'`, condition, value)
condition = fmt.Sprintf(`%s AND dataValue = '%s'`, condition, value)
case "from":
fVal, err := strconv.ParseFloat(value, 64)
if err != nil {
continue
}
iVal := int64(fVal * 1e9)
condition = fmt.Sprintf(`%s AND "time" >= %d`, condition, iVal)
condition = fmt.Sprintf(`%s AND time >= %d`, condition, iVal)
case "to":
fVal, err := strconv.ParseFloat(value, 64)
if err != nil {
continue
}
iVal := int64(fVal * 1e9)
condition = fmt.Sprintf(`%s AND "time" < %d`, condition, iVal)
condition = fmt.Sprintf(`%s AND time < %d`, condition, iVal)
}
}
return condition

View File

@ -51,13 +51,19 @@ func (tr postgresRepository) ReadAll(chanID string, offset, limit uint64, query
LIMIT :limit OFFSET :offset;`, table, fmtCondition(chanID, query), order)
params := map[string]interface{}{
"channel": chanID,
"limit": limit,
"offset": offset,
"subtopic": query["subtopic"],
"publisher": query["publisher"],
"name": query["name"],
"protocol": query["protocol"],
"channel": chanID,
"limit": limit,
"offset": offset,
"subtopic": query["subtopic"],
"publisher": query["publisher"],
"name": query["name"],
"protocol": query["protocol"],
"value": query["v"],
"bool_value": query["vb"],
"string_value": query["vs"],
"data_value": query["vd"],
"from": query["from"],
"to": query["to"],
}
rows, err := tr.db.NamedQuery(q, params)
@ -97,17 +103,20 @@ func (tr postgresRepository) ReadAll(chanID string, offset, limit uint64, query
}
q = fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE channel = $1;`, table)
qParams := []interface{}{chanID}
if query["subtopic"] != "" {
q = fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE channel = $1 AND subtopic = $2;`, table)
qParams = append(qParams, query["subtopic"])
}
if err := tr.db.QueryRow(q, qParams...).Scan(&page.Total); err != nil {
q = fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE %s;`, table, fmtCondition(chanID, query))
rows, err = tr.db.NamedQuery(q, params)
if err != nil {
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
defer rows.Close()
total := uint64(0)
if rows.Next() {
if err := rows.Scan(&total); err != nil {
return page, err
}
}
page.Total = total
return page, nil
}
@ -122,6 +131,18 @@ func fmtCondition(chanID string, query map[string]string) string {
"name",
"protocol":
condition = fmt.Sprintf(`%s AND %s = :%s`, condition, name, name)
case "v":
condition = fmt.Sprintf(`%s AND value = :value`, condition)
case "vb":
condition = fmt.Sprintf(`%s AND bool_value = :bool_value`, condition)
case "vs":
condition = fmt.Sprintf(`%s AND string_value = :string_value`, condition)
case "vd":
condition = fmt.Sprintf(`%s AND data_value = :data_value`, condition)
case "from":
condition = fmt.Sprintf(`%s AND time >= :from`, condition)
case "to":
condition = fmt.Sprintf(`%s AND time < :to`, condition)
}
}
return condition

View File

@ -8,8 +8,8 @@ import (
"testing"
"time"
"github.com/gofrs/uuid"
"github.com/mainflux/mainflux/pkg/transformers/senml"
uuidProvider "github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/readers"
preader "github.com/mainflux/mainflux/readers/postgres"
pwriter "github.com/mainflux/mainflux/writers/postgres"
@ -19,60 +19,77 @@ import (
const (
subtopic = "subtopic"
msgsNum = 42
msgsNum = 100
limit = 10
valueFields = 5
mqttProt = "mqtt"
httpProt = "http"
msgName = "temperature"
)
var (
v float64 = 5
stringV = "value"
boolV = true
dataV = "base64"
sum float64 = 42
v float64 = 5
vs = "value"
vb = true
vd = "dataValue"
sum float64 = 42
)
func TestReadSenml(t *testing.T) {
messageRepo := pwriter.New(db)
chanID, err := uuid.NewV4()
chanID, err := uuidProvider.New().ID()
require.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err))
pubID, err := uuid.NewV4()
pubID, err := uuidProvider.New().ID()
require.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err))
wrongID, err := uuid.NewV4()
pub2ID, err := uuidProvider.New().ID()
require.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err))
wrongID, err := uuidProvider.New().ID()
require.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err))
m := senml.Message{
Channel: chanID.String(),
Publisher: pubID.String(),
Protocol: "mqtt",
Channel: chanID,
Publisher: pubID,
Protocol: mqttProt,
}
messages := []senml.Message{}
subtopicMsgs := []senml.Message{}
now := time.Now().Unix()
valueMsgs := []senml.Message{}
boolMsgs := []senml.Message{}
stringMsgs := []senml.Message{}
dataMsgs := []senml.Message{}
queryMsgs := []senml.Message{}
now := float64(time.Now().Unix())
for i := 0; i < msgsNum; i++ {
// Mix possible values as well as value sum.
count := i % valueFields
msg := m
msg.Time = now - float64(i)
count := i % valueFields
switch count {
case 0:
msg.Subtopic = subtopic
msg.Value = &v
valueMsgs = append(valueMsgs, msg)
case 1:
msg.BoolValue = &boolV
msg.BoolValue = &vb
boolMsgs = append(boolMsgs, msg)
case 2:
msg.StringValue = &stringV
msg.StringValue = &vs
stringMsgs = append(stringMsgs, msg)
case 3:
msg.DataValue = &dataV
msg.DataValue = &vd
dataMsgs = append(dataMsgs, msg)
case 4:
msg.Sum = &sum
msg.Subtopic = subtopic
msg.Protocol = httpProt
msg.Publisher = pub2ID
msg.Name = msgName
queryMsgs = append(queryMsgs, msg)
}
msg.Time = float64(now - int64(i))
messages = append(messages, msg)
if count == 0 {
subtopicMsgs = append(subtopicMsgs, msg)
}
}
err = messageRepo.Save(messages)
@ -91,7 +108,7 @@ func TestReadSenml(t *testing.T) {
page readers.MessagesPage
}{
"read message page for existing channel": {
chanID: chanID.String(),
chanID: chanID,
offset: 0,
limit: msgsNum,
page: readers.MessagesPage{
@ -102,7 +119,7 @@ func TestReadSenml(t *testing.T) {
},
},
"read message page for non-existent channel": {
chanID: wrongID.String(),
chanID: wrongID,
offset: 0,
limit: msgsNum,
page: readers.MessagesPage{
@ -113,18 +130,18 @@ func TestReadSenml(t *testing.T) {
},
},
"read message last page": {
chanID: chanID.String(),
offset: 40,
limit: 5,
chanID: chanID,
offset: msgsNum - 20,
limit: msgsNum,
page: readers.MessagesPage{
Total: msgsNum,
Offset: 40,
Limit: 5,
Messages: fromSenml(messages[40:42]),
Offset: msgsNum - 20,
Limit: msgsNum,
Messages: fromSenml(messages[msgsNum-20 : msgsNum]),
},
},
"read message with non-existent subtopic": {
chanID: chanID.String(),
chanID: chanID,
offset: 0,
limit: msgsNum,
query: map[string]string{"subtopic": "not-present"},
@ -136,27 +153,114 @@ func TestReadSenml(t *testing.T) {
},
},
"read message with subtopic": {
chanID: chanID.String(),
chanID: chanID,
offset: 0,
limit: uint64(len(subtopicMsgs)),
limit: uint64(len(queryMsgs)),
query: map[string]string{"subtopic": subtopic},
page: readers.MessagesPage{
Total: uint64(len(subtopicMsgs)),
Total: uint64(len(queryMsgs)),
Offset: 0,
Limit: uint64(len(subtopicMsgs)),
Messages: fromSenml(subtopicMsgs),
Limit: uint64(len(queryMsgs)),
Messages: fromSenml(queryMsgs),
},
},
"read message with publisher/protocols": {
chanID: chanID.String(),
"read message with publisher": {
chanID: chanID,
offset: 0,
limit: msgsNum,
query: map[string]string{"publisher": pubID.String(), "protocol": "mqtt"},
limit: uint64(len(queryMsgs)),
query: map[string]string{"publisher": pub2ID},
page: readers.MessagesPage{
Total: msgsNum,
Total: uint64(len(queryMsgs)),
Offset: 0,
Limit: msgsNum,
Messages: fromSenml(messages),
Limit: uint64(len(queryMsgs)),
Messages: fromSenml(queryMsgs),
},
},
"read message with protocol": {
chanID: chanID,
offset: 0,
limit: uint64(len(queryMsgs)),
query: map[string]string{"protocol": httpProt},
page: readers.MessagesPage{
Total: uint64(len(queryMsgs)),
Offset: 0,
Limit: uint64(len(queryMsgs)),
Messages: fromSenml(queryMsgs),
},
},
"read message with name": {
chanID: chanID,
offset: 0,
limit: limit,
query: map[string]string{"name": msgName},
page: readers.MessagesPage{
Total: uint64(len(queryMsgs)),
Offset: 0,
Limit: limit,
Messages: fromSenml(queryMsgs[0:limit]),
},
},
"read message with value": {
chanID: chanID,
offset: 0,
limit: limit,
query: map[string]string{"v": fmt.Sprintf("%f", v)},
page: readers.MessagesPage{
Total: uint64(len(valueMsgs)),
Offset: 0,
Limit: limit,
Messages: fromSenml(valueMsgs[0:limit]),
},
},
"read message with boolean value": {
chanID: chanID,
offset: 0,
limit: limit,
query: map[string]string{"vb": fmt.Sprintf("%t", vb)},
page: readers.MessagesPage{
Total: uint64(len(boolMsgs)),
Offset: 0,
Limit: limit,
Messages: fromSenml(boolMsgs[0:limit]),
},
},
"read message with string value": {
chanID: chanID,
offset: 0,
limit: limit,
query: map[string]string{"vs": vs},
page: readers.MessagesPage{
Total: uint64(len(stringMsgs)),
Offset: 0,
Limit: limit,
Messages: fromSenml(stringMsgs[0:limit]),
},
},
"read message with data value": {
chanID: chanID,
offset: 0,
limit: limit,
query: map[string]string{"vd": vd},
page: readers.MessagesPage{
Total: uint64(len(dataMsgs)),
Offset: 0,
Limit: limit,
Messages: fromSenml(dataMsgs[0:limit]),
},
},
"read message with from/to": {
chanID: chanID,
offset: 0,
limit: limit,
query: map[string]string{
"from": fmt.Sprintf("%f", messages[5].Time),
"to": fmt.Sprintf("%f", messages[0].Time),
},
page: readers.MessagesPage{
Total: 5,
Offset: 0,
Limit: limit,
Messages: fromSenml(messages[1:6]),
},
},
}