alert usecases & repository methods
This commit is contained in:
parent
16d38bb3cf
commit
0e73841b3e
5 changed files with 191 additions and 0 deletions
12
internal/entities/alert.go
Normal file
12
internal/entities/alert.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package entities
|
||||
|
||||
import "github.com/shopspring/decimal"
|
||||
|
||||
type AlertID string
|
||||
|
||||
type Alert struct {
|
||||
ID AlertID
|
||||
UserID UserID
|
||||
Price decimal.Decimal
|
||||
Instrument Instrument
|
||||
}
|
||||
|
|
@ -1 +1,115 @@
|
|||
package postgresql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"gitea.computernetthings.ru/yash/crypto_alert_bot/internal/entities"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
const saveAlertQuery = `
|
||||
insert into alert(user_id, instrument_id, price)
|
||||
values ($1, $2, $3)
|
||||
returning id`
|
||||
|
||||
func (p *Postgresql) SaveAlert(ctx context.Context, alert *entities.Alert) (entities.AlertID, error) {
|
||||
var id entities.AlertID
|
||||
|
||||
err := p.db.QueryRow(ctx, saveAlertQuery, alert.UserID, alert.Instrument.ID, alert.Price).Scan(&id)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to exec saveAlertQuery: %w", err)
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
const alertByIDQuery = `
|
||||
select a.id, a.user_id, a.price, i.id, c_base.symbol, c_quote.symbol
|
||||
from alert a
|
||||
join instrument i on i.id = a.instrument_id
|
||||
join currency c_base on c_base.id = i.base_currency_id
|
||||
join currency c_quote on c_quote.id = i.quoted_currency_id
|
||||
where a.id = $1 and a.active = true`
|
||||
|
||||
func (p *Postgresql) AlertByID(ctx context.Context, id entities.AlertID) (*entities.Alert, error) {
|
||||
var alert entities.Alert
|
||||
var priceStr string
|
||||
|
||||
err := p.db.QueryRow(ctx, alertByIDQuery, id).Scan(
|
||||
&alert.ID, &alert.UserID, &priceStr,
|
||||
&alert.Instrument.ID, &alert.Instrument.BaseCurrency, &alert.Instrument.QuoteCurrency,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to exec alertByIDQuery: %w", err)
|
||||
}
|
||||
|
||||
alert.Price, err = decimal.NewFromString(priceStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse alert price: %w", err)
|
||||
}
|
||||
|
||||
return &alert, nil
|
||||
}
|
||||
|
||||
const alertsByUserIDQuery = `
|
||||
select a.id, a.user_id, a.price, i.id, c_base.symbol, c_quote.symbol
|
||||
from alert a
|
||||
join instrument i on i.id = a.instrument_id
|
||||
join currency c_base on c_base.id = i.base_currency_id
|
||||
join currency c_quote on c_quote.id = i.quoted_currency_id
|
||||
where a.user_id = $1 and a.active = true
|
||||
order by a.id
|
||||
offset $2 limit $3`
|
||||
|
||||
func (p *Postgresql) AlertsByUserID(ctx context.Context, userID entities.UserID, offset, limit int) ([]entities.Alert, error) {
|
||||
rows, err := p.db.Query(ctx, alertsByUserIDQuery, userID, offset, limit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to exec alertsByUserIDQuery: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var alerts []entities.Alert
|
||||
for rows.Next() {
|
||||
var alert entities.Alert
|
||||
var priceStr string
|
||||
|
||||
if err := rows.Scan(
|
||||
&alert.ID, &alert.UserID, &priceStr,
|
||||
&alert.Instrument.ID, &alert.Instrument.BaseCurrency, &alert.Instrument.QuoteCurrency,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to scan alert row: %w", err)
|
||||
}
|
||||
|
||||
alert.Price, err = decimal.NewFromString(priceStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse alert price: %w", err)
|
||||
}
|
||||
|
||||
alerts = append(alerts, alert)
|
||||
}
|
||||
|
||||
return alerts, nil
|
||||
}
|
||||
|
||||
const deleteAlertQuery = "update alert set active = false where id = $1"
|
||||
|
||||
func (p *Postgresql) DeleteAlert(ctx context.Context, id entities.AlertID) error {
|
||||
_, err := p.db.Exec(ctx, deleteAlertQuery, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to exec deleteAlertQuery: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const updateAlertPriceQuery = "update alert set price = $2 where id = $1"
|
||||
|
||||
func (p *Postgresql) UpdateAlertPrice(ctx context.Context, id entities.AlertID, price decimal.Decimal) error {
|
||||
_, err := p.db.Exec(ctx, updateAlertPriceQuery, id, price.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to exec updateAlertPriceQuery: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ create table if not exists instrument (
|
|||
|
||||
create table if not exists alert (
|
||||
id uuid primary key not null default gen_random_uuid(),
|
||||
user_id uuid references users(id) not null,
|
||||
instrument_id uuid references instrument(id) not null,
|
||||
price text not null,
|
||||
active bool not null default true
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
|
||||
"gitea.computernetthings.ru/yash/crypto_alert_bot/internal/entities"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
type Storage interface {
|
||||
|
|
@ -13,4 +14,10 @@ type Storage interface {
|
|||
|
||||
InstrumentList(ctx context.Context, offset, limit int) ([]entities.Instrument, error)
|
||||
CreateInstrument(ctx context.Context, instrument *entities.Instrument) (entities.InstrumentID, error)
|
||||
|
||||
SaveAlert(ctx context.Context, alert *entities.Alert) (entities.AlertID, error)
|
||||
AlertByID(ctx context.Context, id entities.AlertID) (*entities.Alert, error)
|
||||
AlertsByUserID(ctx context.Context, userID entities.UserID, offset, limit int) ([]entities.Alert, error)
|
||||
DeleteAlert(ctx context.Context, id entities.AlertID) error
|
||||
UpdateAlertPrice(ctx context.Context, id entities.AlertID, price decimal.Decimal) error
|
||||
}
|
||||
|
|
|
|||
57
internal/usecase/alert.go
Normal file
57
internal/usecase/alert.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package usecase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"gitea.computernetthings.ru/yash/crypto_alert_bot/internal/entities"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
func (uc *Usecase) CreateAlert(ctx context.Context, alert *entities.Alert) (entities.AlertID, error) {
|
||||
id, err := uc.storage.SaveAlert(ctx, alert)
|
||||
if err != nil {
|
||||
uc.log.Error("failed to create alert", "alert", alert, "err", err)
|
||||
return "", fmt.Errorf("failed to create alert: %w", err)
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (uc *Usecase) Alert(ctx context.Context, alertID entities.AlertID) (*entities.Alert, error) {
|
||||
alert, err := uc.storage.AlertByID(ctx, alertID)
|
||||
if err != nil {
|
||||
uc.log.Error("failed to get alert", "alert_id", alertID, "err", err)
|
||||
return nil, fmt.Errorf("failed to get alert: %w", err)
|
||||
}
|
||||
|
||||
return alert, nil
|
||||
}
|
||||
|
||||
func (uc *Usecase) Alerts(ctx context.Context, userID entities.UserID, offset, limit int) ([]entities.Alert, error) {
|
||||
alerts, err := uc.storage.AlertsByUserID(ctx, userID, offset, limit)
|
||||
if err != nil {
|
||||
uc.log.Error("failed to get alerts", "user_id", userID, "err", err)
|
||||
return nil, fmt.Errorf("failed to get alerts: %w", err)
|
||||
}
|
||||
|
||||
return alerts, nil
|
||||
}
|
||||
|
||||
func (uc *Usecase) RemoveAlert(ctx context.Context, alertID entities.AlertID) error {
|
||||
if err := uc.storage.DeleteAlert(ctx, alertID); err != nil {
|
||||
uc.log.Error("failed to remove alert", "alert_id", alertID, "err", err)
|
||||
return fmt.Errorf("failed to remove alert: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uc *Usecase) UpdateAlertPrice(ctx context.Context, alertID entities.AlertID, price decimal.Decimal) error {
|
||||
if err := uc.storage.UpdateAlertPrice(ctx, alertID, price); err != nil {
|
||||
uc.log.Error("failed to update alert price", "alert_id", alertID, "price", price, "err", err)
|
||||
return fmt.Errorf("failed to update alert price: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue