From 731343feefc55fe133b305ec22527260446e242c Mon Sep 17 00:00:00 2001 From: Samuel Tariku Date: Fri, 28 Mar 2025 23:03:25 +0300 Subject: [PATCH] ticket setup --- cmd/main.go | 4 + db/migrations/000001_fortune.down.sql | 4 + db/migrations/000001_fortune.up.sql | 10 ++- db/query/ticket.sql | 16 ++++ gen/db/db.go | 2 +- gen/db/models.go | 10 ++- gen/db/ticket.sql.go | 102 ++++++++++++++++++++++++++ gen/db/user.sql.go | 2 +- internal/domain/ticket.go | 9 +++ internal/repository/ticket.go | 72 ++++++++++++++++++ internal/services/ticket/port.go | 15 ++++ internal/services/ticket/service.go | 34 +++++++++ 12 files changed, 276 insertions(+), 4 deletions(-) create mode 100644 db/query/ticket.sql create mode 100644 gen/db/ticket.sql.go create mode 100644 internal/domain/ticket.go create mode 100644 internal/repository/ticket.go create mode 100644 internal/services/ticket/port.go create mode 100644 internal/services/ticket/service.go diff --git a/cmd/main.go b/cmd/main.go index 7899d54..320c594 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -7,6 +7,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/config" "github.com/SamuelTariku/FortuneBet-Backend/internal/repository" + // httpserver "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server" "github.com/joho/godotenv" ) @@ -28,4 +29,7 @@ func main() { } store := repository.NewStore(db) fmt.Println(store) + + // app := httpserver.NewApp(cfg.Port) + // app.Run() } diff --git a/db/migrations/000001_fortune.down.sql b/db/migrations/000001_fortune.down.sql index 489466f..ffaa92e 100644 --- a/db/migrations/000001_fortune.down.sql +++ b/db/migrations/000001_fortune.down.sql @@ -72,3 +72,7 @@ DROP TABLE IF EXISTS ussd_account; DROP TYPE IF EXISTS ua_pin_status; DROP TYPE IF EXISTS ua_status; DROP TYPE IF EXISTS ua_registaration_type; + +-- Drop Ticket +DROP TABLE IF EXIST ticket; + diff --git a/db/migrations/000001_fortune.up.sql b/db/migrations/000001_fortune.up.sql index bfd54da..98e59ff 100644 --- a/db/migrations/000001_fortune.up.sql +++ b/db/migrations/000001_fortune.up.sql @@ -9,4 +9,12 @@ CREATE TABLE users ( verified BOOLEAN DEFAULT FALSE, created_at TIMESTAMP , updated_at TIMESTAMP -); \ No newline at end of file +); + +CREATE TABLE IF NOT EXISTS tickets ( + id BIGSERIAL PRIMARY KEY, + amount DECIMAL(12,2) NULL, + total_odds DECIMAL(12,2) NOT NULL, + created_at TIMESTAMP, + updated_at TIMESTAMP +); diff --git a/db/query/ticket.sql b/db/query/ticket.sql new file mode 100644 index 0000000..5b3a99a --- /dev/null +++ b/db/query/ticket.sql @@ -0,0 +1,16 @@ +-- name: CreateTicket :one +INSERT INTO tickets (id, amount, total_odds) +VALUES ($1, $2, $3) +RETURNING *; + +-- name: GetAllTickets :many +SELECT * FROM tickets; + +-- name: GetTicketByID :one +SELECT * FROM tickets WHERE id = $1; + +-- name: DeleteTicket :exec +DELETE FROM tickets WHERE id = $1; + +-- name: DeleteOldTickets :exec +Delete from tickets where created_at < now() - interval '1 day'; diff --git a/gen/db/db.go b/gen/db/db.go index fe4ae38..136f20a 100644 --- a/gen/db/db.go +++ b/gen/db/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.26.0 +// sqlc v1.28.0 package dbgen diff --git a/gen/db/models.go b/gen/db/models.go index 307326d..dcbf8be 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.26.0 +// sqlc v1.28.0 package dbgen @@ -8,6 +8,14 @@ import ( "github.com/jackc/pgx/v5/pgtype" ) +type Ticket struct { + ID int64 + Amount pgtype.Numeric + TotalOdds pgtype.Numeric + CreatedAt pgtype.Timestamp + UpdatedAt pgtype.Timestamp +} + type User struct { ID int64 FirstName string diff --git a/gen/db/ticket.sql.go b/gen/db/ticket.sql.go new file mode 100644 index 0000000..24d11f3 --- /dev/null +++ b/gen/db/ticket.sql.go @@ -0,0 +1,102 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.28.0 +// source: ticket.sql + +package dbgen + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const CreateTicket = `-- name: CreateTicket :one +INSERT INTO tickets (id, amount, total_odds) +VALUES ($1, $2, $3) +RETURNING id, amount, total_odds, created_at, updated_at +` + +type CreateTicketParams struct { + ID int64 + Amount pgtype.Numeric + TotalOdds pgtype.Numeric +} + +func (q *Queries) CreateTicket(ctx context.Context, arg CreateTicketParams) (Ticket, error) { + row := q.db.QueryRow(ctx, CreateTicket, arg.ID, arg.Amount, arg.TotalOdds) + var i Ticket + err := row.Scan( + &i.ID, + &i.Amount, + &i.TotalOdds, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const DeleteOldTickets = `-- name: DeleteOldTickets :exec +Delete from tickets where created_at < now() - interval '1 day' +` + +func (q *Queries) DeleteOldTickets(ctx context.Context) error { + _, err := q.db.Exec(ctx, DeleteOldTickets) + return err +} + +const DeleteTicket = `-- name: DeleteTicket :exec +DELETE FROM tickets WHERE id = $1 +` + +func (q *Queries) DeleteTicket(ctx context.Context, id int64) error { + _, err := q.db.Exec(ctx, DeleteTicket, id) + return err +} + +const GetAllTickets = `-- name: GetAllTickets :many +SELECT id, amount, total_odds, created_at, updated_at FROM tickets +` + +func (q *Queries) GetAllTickets(ctx context.Context) ([]Ticket, error) { + rows, err := q.db.Query(ctx, GetAllTickets) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Ticket + for rows.Next() { + var i Ticket + if err := rows.Scan( + &i.ID, + &i.Amount, + &i.TotalOdds, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetTicketByID = `-- name: GetTicketByID :one +SELECT id, amount, total_odds, created_at, updated_at FROM tickets WHERE id = $1 +` + +func (q *Queries) GetTicketByID(ctx context.Context, id int64) (Ticket, error) { + row := q.db.QueryRow(ctx, GetTicketByID, id) + var i Ticket + err := row.Scan( + &i.ID, + &i.Amount, + &i.TotalOdds, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/gen/db/user.sql.go b/gen/db/user.sql.go index 1608a32..c5b0e90 100644 --- a/gen/db/user.sql.go +++ b/gen/db/user.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.26.0 +// sqlc v1.28.0 // source: user.sql package dbgen diff --git a/internal/domain/ticket.go b/internal/domain/ticket.go new file mode 100644 index 0000000..3ca75e3 --- /dev/null +++ b/internal/domain/ticket.go @@ -0,0 +1,9 @@ +package domain + +// TODO: Adding Outcome Array Once the event is done +// ID will serve as the fast code since this doesn't need to be secure +type Ticket struct { + ID int64 + Amount int32 + TotalOdds int32 +} diff --git a/internal/repository/ticket.go b/internal/repository/ticket.go new file mode 100644 index 0000000..513196d --- /dev/null +++ b/internal/repository/ticket.go @@ -0,0 +1,72 @@ +package repository + +import ( + "context" + + dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" + "github.com/jackc/pgx/v5/pgtype" +) + +func (s *Store) CreateTicket(ctx context.Context, amount int32, totalOdds int32) (domain.Ticket, error) { + + ticket, err := s.queries.CreateTicket(ctx, dbgen.CreateTicketParams{ + Amount: pgtype.Numeric{ + Exp: amount, + }, + TotalOdds: pgtype.Numeric{ + Exp: totalOdds, + }, + }) + + if err != nil { + return domain.Ticket{}, err + } + + return domain.Ticket{ + ID: ticket.ID, + Amount: ticket.Amount.Exp, + TotalOdds: ticket.TotalOdds.Exp, + }, err + +} + +func (s *Store) GetTicketByID(ctx context.Context, id int64) (domain.Ticket, error) { + ticket, err := s.queries.GetTicketByID(ctx, id) + if err != nil { + return domain.Ticket{}, err + } + + return domain.Ticket{ + ID: ticket.ID, + Amount: ticket.Amount.Exp, + TotalOdds: ticket.TotalOdds.Exp, + }, nil +} + +func (s *Store) GetAllTickets(ctx context.Context) ([]domain.Ticket, error) { + tickets, err := s.queries.GetAllTickets(ctx) + + if err != nil { + return nil, err + } + + var result []domain.Ticket + for _, ticket := range tickets { + result = append(result, domain.Ticket{ + ID: ticket.ID, + Amount: ticket.Amount.Exp, + TotalOdds: ticket.TotalOdds.Exp, + }) + } + + return result, nil +} + +func (s *Store) DeleteOldTickets(ctx context.Context) error { + return s.queries.DeleteOldTickets(ctx) +} + +func (s *Store) DeleteTicket(ctx context.Context, id int64) error { + return s.queries.DeleteTicket(ctx, id) +} diff --git a/internal/services/ticket/port.go b/internal/services/ticket/port.go new file mode 100644 index 0000000..d9591d6 --- /dev/null +++ b/internal/services/ticket/port.go @@ -0,0 +1,15 @@ +package ticket + +import ( + "context" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" +) + +type TicketStore interface { + CreateTicket(ctx context.Context, amount int32, totalOdds int32) (domain.Ticket, error) + GetTicketByID(ctx context.Context, id int64) (domain.Ticket, error) + GetAllTickets(ctx context.Context) ([]domain.Ticket, error) + DeleteOldTickets(ctx context.Context) error + DeleteTicket(ctx context.Context, id int64) error +} diff --git a/internal/services/ticket/service.go b/internal/services/ticket/service.go new file mode 100644 index 0000000..b0bca28 --- /dev/null +++ b/internal/services/ticket/service.go @@ -0,0 +1,34 @@ +package ticket + +import ( + "context" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" +) + +type Service struct { + ticketStore TicketStore +} + +func NewService(ticketStore TicketStore) *Service { + return &Service{ + ticketStore: ticketStore, + } +} + +func (s *Service) CreateUser(ctx context.Context, amount int32, totalOdds int32) (domain.Ticket, error) { + return s.ticketStore.CreateTicket(ctx, amount, totalOdds) +} +func (s *Service) GetTicketByID(ctx context.Context, id int64) (domain.Ticket, error) { + return s.ticketStore.GetTicketByID(ctx, id) +} +func (s *Service) GetAllTickets(ctx context.Context) ([]domain.Ticket, error) { + return s.ticketStore.GetAllTickets(ctx) +} +func (s *Service) DeleteTicket(ctx context.Context, id int64) error { + return s.ticketStore.DeleteTicket(ctx, id) +} + +func (s *Service) DeleteOldTickets(ctx context.Context) error { + return s.ticketStore.DeleteOldTickets(ctx) +}