package main import ( "context" _ "embed" "fmt" "github.com/jackc/pgx/v5/pgxpool" ) //go:embed sql/schema.sql var sqlSchema string //go:embed sql/views.sql var sqlViews string type PostgresClient struct { //TODO move context out of client Ctx context.Context Pool *pgxpool.Pool } func (db *PostgresClient) CreateOrReplaceSchema() error { _, err := db.Pool.Exec(db.Ctx, sqlSchema) return err } func (db *PostgresClient) CreateOrReplaceViews() error { _, err := db.Pool.Exec(db.Ctx, sqlViews) return err } // InsertMembres inserts a slice of Membre into a database, returning the amount inserted and any error encountered func (d *PostgresClient) InsertMembres(membres ...Membre) (inserted int64, err error) { select { case <-d.Ctx.Done(): return inserted, fmt.Errorf("PostgresClient.Ctx closed: %s", d.Ctx.Err()) default: tx, err := d.Pool.Begin(d.Ctx) if err != nil { return inserted, err } defer tx.Rollback(d.Ctx) for i, membre := range membres { if membre.ID == "" { return inserted, fmt.Errorf("insertion ligne %d: membre requiert numéro étudiant valide", i) } result, err := tx.Exec(d.Ctx, ` INSERT INTO membres (id, last_name, first_name, prefered_name, programme_id) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (id) DO NOTHING;`, membre.ID, membre.LastName, membre.FirstName, membre.PreferedName, membre.ProgrammeID, ) if err != nil { return 0, err } inserted += result.RowsAffected() } if err = tx.Commit(d.Ctx); err != nil { return 0, err } return inserted, err } } func (d *PostgresClient) InsertProgrammes(programmes ...Programme) (inserted int64, err error) { select { case <-d.Ctx.Done(): return inserted, fmt.Errorf("PostgresClient.Ctx closed: %s", d.Ctx.Err()) default: tx, err := d.Pool.Begin(d.Ctx) if err != nil { return inserted, err } defer tx.Rollback(d.Ctx) for _, programme := range programmes { if programme.ID == "" { return 0, fmt.Errorf("Cannot insert programme with no programme_id") } result, err := tx.Exec(d.Ctx, ` INSERT INTO programmes (id, name) VALUES ($1, $2) ON CONFLICT DO NOTHING;`, programme.ID, programme.Name) if err != nil { return 0, err } inserted += result.RowsAffected() } if err := tx.Commit(d.Ctx); err != nil { return inserted, err } return inserted, err } } /* func (d *PostgresClient) GetMembre(membreID string) (Membre, error) { var membre Membre rows, err := d.Pool.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 *PostgresClient) UpdateMembreName(membreID, newName string) (int64, error) { result, err := d.Pool.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 *PostgresClient) GetMembres() (membres []Membre, err error) { select { case <-d.Ctx.Done(): return nil, fmt.Errorf("PostgresClient.Ctx closed: %s", d.Ctx.Err()) default: rows, err := d.Pool.Query(d.Ctx, ` SELECT membres.id, membres.last_name, membres.first_name, membres.prefered_name, membres.programme_id FROM membres LIMIT 10000 ORDER BY membres.id;`) if err != nil { return nil, err } defer rows.Close() for rows.Next() { var membre Membre if err = rows.Scan( &membre.ID, &membre.LastName, &membre.FirstName, &membre.PreferedName, &membre.ProgrammeID, ); err != nil { return nil, err } membres = append(membres, membre) } if rows.Err() != nil { return membres, rows.Err() } return membres, nil } }