package human import ( "context" "errors" "strings" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" "go.jetify.com/typeid" ) var errNotFound = errors.New("not found") type humanIDPrefix struct{} func (humanIDPrefix) Prefix() string { return "human" } type humanID struct { typeid.TypeID[humanIDPrefix] } func newHumanID() (humanID, error) { return typeid.New[humanID]() } func emailPrefix(email string) string { return strings.Split(email, "@")[0] } type repository interface { getByEmail(ctx context.Context, email string) (*Human, error) getByID(ctx context.Context, id string) (*Human, error) create(ctx context.Context, email string) (*Human, error) exists(ctx context.Context, email string) (bool, error) } type repositoryImpl struct { pool *pgxpool.Pool } func newRepository(pool *pgxpool.Pool) repository { return &repositoryImpl{pool: pool} } func (r *repositoryImpl) getByEmail(ctx context.Context, email string) (*Human, error) { var h Human err := r.pool.QueryRow(ctx, `SELECT id, email, created_at FROM humans WHERE email = $1`, email, ).Scan(&h.ID, &h.Email, &h.CreatedAt) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, errNotFound } return nil, err } h.EmailPrefix = emailPrefix(h.Email) return &h, nil } func (r *repositoryImpl) getByID(ctx context.Context, id string) (*Human, error) { var h Human err := r.pool.QueryRow(ctx, `SELECT id, email, created_at FROM humans WHERE id = $1`, id, ).Scan(&h.ID, &h.Email, &h.CreatedAt) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, errNotFound } return nil, err } h.EmailPrefix = emailPrefix(h.Email) return &h, nil } func (r *repositoryImpl) create(ctx context.Context, email string) (*Human, error) { id, err := newHumanID() if err != nil { return nil, err } var h Human err = r.pool.QueryRow(ctx, `INSERT INTO humans (id, email) VALUES ($1, $2) RETURNING id, email, created_at`, id.String(), email, ).Scan(&h.ID, &h.Email, &h.CreatedAt) if err != nil { return nil, err } h.EmailPrefix = emailPrefix(h.Email) return &h, nil } func (r *repositoryImpl) exists(ctx context.Context, email string) (bool, error) { var exists bool err := r.pool.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM humans WHERE email = $1)`, email, ).Scan(&exists) if err != nil { return false, err } return exists, nil }