1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-26 13:48:53 +08:00

MF-916 - Fix Things and Channels counters (#947)

* MF-916 - Fix Things and Channels counters

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

* Fix reviews

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

* Use NamedQueryContext to count rows

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

* Fix reviews

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

* Create single helper total() func

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

* Fix reviews

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

* Rm useless LOWER

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

* Revert previous commit

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
This commit is contained in:
Manuel Imperiale 2019-11-13 15:26:57 +01:00 committed by GitHub
parent 67d518821a
commit afeec81a5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 125 additions and 79 deletions

View File

@ -22,6 +22,12 @@ type channelRepository struct {
db Database
}
type dbConnection struct {
Channel string `db:"channel"`
Thing string `db:"thing"`
Owner string `db:"owner"`
}
// NewChannelRepository instantiates a PostgreSQL implementation of channel
// repository.
func NewChannelRepository(db Database) things.ChannelRepository {
@ -149,23 +155,11 @@ func (cr channelRepository) RetrieveAll(ctx context.Context, owner string, offse
items = append(items, ch)
}
cq := ""
if name != "" {
cq = `AND LOWER(name) LIKE $2`
}
cq := fmt.Sprintf(`SELECT COUNT(*) FROM channels WHERE owner = :owner %s%s;`, nq, mq)
q = fmt.Sprintf(`SELECT COUNT(*) FROM channels WHERE owner = $1 %s;`, cq)
total := uint64(0)
switch name {
case "":
if err := cr.db.GetContext(ctx, &total, q, owner); err != nil {
return things.ChannelsPage{}, err
}
default:
if err := cr.db.GetContext(ctx, &total, q, owner, name); err != nil {
return things.ChannelsPage{}, err
}
total, err := total(ctx, cr.db, cq, params)
if err != nil {
return things.ChannelsPage{}, err
}
page := things.ChannelsPage{
@ -438,8 +432,18 @@ func getMetadataQuery(m things.Metadata) ([]byte, string, error) {
return mb, mq, nil
}
type dbConnection struct {
Channel string `db:"channel"`
Thing string `db:"thing"`
Owner string `db:"owner"`
func total(ctx context.Context, db Database, query string, params map[string]interface{}) (uint64, error) {
rows, err := db.NamedQueryContext(ctx, query, params)
if err != nil {
return 0, err
}
total := uint64(0)
if rows.Next() {
if err := rows.Scan(&total); err != nil {
return 0, err
}
}
return total, nil
}

View File

@ -218,14 +218,22 @@ func TestSingleChannelRetrieval(t *testing.T) {
}
func TestMultiChannelRetrieval(t *testing.T) {
email := "channel-multi-retrieval@example.com"
dbMiddleware := postgres.NewDatabase(db)
chanRepo := postgres.NewChannelRepository(dbMiddleware)
channelName := "channel_name"
meta := things.Metadata{}
wrongMeta := things.Metadata{}
meta["name"] = "test-channel"
wrongMeta["wrong"] = "wrong"
email := "channel-multi-retrieval@example.com"
name := "channel_name"
metadata := things.Metadata{
"field": "value",
}
wrongMeta := things.Metadata{
"wrong": "wrong",
}
offset := uint64(1)
chNameNum := uint64(3)
chMetaNum := uint64(3)
chNameMetaNum := uint64(2)
n := uint64(10)
for i := uint64(0); i < n; i++ {
@ -237,14 +245,18 @@ func TestMultiChannelRetrieval(t *testing.T) {
Owner: email,
}
// Create first two Channels with name.
if i < 2 {
ch.Name = channelName
// Create Channels with name.
if i < chNameNum {
ch.Name = name
}
// Create last two Channels with metadata.
if i >= 8 {
ch.Metadata = meta
// Create Channels with metadata.
if i >= chNameNum && i < chNameNum+chMetaNum {
ch.Metadata = metadata
}
// Create Channels with name and metadata.
if i >= n-chNameMetaNum {
ch.Metadata = metadata
ch.Name = name
}
chanRepo.Save(context.Background(), ch)
@ -282,11 +294,11 @@ func TestMultiChannelRetrieval(t *testing.T) {
},
"retrieve channels with existing name": {
owner: email,
offset: 1,
offset: offset,
limit: n,
name: channelName,
size: 1,
total: 2,
name: name,
size: chNameNum + chNameMetaNum - offset,
total: chNameNum + chNameMetaNum,
},
"retrieve all channels with non-existing name": {
owner: email,
@ -300,25 +312,33 @@ func TestMultiChannelRetrieval(t *testing.T) {
owner: email,
offset: 0,
limit: n,
size: 2,
total: n,
metadata: meta,
size: chMetaNum + chNameMetaNum,
total: chMetaNum + chNameMetaNum,
metadata: metadata,
},
"retrieve all channels with non-existing metadata": {
owner: email,
offset: 0,
limit: n,
size: 0,
total: n,
total: 0,
metadata: wrongMeta,
},
"retrieve all channels with existing name and metadata": {
owner: email,
offset: 0,
limit: n,
size: chNameMetaNum,
total: chNameMetaNum,
name: name,
metadata: metadata,
},
}
for desc, tc := range cases {
page, err := chanRepo.RetrieveAll(context.Background(), tc.owner, tc.offset, tc.limit, tc.name, tc.metadata)
size := uint64(len(page.Channels))
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected %d got %d\n", desc, tc.size, size))
assert.Equal(t, tc.total, page.Total, fmt.Sprintf("%s: expected %d got %d\n", desc, tc.total, page.Total))
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", desc, tc.size, size))
assert.Equal(t, tc.total, page.Total, fmt.Sprintf("%s: expected total %d got %d\n", desc, tc.total, page.Total))
assert.Nil(t, err, fmt.Sprintf("%s: expected no error got %d\n", desc, err))
}
}

View File

@ -218,23 +218,11 @@ func (tr thingRepository) RetrieveAll(ctx context.Context, owner string, offset,
items = append(items, th)
}
cq := ""
if name != "" {
cq = `AND LOWER(name) LIKE $2`
}
cq := fmt.Sprintf(`SELECT COUNT(*) FROM things WHERE owner = :owner %s%s;`, nq, mq)
q = fmt.Sprintf(`SELECT COUNT(*) FROM things WHERE owner = $1 %s;`, cq)
total := uint64(0)
switch name {
case "":
if err := tr.db.GetContext(ctx, &total, q, owner); err != nil {
return things.ThingsPage{}, err
}
default:
if err := tr.db.GetContext(ctx, &total, q, owner, name); err != nil {
return things.ThingsPage{}, err
}
total, err := total(ctx, tr.db, cq, params)
if err != nil {
return things.ThingsPage{}, err
}
page := things.ThingsPage{

View File

@ -380,15 +380,24 @@ func TestThingRetrieveByKey(t *testing.T) {
}
func TestMultiThingRetrieval(t *testing.T) {
email := "thing-multi-retrieval@example.com"
name := "mainflux"
metadata := make(map[string]interface{})
metadata["serial"] = "123456"
metadata["type"] = "test"
idp := uuid.New()
dbMiddleware := postgres.NewDatabase(db)
thingRepo := postgres.NewThingRepository(dbMiddleware)
email := "thing-multi-retrieval@example.com"
name := "mainflux"
metadata := things.Metadata{
"field": "value",
}
wrongMeta := things.Metadata{
"wrong": "wrong",
}
idp := uuid.New()
offset := uint64(1)
thNameNum := uint64(3)
thMetaNum := uint64(3)
thNameMetaNum := uint64(2)
n := uint64(10)
for i := uint64(0); i < n; i++ {
thid, err := idp.ID()
@ -397,14 +406,22 @@ func TestMultiThingRetrieval(t *testing.T) {
require.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err))
th := things.Thing{
Owner: email,
ID: thid,
Key: thkey,
Metadata: metadata,
Owner: email,
ID: thid,
Key: thkey,
}
// Create first two Things with name.
if i < 2 {
// Create Things with name.
if i < thNameNum {
th.Name = name
}
// Create Things with metadata.
if i >= thNameNum && i < thNameNum+thMetaNum {
th.Metadata = metadata
}
// Create Things with name and metadata.
if i >= n-thNameMetaNum {
th.Metadata = metadata
th.Name = name
}
@ -446,8 +463,8 @@ func TestMultiThingRetrieval(t *testing.T) {
offset: 1,
limit: n,
name: name,
size: 1,
total: 2,
size: thNameNum + thNameMetaNum - offset,
total: thNameNum + thNameMetaNum,
},
"retrieve things with non-existing name": {
owner: email,
@ -457,12 +474,29 @@ func TestMultiThingRetrieval(t *testing.T) {
size: 0,
total: 0,
},
"retrieve things with metadata": {
"retrieve things with existing metadata": {
owner: email,
offset: 0,
limit: n,
size: n,
total: n,
size: thMetaNum + thNameMetaNum,
total: thMetaNum + thNameMetaNum,
metadata: metadata,
},
"retrieve things with non-existing metadata": {
owner: email,
offset: 0,
limit: n,
size: 0,
total: 0,
metadata: wrongMeta,
},
"retrieve all things with existing name and metadata": {
owner: email,
offset: 0,
limit: n,
size: thNameMetaNum,
total: thNameMetaNum,
name: name,
metadata: metadata,
},
}
@ -470,8 +504,8 @@ func TestMultiThingRetrieval(t *testing.T) {
for desc, tc := range cases {
page, err := thingRepo.RetrieveAll(context.Background(), tc.owner, tc.offset, tc.limit, tc.name, tc.metadata)
size := uint64(len(page.Things))
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected %d got %d\n", desc, tc.size, size))
assert.Equal(t, tc.total, page.Total, fmt.Sprintf("%s: expected %d got %d\n", desc, tc.total, page.Total))
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", desc, tc.size, size))
assert.Equal(t, tc.total, page.Total, fmt.Sprintf("%s: expected total %d got %d\n", desc, tc.total, page.Total))
assert.Nil(t, err, fmt.Sprintf("%s: expected no error got %d\n", desc, err))
}
}