From 93da47c688fb8306d4968db5a393a981f9b7707b Mon Sep 17 00:00:00 2001 From: maximo tejeda Date: Sun, 25 Feb 2024 21:23:42 -0400 Subject: [PATCH] add db structure --- db/db.go | 43 +++++++ db/models.go | 326 ++++++++++++++++++++++++++++++++++++++++++++++++++ db/schema.sql | 10 ++ 3 files changed, 379 insertions(+) create mode 100644 db/db.go create mode 100644 db/models.go create mode 100644 db/schema.sql diff --git a/db/db.go b/db/db.go new file mode 100644 index 0000000..6497395 --- /dev/null +++ b/db/db.go @@ -0,0 +1,43 @@ +package db + +import ( + "context" + "database/sql" + _ "embed" + "fmt" + + _ "modernc.org/sqlite" +) + +const ( + DEFAULT_DRIVER = "sqlite" +) + +var ( + //go:embed schema.sql + schema string +) + +type DB struct { + *sql.DB +} + +func Dial(ctx context.Context, driver, uri string) *DB { + db, err := sql.Open(driver, uri) + if err != nil { + fmt.Println("Failed to connect to database:", err) + panic(err) + } + err = db.PingContext(ctx) + if err != nil { + fmt.Printf("Pinging with context: %s", err) + panic(err) + } + + _, err = db.ExecContext(ctx, schema) + if err != nil { + panic(err) + } + + return &DB{db} +} diff --git a/db/models.go b/db/models.go new file mode 100644 index 0000000..60093c0 --- /dev/null +++ b/db/models.go @@ -0,0 +1,326 @@ +package db + +import ( + "fmt" + "log/slog" + "slices" + "strings" + "time" +) + +type User struct { + db *DB + log *slog.Logger + ID int + TguID int + Subs []string + Created time.Time + Edited time.Time + Deleted time.Time +} + +type Inst struct { + db *DB + log *slog.Logger + List []string +} + +func NewUser(db *DB, log *slog.Logger) User { + return User{ + log: log, + db: db, + } +} + +// GetAll +// Get all users in db +func (u *User) GetAll(name string) (users []User, err error) { + stmt, err := u.db.Prepare("SELECT users.id, users.tgu_id, users.subs FROM users WHERE users.subs LIKE ?") + if err != nil { + u.log.Error("[user-GetAll]", "error", err) + return nil, err + } + + rows, err := stmt.Query("%" + name + "%") + if err != nil { + u.log.Error("[user-GetAll-stmt]", "error", err) + return nil, err + } + + defer rows.Close() + users = []User{} + for rows.Next() { + user := User{} + subs := "" + if err = rows.Scan(&user.ID, &user.TguID, &subs); err != nil { + u.log.Error("[user-GetAll-scanning]", "error", err) + return users, err + } + if subs == "" { + u.log.Info("[user-GetAll-scanning] returning subs empty") + continue + } + user.Subs = strings.Split(subs, ",") + u.log.Info("user", "no", user) + users = append(users, user) + } + if err := rows.Err(); err != nil { + u.log.Error("[user-GetAll-returning]", "error", err) + return users, err + } + return users, nil +} + +// Get +// Get an specific user +func (u *User) Get(telegramID int64) (user User, err error) { + stmt, err := u.db.Prepare("SELECT users.id, users.tgu_id, users.subs FROM users WHERE tgu_id=?") + if err != nil { + u.log.Error("[user-Get]", "error", err) + return user, err + } + subs := "" + err = stmt.QueryRow(telegramID).Scan(&user.ID, &user.TguID, &subs) + if err != nil { + u.log.Error("[user-Get-stmt]", "error", err) + return user, err + } + if subs != "" { + user.Subs = strings.Split(subs, ",") + } else { + user.Subs = []string{} + } + u.ID, u.TguID, u.Subs = user.ID, user.TguID, user.Subs + return user, nil +} + +// Add +// Add user to database +func (u *User) Add(telegramID int64) (bool, error) { + stmt, err := u.db.Prepare("INSERT INTO users ('tgu_id', 'subs', 'created', 'edited') VALUES(?,?,datetime(),datetime())") + if err != nil { + u.log.Error("[user-Add-stmt]", "error", err) + return false, err + } + _, err = stmt.Exec(telegramID, "") + if err != nil { + u.log.Error("[user-Add-exec]", "error", err) + return false, err + } + return true, nil + +} + +// Edit +// edit user info in database +func (u *User) Subscribe(name string) (err error) { + if u.TguID == 0 || u.ID == 0 { + err = fmt.Errorf("user needs to have a telegram id or reference on db") + u.log.Error("[user-Subscribe-check]", "error", err) + return err + } + idx := slices.Index[[]string](u.Subs, name) + if idx >= 0 { + return fmt.Errorf("user alredy subscribed to inst") + } + u.Subs = append(u.Subs, name) + stmt, err := u.db.Prepare("UPDATE users SET subs=? WHERE tgu_id=?") + if err != nil { + u.log.Error("[user-Subscribe-stmt]", "error", err) + return err + } + strSubs := strings.Join(u.Subs, ",") + _, err = stmt.Exec(strSubs, u.TguID) + if err != nil { + u.log.Error("[user-Subscribe-exec]", "error", err) + return err + } + return nil +} + +// Delete +// Delete user from database +func (u *User) Unsubscribe(name string) (err error) { + if u.TguID == 0 || u.ID == 0 { + err = fmt.Errorf("user needs to have a telegram id or reference on db") + u.log.Error("[user-UnSubscribe-check]", "error", err) + return err + } + if len(u.Subs) <= 0 { + err = fmt.Errorf("user needs to have a subscription to unsubcribe") + u.log.Error("[user-UnSubscribe-check]", "error", err) + return err + } + + idx := slices.Index[[]string](u.Subs, name) + if idx >= 0 { + u.Subs = slices.Delete[[]string](u.Subs, idx, idx+1) + } else { + err = fmt.Errorf("user is not subscribed to %s", name) + u.log.Error("[user-UnSubscribe-check]", "error", err) + return err + } + + stmt, err := u.db.Prepare("UPDATE users SET subs=? WHERE tgu_id=?") + if err != nil { + u.log.Error("[user-UnSubscribe-stmt]", "error", err) + return err + } + strSubs := strings.Join(u.Subs, ",") + _, err = stmt.Exec(strSubs, u.TguID) + if err != nil { + u.log.Error("[user-UnSubscribe-exec]", "error", err) + return err + } + return nil +} + +// Reset +// Clean user subscriptions on system +func (u *User) Reset() (err error) { + if u.TguID == 0 || u.ID == 0 { + err = fmt.Errorf("user needs to have a telegram id or reference on db") + u.log.Error("[user-Subscribe-check]", "error", err) + return err + } + stmt, err := u.db.Prepare("UPDATE users SET subs=? WHERE tgu_id=?") + if err != nil { + u.log.Error("[user-Subscribe-stmt]", "error", err) + return err + } + _, err = stmt.Exec("", u.TguID) + if err != nil { + u.log.Error("[user-Subscribe-exec]", "error", err) + return err + } + return nil +} + +func NewInst(dbx *DB, log *slog.Logger) Inst { + return Inst{ + log: log, + db: dbx, + } +} + +func (i *Inst) GetAll() ([]string, error) { + stmt, err := i.db.Prepare("SELECT DISTINCT dolars.name FROM dolars WHERE name LIKE '%ban%' OR name LIKE '%scoti%' OR name LIKE '%asociacion%'") + if err != nil { + i.log.Error("[inst-GetAll]", "error", err) + return nil, err + } + rows, err := stmt.Query() + if err != nil { + i.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 (i *Inst) GetBancos() ([]string, error) { + stmt, err := i.db.Prepare("SELECT DISTINCT dolars.name FROM dolars WHERE name LIKE '%ban%' OR name LIKE '%scoti%'") + if err != nil { + i.log.Error("[inst-GetAll]", "error", err) + return nil, err + } + rows, err := stmt.Query() + if err != nil { + i.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 (i *Inst) GetCajas() ([]string, error) { + stmt, err := i.db.Prepare("SELECT DISTINCT dolars.name FROM dolars WHERE name LIKE '%asociacion%'") + if err != nil { + i.log.Error("[inst-GetAll]", "error", err) + return nil, err + } + rows, err := stmt.Query() + if err != nil { + i.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 (i *Inst) GetAgentes() ([]string, error) { + stmt, err := i.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 { + i.log.Error("[inst-GetAll]", "error", err) + return nil, err + } + rows, err := stmt.Query() + if err != nil { + i.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 + +} diff --git a/db/schema.sql b/db/schema.sql new file mode 100644 index 0000000..be015db --- /dev/null +++ b/db/schema.sql @@ -0,0 +1,10 @@ +PRAGMA foreign_keys = ON; + +CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY NOT NULL, + tgu_id INTEGER NOT NULL UNIQUE, + subs TEXT NOT NULL, + created TEXT NOT NULL, + edited TEXT NOT NULL, + deleted TEXT +);