1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-27 13:48:49 +08:00
Ivan Milošević 880e193b0a
NOISSUE - Implement errors package in senml transformer, readers and writers (#1108)
* Implement errors package in senml transformer, readers and writers

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* Remove unused const
Return wrapped error in postgres writer

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* fix default db host in postgres writer

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* fix capital letters in errors messages

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* use svcName instead of postgres for Promethius initialization

Signed-off-by: Ivan Milošević <iva@blokovi.com>
2020-04-13 12:57:53 +02:00

141 lines
3.4 KiB
Go

// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package postgres
import (
"fmt"
"github.com/jmoiron/sqlx" // required for DB access
"github.com/mainflux/mainflux/errors"
"github.com/mainflux/mainflux/readers"
"github.com/mainflux/mainflux/transformers/senml"
)
const errInvalid = "invalid_text_representation"
var errReadMessages = errors.New("faled to read messages from postgres database")
var _ readers.MessageRepository = (*postgresRepository)(nil)
type postgresRepository struct {
db *sqlx.DB
}
// New returns new PostgreSQL writer.
func New(db *sqlx.DB) readers.MessageRepository {
return &postgresRepository{
db: db,
}
}
func (tr postgresRepository) ReadAll(chanID string, offset, limit uint64, query map[string]string) (readers.MessagesPage, error) {
q := fmt.Sprintf(`SELECT * FROM messages
WHERE %s ORDER BY time DESC
LIMIT :limit OFFSET :offset;`, fmtCondition(chanID, query))
params := map[string]interface{}{
"channel": chanID,
"limit": limit,
"offset": offset,
"subtopic": query["subtopic"],
"publisher": query["publisher"],
"name": query["name"],
"protocol": query["protocol"],
}
rows, err := tr.db.NamedQuery(q, params)
if err != nil {
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
defer rows.Close()
page := readers.MessagesPage{
Offset: offset,
Limit: limit,
Messages: []senml.Message{},
}
for rows.Next() {
dbm := dbMessage{Channel: chanID}
if err := rows.StructScan(&dbm); err != nil {
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
msg := toMessage(dbm)
page.Messages = append(page.Messages, msg)
}
q = `SELECT COUNT(*) FROM messages WHERE channel = $1;`
qParams := []interface{}{chanID}
if query["subtopic"] != "" {
q = `SELECT COUNT(*) FROM messages WHERE channel = $1 AND subtopic = $2;`
qParams = append(qParams, query["subtopic"])
}
if err := tr.db.QueryRow(q, qParams...).Scan(&page.Total); err != nil {
return readers.MessagesPage{}, errors.Wrap(errReadMessages, err)
}
return page, nil
}
func fmtCondition(chanID string, query map[string]string) string {
condition := `channel = :channel`
for name := range query {
switch name {
case
"subtopic",
"publisher",
"name",
"protocol":
condition = fmt.Sprintf(`%s AND %s = :%s`, condition, name, name)
}
}
return condition
}
type dbMessage struct {
ID string `db:"id"`
Channel string `db:"channel"`
Subtopic string `db:"subtopic"`
Publisher string `db:"publisher"`
Protocol string `db:"protocol"`
Name string `db:"name"`
Unit string `db:"unit"`
Value *float64 `db:"value"`
StringValue *string `db:"string_value"`
BoolValue *bool `db:"bool_value"`
DataValue *string `db:"data_value"`
Sum *float64 `db:"sum"`
Time float64 `db:"time"`
UpdateTime float64 `db:"update_time"`
}
func toMessage(dbm dbMessage) senml.Message {
msg := senml.Message{
Channel: dbm.Channel,
Subtopic: dbm.Subtopic,
Publisher: dbm.Publisher,
Protocol: dbm.Protocol,
Name: dbm.Name,
Unit: dbm.Unit,
Time: dbm.Time,
UpdateTime: dbm.UpdateTime,
Sum: dbm.Sum,
}
switch {
case dbm.Value != nil:
msg.Value = dbm.Value
case dbm.StringValue != nil:
msg.StringValue = dbm.StringValue
case dbm.DataValue != nil:
msg.DataValue = dbm.DataValue
case dbm.BoolValue != nil:
msg.BoolValue = dbm.BoolValue
}
return msg
}