ADD external definitions

This commit is contained in:
maximo tejeda 2024-02-25 21:22:48 -04:00
parent 13232710bb
commit 74f881ac9c
2 changed files with 315 additions and 0 deletions

302
edb/db.go Normal file
View File

@ -0,0 +1,302 @@
package db
import (
"database/sql"
_ "embed"
"errors"
"fmt"
"log/slog"
"time"
"github.com/maximotejeda/us_dop_bot/models"
_ "modernc.org/sqlite"
)
type DB struct {
*sql.DB
log *slog.Logger
}
type change struct {
Before models.Institucion `json:"before"`
After models.Institucion `json:"after"`
}
type Message struct {
Message string `json:"message"`
Data change `json:"data"`
Error error `json:"error"`
}
// Dial
func Dial(path string, log *slog.Logger) *DB {
db, err := sql.Open("sqlite", path)
if err != nil {
fmt.Printf("opening database: %s", err.Error())
panic("opening database")
}
if err := db.Ping(); err != nil {
fmt.Printf("pinging database: %s", err.Error())
panic("pinging database")
}
return &DB{db, log}
}
// Inspect
// Handle behavior of the changes
// Will report errors to a nats consumer
func (db *DB) Inspect(enter models.Institucion) error {
if db == nil {
return fmt.Errorf("nil or empty database")
}
// Get last row added
inst, err := db.GetLatest(enter.Parser, enter.Name)
// if no rows are found because of first enter a name - parser ?
if errors.Is(sql.ErrNoRows, err) {
db.log.Info("adding new item to table: ", "parse", enter.Parser, "name", enter.Name)
if err != nil {
db.log.Error("marshaling struct", "error", err)
}
return db.AddNew(enter)
}
// check prices compra venta
if inst == nil {
db.log.Error("row is nil", "name", enter.Name, "parser", enter.Parser)
return fmt.Errorf("row is nil, not entering row")
}
if enter.Compra == inst.Compra && enter.Venta == inst.Venta {
return nil
} else {
// if one of them changes create a new row
db.log.Info("change registered, adding item", "parse", enter.Parser, "name", enter.Name, "compra enter", enter.Compra, "compra db", inst.Compra, "venta enter", enter.Venta, "venta db", inst.Venta)
if err != nil {
db.log.Error("marshaling struct", "error", err)
}
return db.AddNew(enter)
}
}
// GetLatest
// returns the latest row in a specific parser and name
// we are using DateTime in DB and date.Datetime in go
func (db *DB) GetLatest(parser string, name string) (inst *models.Institucion, err error) {
var parsed string
inst = &models.Institucion{}
stmt, err := db.Prepare("SELECT name, parser, compra, venta, parsed FROM dolars WHERE parser = ? AND name = ? ORDER BY parsed DESC LIMIT 1;")
if err != nil {
db.log.Error("preparing", "error", err.Error())
return nil, err
}
defer stmt.Close()
if err := stmt.QueryRow(parser, name).Scan(&inst.Name, &inst.Parser, &inst.Compra, &inst.Venta, &parsed); err != nil {
db.log.Error("getting latest", "error", err.Error(), "parser", parser, "name", name)
return nil, err
}
inst.Parsed, err = time.Parse(time.DateTime, parsed)
if err != nil {
//db.log.Error("parsed", "error", err.Error())
return nil, err
}
return inst, nil
}
// AddNew
// Add a new row in the dolar table
// Will send to nats changes on prices
func (db *DB) AddNew(row models.Institucion) error {
stmt, err := db.Prepare("INSERT INTO dolars (name, compra, venta, parser, parsed) VALUES(?,?,?,?,?);")
if err != nil {
return err
}
defer stmt.Close()
parsed := row.Parsed.Format(time.DateTime)
_, err = stmt.Exec(&row.Name, &row.Compra, &row.Venta, &row.Parser, &parsed)
if err != nil {
return err
}
return nil
}
func (db *DB) GetAll() ([]string, error) {
stmt, err := db.Prepare("SELECT DISTINCT dolars.name FROM dolars WHERE name LIKE '%ban%' OR name LIKE '%scoti%' OR name LIKE '%asociacion%'")
if err != nil {
db.log.Error("[db-GetAll]", "error", err)
return nil, err
}
rows, err := stmt.Query()
if err != nil {
db.log.Error("[db-GetAll-stmt]", "error", err)
return nil, err
}
defer rows.Close()
insts := []string{}
for rows.Next() {
inst := ""
if err = rows.Scan(&inst); err != nil {
return nil, err
}
if inst == "" {
continue
}
insts = append(insts, inst)
}
if err := rows.Err(); err != nil {
return insts, err
}
return insts, nil
}
func (db *DB) GetBancos() ([]string, error) {
stmt, err := db.Prepare("SELECT DISTINCT dolars.name FROM dolars WHERE name LIKE '%ban%' OR name LIKE '%scoti%'")
if err != nil {
db.log.Error("[inst-GetAll]", "error", err)
return nil, err
}
rows, err := stmt.Query()
if err != nil {
db.log.Error("[inst-GetAll-stmt]", "error", err)
return nil, err
}
defer rows.Close()
insts := []string{}
for rows.Next() {
inst := ""
if err = rows.Scan(&inst); err != nil {
return nil, err
}
if inst == "" {
continue
}
insts = append(insts, inst)
}
if err := rows.Err(); err != nil {
return insts, err
}
return insts, nil
}
func (db *DB) GetCajas() ([]string, error) {
stmt, err := db.Prepare("SELECT DISTINCT dolars.name FROM dolars WHERE name LIKE '%asociacion%'")
if err != nil {
db.log.Error("[inst-GetAll]", "error", err)
return nil, err
}
rows, err := stmt.Query()
if err != nil {
db.log.Error("[inst-GetAll-stmt]", "error", err)
return nil, err
}
defer rows.Close()
insts := []string{}
for rows.Next() {
inst := ""
if err = rows.Scan(&inst); err != nil {
return nil, err
}
if inst == "" {
continue
}
insts = append(insts, inst)
}
if err := rows.Err(); err != nil {
return insts, err
}
return insts, nil
}
func (db *DB) GetAgentes() ([]string, error) {
stmt, err := db.Prepare("SELECT DISTINCT dolars.name FROM dolars WHERE name NOT LIKE '%ban%' AND name NOT LIKE '%scoti%' AND name NOT LIKE '%asociacion%'")
if err != nil {
db.log.Error("[inst-GetAll]", "error", err)
return nil, err
}
rows, err := stmt.Query()
if err != nil {
db.log.Error("[inst-GetAll-stmt]", "error", err)
return nil, err
}
defer rows.Close()
insts := []string{}
for rows.Next() {
inst := ""
if err = rows.Scan(&inst); err != nil {
return nil, err
}
if inst == "" {
continue
}
insts = append(insts, inst)
}
if err := rows.Err(); err != nil {
return insts, err
}
return insts, nil
}
func (db *DB) GetLastPrice(name string) (inst *models.Institucion, err error) {
var parsed string
inst = &models.Institucion{}
stmt, err := db.Prepare("SELECT name, parser, compra, venta, parsed FROM dolars WHERE name = ? ORDER BY parsed DESC LIMIT 1;")
if err != nil {
db.log.Error("preparing", "error", err.Error())
return nil, err
}
defer stmt.Close()
if err := stmt.QueryRow(name).Scan(&inst.Name, &inst.Parser, &inst.Compra, &inst.Venta, &parsed); err != nil {
db.log.Error("getting last price", "error", err.Error(), "name", name)
return nil, err
}
inst.Parsed, err = time.Parse(time.DateTime, parsed)
if err != nil {
//db.log.Error("parsed", "error", err.Error())
return nil, err
}
return inst, nil
}
func (db *DB) GetChangeSince(name string, duration time.Duration) (insts []*models.Institucion, err error) {
date := time.Now().Add(-duration).Format(time.DateTime)
stmt, err := db.Prepare("SELECT name, parser, compra, venta, parsed FROM dolars WHERE name = ? AND parsed > ? ORDER BY parsed DESC;")
if err != nil {
db.log.Error("[GetChangeSince] preparing", "error", err.Error())
return nil, err
}
defer stmt.Close()
rows, err := stmt.Query(name, date)
if err != nil {
db.log.Error("[GetChangeSince] preparing", "error", err.Error())
return nil, err
}
defer rows.Close()
for rows.Next() {
inst := models.Institucion{}
parsed := ""
if err := rows.Scan(&inst.Name, &inst.Parser, &inst.Compra, &inst.Venta, &parsed); err != nil {
db.log.Error("[GetChangeSince] scanning", "error", err)
return nil, err
}
inst.Parsed, err = time.Parse(time.DateTime, parsed)
if err != nil {
//db.log.Error("parsed", "error", err.Error())
continue
}
insts = append(insts, &inst)
}
return insts, nil
}

13
models/models.go Normal file
View File

@ -0,0 +1,13 @@
package models
import (
"time"
)
type Institucion struct {
Name string `json:"name"`
Compra float64 `json:"compra"`
Venta float64 `json:"venta"`
Parser string `json:"parser"`
Parsed time.Time `json:"parsed"`
}