2023-03-06 14:01:18 -05:00
|
|
|
package data
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2023-05-29 18:19:31 -04:00
|
|
|
"fmt"
|
2023-03-06 14:01:18 -05:00
|
|
|
|
2023-06-02 16:08:08 -04:00
|
|
|
"git.agecem.com/agecem/bottin/models"
|
2023-05-29 18:19:31 -04:00
|
|
|
_ "github.com/jackc/pgx/stdlib"
|
|
|
|
"github.com/jmoiron/sqlx"
|
2023-06-02 02:44:11 -04:00
|
|
|
"github.com/spf13/viper"
|
2023-03-06 14:01:18 -05:00
|
|
|
)
|
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
// DataClient is a postgres client based on sqlx
|
|
|
|
type DataClient struct {
|
|
|
|
PostgresConnection PostgresConnection
|
|
|
|
DB sqlx.DB
|
|
|
|
}
|
2023-03-06 14:01:18 -05:00
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
type PostgresConnection struct {
|
|
|
|
User string
|
|
|
|
Password string
|
|
|
|
Database string
|
|
|
|
Host string
|
|
|
|
Port int
|
|
|
|
SSL bool
|
2023-03-06 14:01:18 -05:00
|
|
|
}
|
|
|
|
|
2023-06-02 02:44:11 -04:00
|
|
|
func NewDataClientFromViper() (*DataClient, error) {
|
|
|
|
client, err := NewDataClient(
|
|
|
|
PostgresConnection{
|
|
|
|
User: viper.GetString("db.user"),
|
|
|
|
Password: viper.GetString("db.password"),
|
|
|
|
Host: viper.GetString("db.host"),
|
|
|
|
Database: viper.GetString("db.database"),
|
|
|
|
Port: viper.GetInt("db.port"),
|
|
|
|
})
|
|
|
|
|
|
|
|
return client, err
|
|
|
|
}
|
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
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,
|
|
|
|
)
|
2023-03-06 14:01:18 -05:00
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
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
|
|
|
|
}
|
2023-03-06 14:01:18 -05:00
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
return rows, nil
|
|
|
|
}
|
2023-03-06 14:01:18 -05:00
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
// 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
|
|
|
|
}
|
2023-03-06 14:01:18 -05:00
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
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
|
2023-03-06 14:01:18 -05:00
|
|
|
}
|
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
rows, err := result.RowsAffected()
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return 0, err
|
|
|
|
}
|
2023-03-06 14:01:18 -05:00
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
rowsInserted += rows
|
2023-03-06 14:01:18 -05:00
|
|
|
}
|
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
err = tx.Commit()
|
2023-03-06 14:01:18 -05:00
|
|
|
if err != nil {
|
2023-05-29 18:19:31 -04:00
|
|
|
return rowsInserted, err
|
2023-03-06 14:01:18 -05:00
|
|
|
}
|
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
return rowsInserted, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *DataClient) InsertProgrammes(programmes []models.Programme) (int64, error) {
|
|
|
|
var rowsInserted int64
|
|
|
|
tx, err := d.DB.Beginx()
|
2023-03-06 14:01:18 -05:00
|
|
|
if err != nil {
|
2023-05-29 18:19:31 -04:00
|
|
|
tx.Rollback()
|
|
|
|
return rowsInserted, err
|
2023-03-06 14:01:18 -05:00
|
|
|
}
|
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
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
|
2023-03-06 14:01:18 -05:00
|
|
|
}
|
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
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
|
2023-03-06 14:01:18 -05:00
|
|
|
}
|
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
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
|
2023-03-06 14:01:18 -05:00
|
|
|
}
|
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
}
|
2023-03-06 14:01:18 -05:00
|
|
|
}
|
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
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
|
|
|
|
}
|
2023-03-06 14:01:18 -05:00
|
|
|
}
|
|
|
|
|
2023-05-29 18:19:31 -04:00
|
|
|
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
|
|
|
|
}
|
2023-03-06 14:01:18 -05:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2023-05-29 18:19:31 -04:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
*/
|