Mainflux.mainflux/things/postgres/clients.go

105 lines
3.2 KiB
Go

// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package postgres
import (
"context"
"database/sql"
"fmt"
"github.com/mainflux/mainflux/internal/postgres"
mfclients "github.com/mainflux/mainflux/pkg/clients"
pgclients "github.com/mainflux/mainflux/pkg/clients/postgres"
"github.com/mainflux/mainflux/pkg/errors"
)
var _ mfclients.Repository = (*clientRepo)(nil)
type clientRepo struct {
pgclients.ClientRepository
}
type Repository interface {
mfclients.Repository
// Save persists the client account. A non-nil error is returned to indicate
// operation failure.
Save(ctx context.Context, client ...mfclients.Client) ([]mfclients.Client, error)
// RetrieveBySecret retrieves a client based on the secret (key).
RetrieveBySecret(ctx context.Context, key string) (mfclients.Client, error)
}
// NewRepository instantiates a PostgreSQL
// implementation of Clients repository.
func NewRepository(db postgres.Database) Repository {
return &clientRepo{
ClientRepository: pgclients.ClientRepository{DB: db},
}
}
func (repo clientRepo) Save(ctx context.Context, cs ...mfclients.Client) ([]mfclients.Client, error) {
tx, err := repo.ClientRepository.DB.BeginTxx(ctx, nil)
if err != nil {
return []mfclients.Client{}, errors.Wrap(errors.ErrCreateEntity, err)
}
var clients []mfclients.Client
for _, cli := range cs {
q := `INSERT INTO clients (id, name, tags, owner_id, identity, secret, metadata, created_at, updated_at, updated_by, status)
VALUES (:id, :name, :tags, :owner_id, :identity, :secret, :metadata, :created_at, :updated_at, :updated_by, :status)
RETURNING id, name, tags, identity, secret, metadata, COALESCE(owner_id, '') AS owner_id, status, created_at, updated_at, updated_by`
dbcli, err := pgclients.ToDBClient(cli)
if err != nil {
return []mfclients.Client{}, errors.Wrap(errors.ErrCreateEntity, err)
}
row, err := repo.ClientRepository.DB.NamedQueryContext(ctx, q, dbcli)
if err != nil {
if err := tx.Rollback(); err != nil {
return []mfclients.Client{}, postgres.HandleError(err, errors.ErrCreateEntity)
}
return []mfclients.Client{}, errors.Wrap(errors.ErrCreateEntity, err)
}
defer row.Close()
row.Next()
dbcli = pgclients.DBClient{}
if err := row.StructScan(&dbcli); err != nil {
return []mfclients.Client{}, err
}
client, err := pgclients.ToClient(dbcli)
if err != nil {
return []mfclients.Client{}, err
}
clients = append(clients, client)
}
if err = tx.Commit(); err != nil {
return []mfclients.Client{}, errors.Wrap(errors.ErrCreateEntity, err)
}
return clients, nil
}
func (repo clientRepo) RetrieveBySecret(ctx context.Context, key string) (mfclients.Client, error) {
q := fmt.Sprintf(`SELECT id, name, tags, COALESCE(owner_id, '') AS owner_id, identity, secret, metadata, created_at, updated_at, updated_by, status
FROM clients
WHERE secret = $1 AND status = %d`, mfclients.EnabledStatus)
dbc := pgclients.DBClient{
Secret: key,
}
if err := repo.DB.QueryRowxContext(ctx, q, key).StructScan(&dbc); err != nil {
if err == sql.ErrNoRows {
return mfclients.Client{}, errors.Wrap(errors.ErrNotFound, err)
}
return mfclients.Client{}, errors.Wrap(errors.ErrViewEntity, err)
}
return pgclients.ToClient(dbc)
}