quite a lot of things
This commit is contained in:
@@ -3,9 +3,11 @@ package database
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -13,15 +15,88 @@ import (
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// Product represents a product in the database
|
||||
type Product struct {
|
||||
SKU string `json:"sku"`
|
||||
Name string `json:"name"`
|
||||
HSNCode string `json:"hsn_code"`
|
||||
BasePrice float64 `json:"base_price"`
|
||||
WholesalePrice float64 `json:"wholesale_price"`
|
||||
GSTRate float64 `json:"gst_rate"`
|
||||
SmallOrderQty int `json:"small_order_qty"`
|
||||
SmallOrderFee float64 `json:"small_order_fee"` // Convenience fee for orders below SmallOrderQty
|
||||
Unit string `json:"unit"` // Unit of measurement (e.g., "pcs", "kg", "box")
|
||||
UserID string `json:"user_id"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// Invoice represents a stored invoice
|
||||
type Invoice struct {
|
||||
ID string `json:"id"` // UUID
|
||||
HumanReadableID string `json:"human_readable_id"` // Formatted ID like INV/12-2025/001
|
||||
Data string `json:"data"` // JSON blob of invoice details
|
||||
UserID string `json:"user_id"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// User represents an authenticated user
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"-"`
|
||||
CompanyDetails string `json:"company_details"` // Multiline company details for invoice header
|
||||
BankDetails string `json:"bank_details"` // Multiline bank details for invoice footer
|
||||
InvoicePrefix string `json:"invoice_prefix"` // Prefix for invoice IDs (e.g., INV, BILL)
|
||||
InvoiceCounter int `json:"invoice_counter"` // Auto-incrementing counter for invoice serial numbers
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// BuyerDetails represents a buyer/customer for invoices
|
||||
type BuyerDetails struct {
|
||||
ID string `json:"id"`
|
||||
UserID string `json:"user_id"`
|
||||
Name string `json:"name"` // Display name for selection
|
||||
Details string `json:"details"` // Multiline buyer details
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// Service represents a service that interacts with a database.
|
||||
// Service represents a service that interacts with a database.
|
||||
type Service interface {
|
||||
// Health returns a map of health status information.
|
||||
// The keys and values in the map are service-specific.
|
||||
Health() map[string]string
|
||||
|
||||
// Close terminates the database connection.
|
||||
// It returns an error if the connection cannot be closed.
|
||||
Close() error
|
||||
|
||||
// Product operations (user-scoped)
|
||||
CreateProduct(p Product, userID string) error
|
||||
UpdateProduct(p Product, userID string) error
|
||||
GetAllProducts(userID string) ([]Product, error)
|
||||
GetProductBySKU(sku string, userID string) (*Product, error)
|
||||
DeleteProduct(sku string, userID string) error
|
||||
|
||||
// Invoice operations (user-scoped)
|
||||
CreateInvoice(id string, humanReadableID string, data interface{}, userID string) error
|
||||
GetInvoice(id string, userID string) (*Invoice, error)
|
||||
GetAllInvoices(userID string) ([]Invoice, error)
|
||||
GetRecentProducts(userID string, limit int) ([]Product, error)
|
||||
GetRecentInvoices(userID string, limit int) ([]Invoice, error)
|
||||
GetNextInvoiceNumber(userID string) (string, error) // Returns formatted invoice ID and increments counter
|
||||
|
||||
// User operations
|
||||
CreateUser(email, passwordHash string) (*User, error)
|
||||
GetUserByEmail(email string) (*User, error)
|
||||
GetUserByID(id string) (*User, error)
|
||||
UpdateUserPassword(id string, passwordHash string) error
|
||||
UpdateUserDetails(id string, companyDetails string, bankDetails string, invoicePrefix string) error
|
||||
|
||||
// Buyer details operations
|
||||
CreateBuyerDetails(userID string, name string, details string) (*BuyerDetails, error)
|
||||
UpdateBuyerDetails(id string, userID string, name string, details string) error
|
||||
GetBuyerDetails(id string, userID string) (*BuyerDetails, error)
|
||||
GetAllBuyerDetails(userID string) ([]BuyerDetails, error)
|
||||
DeleteBuyerDetails(id string, userID string) error
|
||||
}
|
||||
|
||||
type service struct {
|
||||
@@ -29,7 +104,7 @@ type service struct {
|
||||
}
|
||||
|
||||
var (
|
||||
dburl = os.Getenv("BLUEPRINT_DB_URL")
|
||||
dburl = os.Getenv("DB_PATH")
|
||||
dbInstance *service
|
||||
)
|
||||
|
||||
@@ -39,19 +114,400 @@ func New() Service {
|
||||
return dbInstance
|
||||
}
|
||||
|
||||
// Ensure the directory for the database file exists
|
||||
if dburl != "" && dburl != ":memory:" {
|
||||
dir := filepath.Dir(dburl)
|
||||
if dir != "" && dir != "." {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
log.Fatalf("Failed to create database directory: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite3", dburl)
|
||||
if err != nil {
|
||||
// This will not be a connection error, but a DSN parse error or
|
||||
// another initialization error.
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
dbInstance = &service{
|
||||
db: db,
|
||||
}
|
||||
|
||||
// Initialize tables
|
||||
dbInstance.initTables()
|
||||
|
||||
return dbInstance
|
||||
}
|
||||
|
||||
func (s *service) initTables() {
|
||||
// Products table with user ownership
|
||||
_, err := s.db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS products (
|
||||
sku TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
hsn_code TEXT,
|
||||
base_price REAL NOT NULL,
|
||||
wholesale_price REAL,
|
||||
gst_rate REAL NOT NULL DEFAULT 0.18,
|
||||
small_order_qty INTEGER DEFAULT 1,
|
||||
small_order_fee REAL DEFAULT 0,
|
||||
unit TEXT DEFAULT 'pcs',
|
||||
user_id TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (sku, user_id)
|
||||
)
|
||||
`)
|
||||
if err != nil {
|
||||
log.Printf("Error creating products table: %v", err)
|
||||
}
|
||||
|
||||
// Add user_id column if not exists (migration for existing DBs)
|
||||
s.db.Exec(`ALTER TABLE products ADD COLUMN user_id TEXT DEFAULT ''`)
|
||||
// Add unit column if not exists (migration for existing DBs)
|
||||
s.db.Exec(`ALTER TABLE products ADD COLUMN unit TEXT DEFAULT 'pcs'`)
|
||||
|
||||
// Invoices table with user ownership
|
||||
_, err = s.db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS invoices (
|
||||
id TEXT PRIMARY KEY,
|
||||
human_readable_id TEXT DEFAULT '',
|
||||
data TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`)
|
||||
if err != nil {
|
||||
log.Printf("Error creating invoices table: %v", err)
|
||||
}
|
||||
|
||||
// Add columns if not exists (migration for existing DBs)
|
||||
s.db.Exec(`ALTER TABLE invoices ADD COLUMN user_id TEXT DEFAULT ''`)
|
||||
s.db.Exec(`ALTER TABLE invoices ADD COLUMN human_readable_id TEXT DEFAULT ''`)
|
||||
|
||||
// Create index on user_id for fast lookups
|
||||
s.db.Exec(`CREATE INDEX IF NOT EXISTS idx_products_user ON products(user_id)`)
|
||||
s.db.Exec(`CREATE INDEX IF NOT EXISTS idx_invoices_user ON invoices(user_id)`)
|
||||
|
||||
// Users table
|
||||
_, err = s.db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id TEXT PRIMARY KEY,
|
||||
email TEXT UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
company_details TEXT DEFAULT '',
|
||||
bank_details TEXT DEFAULT '',
|
||||
invoice_prefix TEXT DEFAULT 'INV',
|
||||
invoice_counter INTEGER DEFAULT 0,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`)
|
||||
if err != nil {
|
||||
log.Printf("Error creating users table: %v", err)
|
||||
}
|
||||
|
||||
// Add columns if not exists (migration for existing DBs)
|
||||
s.db.Exec(`ALTER TABLE users ADD COLUMN company_details TEXT DEFAULT ''`)
|
||||
s.db.Exec(`ALTER TABLE users ADD COLUMN bank_details TEXT DEFAULT ''`)
|
||||
s.db.Exec(`ALTER TABLE users ADD COLUMN invoice_prefix TEXT DEFAULT 'INV'`)
|
||||
s.db.Exec(`ALTER TABLE users ADD COLUMN invoice_counter INTEGER DEFAULT 0`)
|
||||
s.db.Exec(`ALTER TABLE users ADD COLUMN invoice_prefix TEXT DEFAULT 'INV'`)
|
||||
s.db.Exec(`ALTER TABLE users ADD COLUMN invoice_counter INTEGER DEFAULT 0`)
|
||||
|
||||
// Create index on email for fast lookups
|
||||
_, err = s.db.Exec(`CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)`)
|
||||
if err != nil {
|
||||
log.Printf("Error creating users email index: %v", err)
|
||||
}
|
||||
|
||||
// Buyer details table
|
||||
_, err = s.db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS buyer_details (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
details TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`)
|
||||
if err != nil {
|
||||
log.Printf("Error creating buyer_details table: %v", err)
|
||||
}
|
||||
|
||||
// Create index on user_id for fast lookups
|
||||
s.db.Exec(`CREATE INDEX IF NOT EXISTS idx_buyer_details_user ON buyer_details(user_id)`)
|
||||
}
|
||||
|
||||
// CreateProduct inserts a new product for a user
|
||||
func (s *service) CreateProduct(p Product, userID string) error {
|
||||
_, err := s.db.Exec(`
|
||||
INSERT INTO products (sku, name, hsn_code, base_price, wholesale_price, gst_rate, small_order_qty, small_order_fee, unit, user_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, p.SKU, p.Name, p.HSNCode, p.BasePrice, p.WholesalePrice, p.GSTRate, p.SmallOrderQty, p.SmallOrderFee, p.Unit, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateProduct updates an existing product for a user
|
||||
func (s *service) UpdateProduct(p Product, userID string) error {
|
||||
_, err := s.db.Exec(`
|
||||
UPDATE products SET name=?, hsn_code=?, base_price=?, wholesale_price=?, gst_rate=?, small_order_qty=?, small_order_fee=?, unit=?
|
||||
WHERE sku=? AND user_id=?
|
||||
`, p.Name, p.HSNCode, p.BasePrice, p.WholesalePrice, p.GSTRate, p.SmallOrderQty, p.SmallOrderFee, p.Unit, p.SKU, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetAllProducts returns all products for a user
|
||||
func (s *service) GetAllProducts(userID string) ([]Product, error) {
|
||||
rows, err := s.db.Query(`SELECT sku, name, hsn_code, base_price, wholesale_price, gst_rate, small_order_qty, small_order_fee, unit, user_id, created_at FROM products WHERE user_id=? ORDER BY name`, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var products []Product
|
||||
for rows.Next() {
|
||||
var p Product
|
||||
if err := rows.Scan(&p.SKU, &p.Name, &p.HSNCode, &p.BasePrice, &p.WholesalePrice, &p.GSTRate, &p.SmallOrderQty, &p.SmallOrderFee, &p.Unit, &p.UserID, &p.CreatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
products = append(products, p)
|
||||
}
|
||||
return products, nil
|
||||
}
|
||||
|
||||
// GetProductBySKU returns a single product by SKU for a user
|
||||
func (s *service) GetProductBySKU(sku string, userID string) (*Product, error) {
|
||||
var p Product
|
||||
err := s.db.QueryRow(`SELECT sku, name, hsn_code, base_price, wholesale_price, gst_rate, small_order_qty, small_order_fee, unit, user_id, created_at FROM products WHERE sku=? AND user_id=?`, sku, userID).
|
||||
Scan(&p.SKU, &p.Name, &p.HSNCode, &p.BasePrice, &p.WholesalePrice, &p.GSTRate, &p.SmallOrderQty, &p.SmallOrderFee, &p.Unit, &p.UserID, &p.CreatedAt)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
// DeleteProduct removes a product by SKU for a user
|
||||
func (s *service) DeleteProduct(sku string, userID string) error {
|
||||
_, err := s.db.Exec(`DELETE FROM products WHERE sku=? AND user_id=?`, sku, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetNextInvoiceNumber generates the next invoice ID in format PREFIX/MMM-YYYY/XXX and increments the counter
|
||||
func (s *service) GetNextInvoiceNumber(userID string) (string, error) {
|
||||
var prefix string
|
||||
var counter int
|
||||
|
||||
// Get current prefix and counter
|
||||
err := s.db.QueryRow(`SELECT COALESCE(invoice_prefix, 'INV'), COALESCE(invoice_counter, 0) FROM users WHERE id = ?`, userID).
|
||||
Scan(&prefix, &counter)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Increment counter
|
||||
counter++
|
||||
|
||||
// Update counter in database
|
||||
_, err = s.db.Exec(`UPDATE users SET invoice_counter = ? WHERE id = ?`, counter, userID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Generate formatted invoice ID: PREFIX/MMM-YYYY/XXX
|
||||
now := time.Now()
|
||||
humanReadableID := fmt.Sprintf("%s/%s-%d/%03d", prefix, now.Month().String()[:3], now.Year(), counter)
|
||||
|
||||
return humanReadableID, nil
|
||||
}
|
||||
|
||||
// CreateInvoice stores an invoice with UUID and human-readable ID for a user
|
||||
func (s *service) CreateInvoice(id string, humanReadableID string, data interface{}, userID string) error {
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.db.Exec(`INSERT INTO invoices (id, human_readable_id, data, user_id) VALUES (?, ?, ?, ?)`, id, humanReadableID, string(jsonData), userID)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetInvoice retrieves an invoice by ID for a user
|
||||
func (s *service) GetInvoice(id string, userID string) (*Invoice, error) {
|
||||
var inv Invoice
|
||||
err := s.db.QueryRow(`SELECT id, COALESCE(human_readable_id, ''), data, user_id, created_at FROM invoices WHERE id=? AND user_id=?`, id, userID).
|
||||
Scan(&inv.ID, &inv.HumanReadableID, &inv.Data, &inv.UserID, &inv.CreatedAt)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &inv, nil
|
||||
}
|
||||
|
||||
// GetAllInvoices retrieves all invoices for a user
|
||||
func (s *service) GetAllInvoices(userID string) ([]Invoice, error) {
|
||||
rows, err := s.db.Query(`SELECT id, COALESCE(human_readable_id, ''), data, user_id, created_at FROM invoices WHERE user_id=? ORDER BY created_at DESC`, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var invoices []Invoice
|
||||
for rows.Next() {
|
||||
var inv Invoice
|
||||
if err := rows.Scan(&inv.ID, &inv.HumanReadableID, &inv.Data, &inv.UserID, &inv.CreatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
invoices = append(invoices, inv)
|
||||
}
|
||||
return invoices, nil
|
||||
}
|
||||
|
||||
// GetRecentProducts returns the most recently added products for a user
|
||||
func (s *service) GetRecentProducts(userID string, limit int) ([]Product, error) {
|
||||
rows, err := s.db.Query(`SELECT sku, name, hsn_code, base_price, wholesale_price, gst_rate, small_order_qty, small_order_fee, unit, user_id, created_at FROM products WHERE user_id=? ORDER BY created_at DESC LIMIT ?`, userID, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var products []Product
|
||||
for rows.Next() {
|
||||
var p Product
|
||||
if err := rows.Scan(&p.SKU, &p.Name, &p.HSNCode, &p.BasePrice, &p.WholesalePrice, &p.GSTRate, &p.SmallOrderQty, &p.SmallOrderFee, &p.Unit, &p.UserID, &p.CreatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
products = append(products, p)
|
||||
}
|
||||
return products, nil
|
||||
}
|
||||
|
||||
// GetRecentInvoices returns the most recently generated invoices for a user
|
||||
func (s *service) GetRecentInvoices(userID string, limit int) ([]Invoice, error) {
|
||||
rows, err := s.db.Query(`SELECT id, COALESCE(human_readable_id, ''), data, user_id, created_at FROM invoices WHERE user_id=? ORDER BY created_at DESC LIMIT ?`, userID, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var invoices []Invoice
|
||||
for rows.Next() {
|
||||
var inv Invoice
|
||||
if err := rows.Scan(&inv.ID, &inv.HumanReadableID, &inv.Data, &inv.UserID, &inv.CreatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
invoices = append(invoices, inv)
|
||||
}
|
||||
return invoices, nil
|
||||
}
|
||||
|
||||
// CreateUser creates a new user with hashed password
|
||||
func (s *service) CreateUser(email, passwordHash string) (*User, error) {
|
||||
id := fmt.Sprintf("%d", time.Now().UnixNano())
|
||||
_, err := s.db.Exec(`INSERT INTO users (id, email, password) VALUES (?, ?, ?)`, id, email, passwordHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.GetUserByID(id)
|
||||
}
|
||||
|
||||
// GetUserByEmail retrieves a user by email
|
||||
func (s *service) GetUserByEmail(email string) (*User, error) {
|
||||
var u User
|
||||
err := s.db.QueryRow(`SELECT id, email, password, COALESCE(company_details, ''), COALESCE(bank_details, ''), COALESCE(invoice_prefix, 'INV'), COALESCE(invoice_counter, 0), created_at FROM users WHERE email = ?`, email).
|
||||
Scan(&u.ID, &u.Email, &u.Password, &u.CompanyDetails, &u.BankDetails, &u.InvoicePrefix, &u.InvoiceCounter, &u.CreatedAt)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &u, nil
|
||||
}
|
||||
|
||||
// GetUserByID retrieves a user by ID
|
||||
func (s *service) GetUserByID(id string) (*User, error) {
|
||||
var u User
|
||||
err := s.db.QueryRow(`SELECT id, email, password, COALESCE(company_details, ''), COALESCE(bank_details, ''), COALESCE(invoice_prefix, 'INV'), COALESCE(invoice_counter, 0), created_at FROM users WHERE id = ?`, id).
|
||||
Scan(&u.ID, &u.Email, &u.Password, &u.CompanyDetails, &u.BankDetails, &u.InvoicePrefix, &u.InvoiceCounter, &u.CreatedAt)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &u, nil
|
||||
}
|
||||
|
||||
// UpdateUserPassword updates a user's password hash
|
||||
func (s *service) UpdateUserPassword(id string, passwordHash string) error {
|
||||
_, err := s.db.Exec(`UPDATE users SET password = ? WHERE id = ?`, passwordHash, id)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateUserDetails updates a user's company and bank details
|
||||
func (s *service) UpdateUserDetails(id string, companyDetails string, bankDetails string, invoicePrefix string) error {
|
||||
_, err := s.db.Exec(`UPDATE users SET company_details = ?, bank_details = ?, invoice_prefix = ? WHERE id = ?`, companyDetails, bankDetails, invoicePrefix, id)
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateBuyerDetails creates a new buyer details entry
|
||||
func (s *service) CreateBuyerDetails(userID string, name string, details string) (*BuyerDetails, error) {
|
||||
id := fmt.Sprintf("%d", time.Now().UnixNano())
|
||||
_, err := s.db.Exec(`INSERT INTO buyer_details (id, user_id, name, details) VALUES (?, ?, ?, ?)`, id, userID, name, details)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.GetBuyerDetails(id, userID)
|
||||
}
|
||||
|
||||
// UpdateBuyerDetails updates an existing buyer details entry
|
||||
func (s *service) UpdateBuyerDetails(id string, userID string, name string, details string) error {
|
||||
_, err := s.db.Exec(`UPDATE buyer_details SET name = ?, details = ? WHERE id = ? AND user_id = ?`, name, details, id, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetBuyerDetails retrieves a buyer details entry by ID
|
||||
func (s *service) GetBuyerDetails(id string, userID string) (*BuyerDetails, error) {
|
||||
var b BuyerDetails
|
||||
err := s.db.QueryRow(`SELECT id, user_id, name, details, created_at FROM buyer_details WHERE id = ? AND user_id = ?`, id, userID).
|
||||
Scan(&b.ID, &b.UserID, &b.Name, &b.Details, &b.CreatedAt)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
// GetAllBuyerDetails retrieves all buyer details for a user
|
||||
func (s *service) GetAllBuyerDetails(userID string) ([]BuyerDetails, error) {
|
||||
rows, err := s.db.Query(`SELECT id, user_id, name, details, created_at FROM buyer_details WHERE user_id = ? ORDER BY name`, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var buyers []BuyerDetails
|
||||
for rows.Next() {
|
||||
var b BuyerDetails
|
||||
if err := rows.Scan(&b.ID, &b.UserID, &b.Name, &b.Details, &b.CreatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buyers = append(buyers, b)
|
||||
}
|
||||
return buyers, nil
|
||||
}
|
||||
|
||||
// DeleteBuyerDetails removes a buyer details entry
|
||||
func (s *service) DeleteBuyerDetails(id string, userID string) error {
|
||||
_, err := s.db.Exec(`DELETE FROM buyer_details WHERE id = ? AND user_id = ?`, id, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
// Health checks the health of the database connection by pinging the database.
|
||||
// It returns a map with keys indicating various health statistics.
|
||||
func (s *service) Health() map[string]string {
|
||||
|
||||
Reference in New Issue
Block a user