Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions challenge-13/submissions/blxxdclxud/solution-template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package main

import (
"database/sql"
"context"
"time"
"errors"

_ "github.com/mattn/go-sqlite3"
)

// Product represents a product in the inventory system
type Product struct {
ID int64
Name string
Price float64
Quantity int
Category string
}

// ProductStore manages product operations
type ProductStore struct {
db *sql.DB
}

// NewProductStore creates a new ProductStore with the given database connection
func NewProductStore(db *sql.DB) *ProductStore {
return &ProductStore{db: db}
}

// InitDB sets up a new SQLite database and creates the products table
func InitDB(dbPath string) (*sql.DB, error) {
// TODO: Open a SQLite database connection
// TODO: Create the products table if it doesn't exist
// The table should have columns: id, name, price, quantity, category
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
return nil, err
}
ctx, _ := context.WithTimeout(context.Background(), 5 * time.Second)
if err = db.PingContext(ctx); err != nil {
return nil, err
}
Comment on lines +40 to +43
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Context cancel function leaked.

The cancel function from context.WithTimeout is discarded. This can leak resources associated with the context. Always call the cancel function when the context is no longer needed.

🛠️ Proposed fix
-	ctx, _ := context.WithTimeout(context.Background(), 5 * time.Second)
+	ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
+	defer cancel()
 	if err = db.PingContext(ctx); err != nil {
 	    return nil, err
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ctx, _ := context.WithTimeout(context.Background(), 5 * time.Second)
if err = db.PingContext(ctx); err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
defer cancel()
if err = db.PingContext(ctx); err != nil {
return nil, err
}


query := `CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(255),
price DOUBLE,
quantity INT,
category VARCHAR(255)
);`
_, err = db.Exec(query)
if err != nil {
return nil, err
}
return db, nil
}

// CreateProduct adds a new product to the database
func (ps *ProductStore) CreateProduct(product *Product) error {
// TODO: Insert the product into the database
// TODO: Update the product.ID with the database-generated ID
query := "INSERT INTO products(name, price, quantity, category) VALUES ($1, $2, $3, $4) RETURNING id"
err := ps.db.QueryRow(query, product.Name, product.Price, product.Quantity, product.Category).Scan(&product.ID)
return err
}

// GetProduct retrieves a product by ID
func (ps *ProductStore) GetProduct(id int64) (*Product, error) {
// TODO: Query the database for a product with the given ID
// TODO: Return a Product struct populated with the data or an error if not found
query := "SELECT * from products WHERE id = $1"
var p Product
err := ps.db.QueryRow(query, id).Scan(&p.ID, &p.Name, &p.Price, &p.Quantity, &p.Category)
if err != nil {
return nil, err
}
return &p, nil
}

// UpdateProduct updates an existing product
func (ps *ProductStore) UpdateProduct(product *Product) error {
// TODO: Update the product in the database
// TODO: Return an error if the product doesn't exist
query := "UPDATE products SET name=$2, price=$3, quantity=$4, category=$5 WHERE id = $1"
_, err := ps.db.Exec(query, product.Name, product.Price, product.Quantity, product.Category, product.ID)
return err
Comment on lines +85 to +87
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Parameter order mismatch will cause incorrect updates.

The query uses $1 for id in the WHERE clause, but the parameters are passed with product.Name first. This means $1 receives the name instead of the ID, causing the update to either fail or modify incorrect rows.

🐛 Proposed fix
 	query := "UPDATE products SET name=$2, price=$3, quantity=$4, category=$5 WHERE id = $1"
-	_, err := ps.db.Exec(query, product.Name, product.Price, product.Quantity, product.Category, product.ID)
+	_, err := ps.db.Exec(query, product.ID, product.Name, product.Price, product.Quantity, product.Category)
 	return err
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
query := "UPDATE products SET name=$2, price=$3, quantity=$4, category=$5 WHERE id = $1"
_, err := ps.db.Exec(query, product.Name, product.Price, product.Quantity, product.Category, product.ID)
return err
query := "UPDATE products SET name=$2, price=$3, quantity=$4, category=$5 WHERE id = $1"
_, err := ps.db.Exec(query, product.ID, product.Name, product.Price, product.Quantity, product.Category)
return err

}

// DeleteProduct removes a product by ID
func (ps *ProductStore) DeleteProduct(id int64) error {
// TODO: Delete the product from the database
// TODO: Return an error if the product doesn't exist
query := "DELETE FROM products WHERE id = $1"
_, err := ps.db.Exec(query, id)
return err
}
Comment on lines +90 to +97
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing "product not found" error when deleting non-existent product.

Per the TODO comment, this method should return an error if the product doesn't exist. Currently, deleting a non-existent ID silently succeeds.

