mirror of
https://github.com/absmach/supermq.git
synced 2026-06-23 04:20:17 +00:00
67180a55f7
* update MG errors Signed-off-by: Arvindh <arvindh91@gmail.com> * update MG errors Signed-off-by: Arvindh <arvindh91@gmail.com> * sync with supermq main Signed-off-by: Arvindh <arvindh91@gmail.com> * update MG errors Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com>
165 lines
4.2 KiB
Go
165 lines
4.2 KiB
Go
// Copyright (c) Abstract Machines
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package postgres
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/absmach/magistrala/consumers/notifiers"
|
|
"github.com/absmach/supermq/pkg/errors"
|
|
repoerr "github.com/absmach/supermq/pkg/errors/repository"
|
|
"github.com/jackc/pgerrcode"
|
|
"github.com/jackc/pgx/v5/pgconn"
|
|
)
|
|
|
|
var _ notifiers.SubscriptionsRepository = (*subscriptionsRepo)(nil)
|
|
|
|
type subscriptionsRepo struct {
|
|
db Database
|
|
}
|
|
|
|
// New instantiates a PostgreSQL implementation of Subscriptions repository.
|
|
func New(db Database) notifiers.SubscriptionsRepository {
|
|
return &subscriptionsRepo{
|
|
db: db,
|
|
}
|
|
}
|
|
|
|
func (repo subscriptionsRepo) Save(ctx context.Context, sub notifiers.Subscription) (string, error) {
|
|
q := `INSERT INTO subscriptions (id, owner_id, contact, topic) VALUES (:id, :owner_id, :contact, :topic) RETURNING id`
|
|
|
|
dbSub := dbSubscription{
|
|
ID: sub.ID,
|
|
OwnerID: sub.OwnerID,
|
|
Contact: sub.Contact,
|
|
Topic: sub.Topic,
|
|
}
|
|
|
|
row, err := repo.db.NamedQueryContext(ctx, q, dbSub)
|
|
if err != nil {
|
|
if pqErr, ok := err.(*pgconn.PgError); ok && pqErr.Code == pgerrcode.UniqueViolation {
|
|
return "", errors.Wrap(notifiers.ErrSubscriptionsAlreadyExists, err)
|
|
}
|
|
return "", errors.Wrap(repoerr.ErrCreateEntity, err)
|
|
}
|
|
defer row.Close()
|
|
|
|
return sub.ID, nil
|
|
}
|
|
|
|
func (repo subscriptionsRepo) Retrieve(ctx context.Context, id string) (notifiers.Subscription, error) {
|
|
q := `SELECT id, owner_id, contact, topic FROM subscriptions WHERE id = $1`
|
|
sub := dbSubscription{}
|
|
if err := repo.db.QueryRowxContext(ctx, q, id).StructScan(&sub); err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return notifiers.Subscription{}, errors.Wrap(repoerr.ErrNotFound, err)
|
|
}
|
|
return notifiers.Subscription{}, errors.Wrap(repoerr.ErrViewEntity, err)
|
|
}
|
|
|
|
return fromDBSub(sub), nil
|
|
}
|
|
|
|
func (repo subscriptionsRepo) RetrieveAll(ctx context.Context, pm notifiers.PageMetadata) (notifiers.Page, error) {
|
|
q := `SELECT id, owner_id, contact, topic FROM subscriptions`
|
|
args := make(map[string]any)
|
|
if pm.Topic != "" {
|
|
args["topic"] = pm.Topic
|
|
}
|
|
if pm.Contact != "" {
|
|
args["contact"] = pm.Contact
|
|
}
|
|
var condition string
|
|
if len(args) > 0 {
|
|
var cond []string
|
|
for k := range args {
|
|
cond = append(cond, fmt.Sprintf("%s = :%s", k, k))
|
|
}
|
|
condition = fmt.Sprintf(" WHERE %s", strings.Join(cond, " AND "))
|
|
q = fmt.Sprintf("%s%s", q, condition)
|
|
}
|
|
args["offset"] = pm.Offset
|
|
q = fmt.Sprintf("%s OFFSET :offset", q)
|
|
if pm.Limit > 0 {
|
|
q = fmt.Sprintf("%s LIMIT :limit", q)
|
|
args["limit"] = pm.Limit
|
|
}
|
|
|
|
rows, err := repo.db.NamedQueryContext(ctx, q, args)
|
|
if err != nil {
|
|
return notifiers.Page{}, errors.Wrap(repoerr.ErrViewEntity, err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var subs []notifiers.Subscription
|
|
for rows.Next() {
|
|
sub := dbSubscription{}
|
|
if err := rows.StructScan(&sub); err != nil {
|
|
return notifiers.Page{}, errors.Wrap(repoerr.ErrViewEntity, err)
|
|
}
|
|
subs = append(subs, fromDBSub(sub))
|
|
}
|
|
|
|
if len(subs) == 0 {
|
|
return notifiers.Page{}, repoerr.ErrNotFound
|
|
}
|
|
|
|
cq := fmt.Sprintf(`SELECT COUNT(*) FROM subscriptions %s`, condition)
|
|
total, err := total(ctx, repo.db, cq, args)
|
|
if err != nil {
|
|
return notifiers.Page{}, errors.Wrap(repoerr.ErrViewEntity, err)
|
|
}
|
|
|
|
ret := notifiers.Page{
|
|
PageMetadata: pm,
|
|
Total: total,
|
|
Subscriptions: subs,
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func (repo subscriptionsRepo) Remove(ctx context.Context, id string) error {
|
|
q := `DELETE from subscriptions WHERE id = $1`
|
|
|
|
if r := repo.db.QueryRowxContext(ctx, q, id); r.Err() != nil {
|
|
return errors.Wrap(repoerr.ErrRemoveEntity, r.Err())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func total(ctx context.Context, db Database, query string, params any) (uint, error) {
|
|
rows, err := db.NamedQueryContext(ctx, query, params)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer rows.Close()
|
|
var total uint
|
|
if rows.Next() {
|
|
if err := rows.Scan(&total); err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
return total, nil
|
|
}
|
|
|
|
type dbSubscription struct {
|
|
ID string `db:"id"`
|
|
OwnerID string `db:"owner_id"`
|
|
Contact string `db:"contact"`
|
|
Topic string `db:"topic"`
|
|
}
|
|
|
|
func fromDBSub(sub dbSubscription) notifiers.Subscription {
|
|
return notifiers.Subscription{
|
|
ID: sub.ID,
|
|
OwnerID: sub.OwnerID,
|
|
Contact: sub.Contact,
|
|
Topic: sub.Topic,
|
|
}
|
|
}
|