diff --git a/db.go b/db.go index fff8885..ff715d8 100644 --- a/db.go +++ b/db.go @@ -3,6 +3,7 @@ package main import ( "context" _ "embed" + "fmt" "github.com/jackc/pgx/v5/pgxpool" ) @@ -11,6 +12,7 @@ import ( var sqlSchema string type PostgresClient struct { + //TODO move context out of client Ctx context.Context Pool *pgxpool.Pool } @@ -20,142 +22,92 @@ func (db *PostgresClient) CreateOrReplaceSchema() error { return err } -/* -// 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 NewDataClientFromViper() (*DataClient, error) { - client, err := NewDataClient( - PostgresConnection{ - User: viper.GetString(cmd.ViperDBHost), - Password: viper.GetString(cmd.ViperDBPassword), - Host: viper.GetString(cmd.ViperDBHost), - Database: viper.GetString(cmd.ViperDBDatabase), - Port: viper.GetInt(cmd.ViperDBPort), - }) - - return client, err -} - -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(sqlSchema) - 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 []Membre) (int64, error) { - var rowsInserted int64 - tx, err := d.DB.Beginx() - if err != nil { - return rowsInserted, err - } - defer tx.Rollback() - - for _, membre := range membres { - if membre.ID == "" { - 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) ON CONFLICT (id) DO NOTHING;", &membre) +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 } - rows, err := result.RowsAffected() - if err != nil { - return 0, err - } - - rowsInserted += rows + return inserted, err } - - err = tx.Commit() - if err != nil { - return rowsInserted, err - } - - return rowsInserted, nil } -func (d *DataClient) InsertProgrammes(programmes []Programme) (int64, error) { - var rowsInserted int64 - tx, err := d.DB.Beginx() - if err != nil { - return rowsInserted, err - } - defer tx.Rollback() - - for _, programme := range programmes { - if programme.ID == "" { - return 0, errors.New("Cannot insert programme with no programme_id") - } - - result, err := tx.NamedExec("INSERT INTO programmes (id, titre) VALUES (:id, :titre) ON CONFLICT DO NOTHING;", &programme) +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 0, err + 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, titre) +VALUES ($1, $2) ON CONFLICT DO NOTHING;`, + programme.ID, + programme.Titre) + if err != nil { + return 0, err + } + + inserted += result.RowsAffected() } - rows, err := result.RowsAffected() - if err != nil { - return 0, err + if err := tx.Commit(d.Ctx); err != nil { + return inserted, err } - rowsInserted += rows + return inserted, err } - - err = tx.Commit() - if err != nil { - return rowsInserted, err - } - - return rowsInserted, nil } -func (d *DataClient) GetMembre(membreID string) (Membre, error) { +/* +func (d *PostgresClient) GetMembre(membreID string) (Membre, error) { var membre Membre - rows, err := d.DB.Queryx("SELECT * FROM membres WHERE id = $1 LIMIT 1;", membreID) + rows, err := d.Pool.Queryx("SELECT * FROM membres WHERE id = $1 LIMIT 1;", membreID) if err != nil { return membre, err } @@ -173,9 +125,11 @@ func (d *DataClient) GetMembre(membreID string) (Membre, error) { 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) +/* +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 } @@ -187,8 +141,50 @@ func (d *DataClient) UpdateMembreName(membreID, newName string) (int64, error) { return rows, nil } - -func (d *DataClient) GetMembres() (membres []Membre, err error) { - return membres, d.DB.Select(&membres, "SELECT * FROM membres;") -} */ + +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 + } +}