🐛 Proposed fix
 func (ps *ProductStore) DeleteProduct(id int64) error {
 	// TODO: Delete the product from the database
 	// TODO: Return an error if the product doesn't exist
 	query := "DELETE FROM products WHERE id = $1"
-	_, err := ps.db.Exec(query, id)
-	return err
+	result, err := ps.db.Exec(query, id)
+	if err != nil {
+		return err
+	}
+	rowsAffected, err := result.RowsAffected()
+	if err != nil {
+		return err
+	}
+	if rowsAffected == 0 {
+		return sql.ErrNoRows
+	}
+	return nil
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// DeleteProduct removes a product by ID
func (ps *ProductStore) DeleteProduct(id int64) error {
// TODO: Delete the product from the database
// TODO: Return an error if the product doesn't exist
query := "DELETE FROM products WHERE id = $1"
_, err := ps.db.Exec(query, id)
return err
}
// DeleteProduct removes a product by ID
func (ps *ProductStore) DeleteProduct(id int64) error {
// TODO: Delete the product from the database
// TODO: Return an error if the product doesn't exist
query := "DELETE FROM products WHERE id = $1"
result, err := ps.db.Exec(query, id)
if err != nil {
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
return sql.ErrNoRows
}
return nil
}


// ListProducts returns all products with optional filtering by category
func (ps *ProductStore) ListProducts(category string) ([]*Product, error) {
// TODO: Query the database for products
// TODO: If category is not empty, filter by category
// TODO: Return a slice of Product pointers
// TODO: Query the database for a product with the given ID
// TODO: Return a Product struct populated with the data or an error if not found
query := "SELECT * from products WHERE category = $1"
if category == "" {
query = "SELECT * from products"
}
var res []*Product
rows, err := ps.db.Query(query, category)
if err != nil {
return nil, err
}
Comment on lines +106 to +114
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Bug: Parameter passed to query without placeholders when category is empty.

When category == "", the query is set to "SELECT * from products" (no placeholders), but ps.db.Query(query, category) still passes the category parameter. This can cause unexpected behavior or errors.

🐛 Proposed fix
-	query := "SELECT * from products WHERE category = $1"
-	if category == "" {
-	   query = "SELECT * from products" 
-	}
 	var res []*Product
-	rows, err := ps.db.Query(query, category)
+	var rows *sql.Rows
+	var err error
+	if category == "" {
+		rows, err = ps.db.Query("SELECT * FROM products")
+	} else {
+		rows, err = ps.db.Query("SELECT * FROM products WHERE category = $1", category)
+	}
 	if err != nil {
 	    return nil, err
 	}
+	defer rows.Close()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
query := "SELECT * from products WHERE category = $1"
if category == "" {
query = "SELECT * from products"
}
var res []*Product
rows, err := ps.db.Query(query, category)
if err != nil {
return nil, err
}
var res []*Product
var rows *sql.Rows
var err error
if category == "" {
rows, err = ps.db.Query("SELECT * FROM products")
} else {
rows, err = ps.db.Query("SELECT * FROM products WHERE category = $1", category)
}
if err != nil {
return nil, err
}
defer rows.Close()


for rows.Next() {
p := &Product{}
err := rows.Scan(&p.ID, &p.Name, &p.Price, &p.Quantity, &p.Category)
if err != nil {
return nil, err
}

res = append(res, p)
}

if err = rows.Err(); err != nil {
return nil, err
}
return res, nil
}

// BatchUpdateInventory updates the quantity of multiple products in a single transaction
func (ps *ProductStore) BatchUpdateInventory(updates map[int64]int) error {
// TODO: Start a transaction
// TODO: For each product ID in the updates map, update its quantity
// TODO: If any update fails, roll back the transaction
// TODO: Otherwise, commit the transaction
tx, _ := ps.db.BeginTx(context.Background(), nil)
defer tx.Rollback()
Comment on lines +138 to +139
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Transaction start error is ignored, risking nil pointer panic.

If BeginTx fails, tx will be nil and the subsequent defer tx.Rollback() will panic.

🐛 Proposed fix
-	tx, _ := ps.db.BeginTx(context.Background(), nil)
+	tx, err := ps.db.BeginTx(context.Background(), nil)
+	if err != nil {
+		return err
+	}
 	defer tx.Rollback()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tx, _ := ps.db.BeginTx(context.Background(), nil)
defer tx.Rollback()
tx, err := ps.db.BeginTx(context.Background(), nil)
if err != nil {
return err
}
defer tx.Rollback()

for id := range updates {
query := "UPDATE products SET quantity=$1 WHERE id = $2"
res, err := tx.Exec(query, updates[id], id)
if err != nil {
tx.Rollback()
return err
}

rows, err := res.RowsAffected()
if err != nil {
tx.Rollback()
return err
}

if rows == 0 {
tx.Rollback()
return errors.New("product not found")
}
}
tx.Commit()
return nil
Comment on lines +159 to +160
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Commit error is ignored.

If the transaction commit fails (e.g., constraint violation, I/O error), the error is silently discarded. The function returns nil even though the updates may not have persisted.

🐛 Proposed fix
-	tx.Commit()
-	return nil
+	return tx.Commit()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tx.Commit()
return nil
return tx.Commit()

}

func main() {
// Optional: you can write code here to test your implementation
}
Loading