bottin/data/data.go
Victor Lacasse-Beaudoin 9a0bf87e7b Bump root version to v4
Remove all files from v3

Move all files from v4/ to project root
2023-05-29 18:19:31 -04:00

293 lines
6.2 KiB
Go

package data
import (
"errors"
"fmt"
"git.agecem.com/agecem/bottin/v4/models"
_ "github.com/jackc/pgx/stdlib"
"github.com/jmoiron/sqlx"
)
// DataClient is a postgres client based on sqlx
type DataClient struct {
PostgresConnection PostgresConnection
DB sqlx.DB
}
type PostgresConnection struct {
User string
Password string
Database string
Host string
Port int
SSL bool
}
func NewDataClient(connection PostgresConnection) (*DataClient, error) {
client := &DataClient{PostgresConnection: connection}
connectionString := fmt.Sprintf("postgres://%s:%s@%s:%d/%s",
client.PostgresConnection.User,
client.PostgresConnection.Password,
client.PostgresConnection.Host,
client.PostgresConnection.Port,
client.PostgresConnection.Database,
)
db, err := sqlx.Connect("pgx", connectionString)
if err != nil {
return nil, err
}
client.DB = *db
return client, nil
}
func (d *DataClient) Seed() (int64, error) {
result, err := d.DB.Exec(models.Schema)
if err != nil {
return 0, err
}
rows, err := result.RowsAffected()
if err != nil {
return rows, err
}
return rows, nil
}
// InsertMembres inserts a slice of Membre into a database, returning the amount inserted and any error encountered
func (d *DataClient) InsertMembres(membres []models.Membre) (int64, error) {
var rowsInserted int64
tx, err := d.DB.Beginx()
if err != nil {
tx.Rollback()
return rowsInserted, err
}
for _, membre := range membres {
if membre.ID == "" {
tx.Rollback()
return 0, errors.New("Cannot insert membre with no membre_id")
}
result, err := tx.NamedExec("INSERT INTO membres (id, last_name, first_name, prefered_name, programme_id) VALUES (:id, :last_name, :first_name, :prefered_name, :programme_id);", &membre)
if err != nil {
tx.Rollback()
return 0, err
}
rows, err := result.RowsAffected()
if err != nil {
tx.Rollback()
return 0, err
}
rowsInserted += rows
}
err = tx.Commit()
if err != nil {
return rowsInserted, err
}
return rowsInserted, nil
}
func (d *DataClient) InsertProgrammes(programmes []models.Programme) (int64, error) {
var rowsInserted int64
tx, err := d.DB.Beginx()
if err != nil {
tx.Rollback()
return rowsInserted, err
}
for _, programme := range programmes {
if programme.ID == "" {
tx.Rollback()
return 0, errors.New("Cannot insert programme with no programme_id")
}
result, err := tx.NamedExec("INSERT INTO programmes (id, titre) VALUES (:id, :titre);", &programme)
if err != nil {
tx.Rollback()
return 0, err
}
rows, err := result.RowsAffected()
if err != nil {
tx.Rollback()
return 0, err
}
rowsInserted += rows
}
err = tx.Commit()
if err != nil {
return rowsInserted, err
}
return rowsInserted, nil
}
func (d *DataClient) GetMembre(membreID string) (models.Membre, error) {
var membre models.Membre
rows, err := d.DB.Queryx("SELECT * FROM membres WHERE id = $1 LIMIT 1;", membreID)
if err != nil {
return membre, err
}
for rows.Next() {
err := rows.StructScan(&membre)
if err != nil {
return membre, err
}
}
if membre.ID == "" {
return membre, fmt.Errorf("No membre by that id was found")
}
return membre, nil
}
func (d *DataClient) UpdateMembreName(membreID, newName string) (int64, error) {
result, err := d.DB.Exec("UPDATE membres SET prefered_name = $1 WHERE id = $2;", newName, membreID)
if err != nil {
return 0, err
}
rows, err := result.RowsAffected()
if err != nil {
return rows, err
}
return rows, nil
}
/*
func (d *DataClient) Insert(assets []models.Asset) (id int64, err error) {
// Check for minimal required info
for _, asset := range assets {
if asset.Description == "" {
err = errors.New("Cannot insert: At least one asset has no `description` set.")
return
}
}
tx := d.DB.MustBegin()
for _, asset := range assets {
_, err = tx.NamedExec("INSERT INTO assets (description, status, created_at) VALUES (:description, :status, current_timestamp)", asset)
if err != nil {
return
}
}
err = tx.Commit()
return
}
func (d *DataClient) List() ([]models.Asset, error) {
// Query the database, storing results in a []Person (wrapped in []interface{})
assets := []models.Asset{}
err := d.DB.Select(&assets, "SELECT * FROM assets WHERE deleted_at IS NULL LIMIT 1000")
if err != nil {
return nil, err
}
return assets, nil
}
// RecordEvent allows inserting into events when an asset or a tag is modified
// or deleted.
func (d *DataClient) RecordEvent(assetID, tagID int64, content string) error {
event := models.Event{
AssetID: assetID,
TagID: tagID,
Content: content,
}
_, err := d.DB.NamedExec("INSERT INTO events (asset_id, tag_id, at, content) VALUES (:asset_id, :tag_id, current_timestamp, :content);", event)
if err != nil {
return err
}
return nil
}
func (d *DataClient) Delete(assetIDs []int64) ([]int64, error) {
var rows []int64
tx := d.DB.MustBegin()
for _, assetID := range assetIDs {
result, err := d.DB.Exec("UPDATE assets SET deleted_at = current_timestamp WHERE id = $1 AND deleted_at IS NULL;", assetID)
if err != nil {
return rows, err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return rows, err
}
if rowsAffected != 0 {
rows = append(rows, assetID)
}
}
err := tx.Commit()
if err != nil {
return rows, err
}
for _, assetID := range assetIDs {
d.RecordEvent(assetID, -1, fmt.Sprintf("Asset %d deleted.", assetID))
}
return rows, nil
}
func (d *DataClient) UpdateAssetDescription(assetID int64, description string) (int64, error) {
result, err := d.DB.Exec("UPDATE assets SET description = $1 WHERE id = $2", description, assetID)
if err != nil {
return 0, err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return 0, err
}
if rowsAffected != 0 {
return 0, errors.New("Nothing to do")
}
return rowsAffected, nil
}
func (d *DataClient) UpdateAssetStatus(assetID int64, status string) (int64, error) {
result, err := d.DB.Exec("UPDATE assets SET status = $1 WHERE id = $2", status, assetID)
if err != nil {
return 0, err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return 0, err
}
if rowsAffected != 0 {
return 0, errors.New("Nothing to do")
}
return rowsAffected, nil
}
*/