package services import ( "context" "errors" "fmt" "time" "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" "jd-book-uploader/models" "jd-book-uploader/utils" ) // CreateBook creates a new book record in the database func CreateBook(ctx context.Context, req *models.BookCreateRequest) (*models.Book, error) { if DB == nil { return nil, fmt.Errorf("database connection not initialized") } // Generate UUID for book_code bookCode := uuid.New().String() // Generate slug from book name slug := utils.GenerateSlug(req.BookName) // Set default discount if not provided discount := req.Discount if discount < 0 { discount = 0 } now := time.Now() // Insert book into database query := ` INSERT INTO books ( book_code, book_name, cost, price, discount, quantity, publisher_author, category, description, image_url, slug, created_at, updated_at ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 ) RETURNING book_code, book_name, cost, price, discount, quantity, publisher_author, category, description, image_url, slug, created_at, updated_at ` var book models.Book err := DB.QueryRow(ctx, query, bookCode, req.BookName, req.Cost, req.Price, discount, req.Quantity, req.PublisherAuthor, req.Category, req.Description, req.ImageURL, slug, now, now, ).Scan( &book.BookCode, &book.BookName, &book.Cost, &book.Price, &book.Discount, &book.Quantity, &book.PublisherAuthor, &book.Category, &book.Description, &book.ImageURL, &book.Slug, &book.CreatedAt, &book.UpdatedAt, ) if err != nil { // Check for duplicate key error var pgErr *pgconn.PgError if errors.As(err, &pgErr) { if pgErr.Code == "23505" { // unique_violation return nil, fmt.Errorf("book with this code already exists") } } return nil, fmt.Errorf("failed to create book: %w", err) } return &book, nil } // GetBookByCode retrieves a book by its code func GetBookByCode(ctx context.Context, bookCode string) (*models.Book, error) { if DB == nil { return nil, fmt.Errorf("database connection not initialized") } query := ` SELECT book_code, book_name, cost, price, discount, quantity, publisher_author, category, description, image_url, slug, created_at, updated_at FROM books WHERE book_code = $1 ` var book models.Book err := DB.QueryRow(ctx, query, bookCode).Scan( &book.BookCode, &book.BookName, &book.Cost, &book.Price, &book.Discount, &book.Quantity, &book.PublisherAuthor, &book.Category, &book.Description, &book.ImageURL, &book.Slug, &book.CreatedAt, &book.UpdatedAt, ) if err != nil { if err == pgx.ErrNoRows { return nil, fmt.Errorf("book not found") } return nil, fmt.Errorf("failed to get book: %w", err) } return &book, nil } // BookSlugExists checks if a slug already exists in the books table func BookSlugExists(ctx context.Context, slug string) (bool, error) { if DB == nil { return false, fmt.Errorf("database connection not initialized") } query := `SELECT EXISTS(SELECT 1 FROM books WHERE slug = $1)` var exists bool err := DB.QueryRow(ctx, query, slug).Scan(&exists) if err != nil { return false, fmt.Errorf("failed to check slug existence: %w", err) } return exists, nil }