package merch import ( "context" "database/sql" "fmt" "github.com/jackc/pgx/v5/pgxpool" "strings" "time" ) type Repository interface { // createMerch creates new merch record and inserts extra data if given createMerch(ctx context.Context, merch *Merch, extra []ExtraData) error // getMany returns list of only main merch record, without origins extra data getMany(ctx context.Context, userId string) ([]merchDTO, error) // deleteOneMerchRecord sets deleted_at in merch + extra tables deleteOneMerchRecord(ctx context.Context, userId, merchUuid string, delTime time.Time) error Origins } type Origins interface { createOrigin(ctx context.Context, origin *Origin) error getOrigins(ctx context.Context) ([]Origin, error) deleteOriginByName(ctx context.Context, name string, deletedAt sql.NullTime) error } type repo struct { db *pgxpool.Pool } func newRepo(db *pgxpool.Pool) Repository { return &repo{ db: db, } } func (r *repo) createOrigin(ctx context.Context, origin *Origin) error { q := `INSERT INTO merch_origins (created_at, deleted_at, name) VALUES ($1, $2, $3)` _, err := r.db.Exec(ctx, q, origin.CreatedAt, origin.DeletedAt, origin.Name) if err != nil { return err } return nil } func (r *repo) getOrigins(ctx context.Context) ([]Origin, error) { q := `SELECT * FROM merch_origins WHERE deleted_at IS NULL` rows, err := r.db.Query(ctx, q) if err != nil { return nil, err } defer rows.Close() var origins []Origin for rows.Next() { var o Origin if err = rows.Scan(&o.Id, &o.CreatedAt, &o.DeletedAt, &o.Name); err != nil { return nil, err } origins = append(origins, o) } if err = rows.Err(); err != nil { return nil, err } return origins, nil } func (r *repo) deleteOriginByName(ctx context.Context, name string, deletedAt sql.NullTime) error { q := `UPDATE merch_origins SET deleted_at = $1 WHERE name = $2` _, err := r.db.Exec(ctx, q, deletedAt.Time, name) if err != nil { return err } return nil } //Merch crud func (r *repo) createMerch(ctx context.Context, merch *Merch, extra []ExtraData) error { tx, err := r.db.Begin(ctx) if err != nil { return err } qMerch := `INSERT INTO merch (created_at, updated_at, deleted_at, merch_uuid, user_id, name) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id` var merchId int64 err = tx. QueryRow(ctx, qMerch, merch.CreatedAt, merch.UpdatedAt, merch.DeletedAt, merch.MerchUuid, merch.UserId, merch.Name). Scan(&merchId) if err != nil { tx.Rollback(ctx) return err } if extra == nil { return tx.Commit(ctx) } countArgs := 1 var insertFields []string var insertArgs []interface{} for _, item := range extra { insertFields = append(insertFields, fmt.Sprintf("($%v, $%v, $%v, $%v, $%v, $%v)", countArgs, countArgs+1, countArgs+2, countArgs+3, countArgs+4, countArgs+5)) insertArgs = append(insertArgs, item.CreatedAt, item.UpdatedAt, item.DeletedAt, merchId, item.OriginId, item.URL) countArgs += 6 } qExtra := fmt.Sprintf( "INSERT INTO merch_extra_data (created_at, updated_at, deleted_at, merch_id, origin_id, url) VALUES %v", strings.Join(insertFields, ",")) _, err = tx.Exec(ctx, qExtra, insertArgs...) if err != nil { tx.Rollback(ctx) return err } return tx.Commit(ctx) } func (r *repo) getMany(ctx context.Context, userId string) ([]merchDTO, error) { q := `SELECT created_at, updated_at, merch_uuid, name FROM merch WHERE deleted_at IS NULL AND user_id = $1` rows, err := r.db.Query(ctx, q, userId) if err != nil { return nil, err } defer rows.Close() var result []merchDTO for rows.Next() { var m merchDTO if err = rows.Scan(&m.CreatedAt, &m.UpdatedAt, &m.MerchUuid, &m.Name); err != nil { return nil, err } result = append(result, m) } if err = rows.Err(); err != nil { return nil, err } return result, nil } func (r *repo) deleteOneMerchRecord(ctx context.Context, userId, merchUuid string, delTime time.Time) error { tx, err := r.db.Begin(ctx) if err != nil { return err } var merch_id int64 qMerch := `UPDATE merch SET deleted_at = $1 WHERE merch_uuid = $2 AND user_id = $3 RETURNING id` if err = tx.QueryRow(ctx, qMerch, delTime, merchUuid, userId).Scan(&merch_id); err != nil { tx.Rollback(ctx) return err } if merch_id != 0 { qExtra := `UPDATE merch_extra_data SET deleted_at = $1 WHERE merch_id = $2` _, err = tx.Exec(ctx, qExtra, delTime, merch_id) } return tx.Commit(ctx) }