Skip to content

Add solution for Challenge 13 by Onkar-25#1407

Open
Onkar-25 wants to merge 1 commit intoRezaSi:mainfrom
Onkar-25:challenge-13-Onkar-25
Open

Add solution for Challenge 13 by Onkar-25#1407
Onkar-25 wants to merge 1 commit intoRezaSi:mainfrom
Onkar-25:challenge-13-Onkar-25

Conversation

@Onkar-25
Copy link
Contributor

Challenge 13 Solution

Submitted by: @Onkar-25
Challenge: Challenge 13

Description

This PR contains my solution for Challenge 13.

Changes

  • Added solution file to challenge-13/submissions/Onkar-25/solution-template.go

Testing

  • Solution passes all test cases
  • Code follows Go best practices

Thank you for reviewing my submission! 🚀

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 22, 2026

Walkthrough

This PR introduces a SQLite-backed ProductStore implementation in Go for inventory management. It defines a Product struct and ProductStore type with database initialization, CRUD operations (create, read, update, delete), product listing with optional category filtering, and a transactional batch inventory update capability with proper commit/rollback semantics.

Changes

Cohort / File(s) Summary
SQLite Product Inventory Store
challenge-13/submissions/Onkar-25/solution-template.go
Introduces Product struct (ID, Name, Price, Quantity, Category), ProductStore wrapper around sql.DB, InitDB function for database creation and schema setup, NewProductStore constructor, CRUD methods (CreateProduct, GetProduct, UpdateProduct, DeleteProduct), ListProducts with optional category filtering, and BatchUpdateInventory with transaction handling including rollback semantics. All methods include error wrapping and resource cleanup.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A database hops into place,
Products stored with SQLite grace,
CRUD operations, batch updates too,
Transactions commit—what a world anew! ✨🗄️

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a solution for Challenge 13, which matches the file addition and PR objectives.
Description check ✅ Passed The description is directly related to the changeset, detailing the Challenge 13 solution submission with file location and testing claims.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
challenge-13/submissions/Onkar-25/solution-template.go (3)

5-5: Remove the commented-out import.

// "errors" is a dead-code leftover and should be deleted.

🧹 Proposed fix
-	//"errors"

44-48: return db, errerr is always nil here; prefer return db, nil for clarity.

If db.Exec at line 42 fails, the function returns at line 45. By line 48 err can only be nil, so returning it is a no-op but confusing to readers.

🧹 Proposed fix
-	return db,err
+	return db, nil

97-101: UpdateProduct — pre-existence check via GetProduct is a redundant round-trip.

The GetProduct call at line 98 is unnecessary: if the product doesn't exist, the subsequent UPDATE will simply affect 0 rows, which is already caught by the rowsAffected == 0 check at line 117. The extra select also introduces a TOCTOU window (the row could be deleted between the check and the update).

Consider removing the GetProduct call and relying solely on the rowsAffected == 0 guard, returning a "product with ID %d not found" message there instead:

♻️ Proposed simplification
 func (ps *ProductStore) UpdateProduct(product *Product) error {
-    _,err := ps.GetProduct(product.ID)
-    if err != nil{
-        return err
-    }
-    
     query:= `
     UPDATE products
     SET name = ?,price = ?,quantity = ?,category=?
     WHERE id = ?
     `
-    result,err:= ps.db.Exec(query,product.Name,product.Price,product.Quantity,product.Category,product.ID)
+    result, err := ps.db.Exec(query,product.Name,product.Price,product.Quantity,product.Category,product.ID)
     
     if err != nil {
         return fmt.Errorf("failed to update product: %w", err)
     }
     rowsAffected, err := result.RowsAffected()
     if err != nil {
         return fmt.Errorf("failed to get rows affected: %w", err)
     }
     if rowsAffected == 0 {
-        return fmt.Errorf("no rows were updated")
+        return fmt.Errorf("product with ID %d not found", product.ID)
     }
     return nil

Comment on lines +154 to +158
if category != ""{
query = query + `WHERE category = ?`
}

rows, err := ps.db.Query(query,category)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

ListProducts crashes with "expected 0 arguments, got 1" when category is empty.

When category == "", the WHERE clause is omitted so the query has no ? placeholder, but category is still unconditionally passed as an argument to db.Query. The "sql: expected 0 arguments, got 1" error occurs when you pass arguments to a SQL query that has no placeholders — the number of parameters provided must match the number of ? markers in the statement.

Every call to ListProducts("") will return an error instead of the full product list.

🐛 Proposed fix — use variadic args
-	query:= `SELECT *
-	FROM products
-	`
-	if category != ""{
-	    query = query + `WHERE category = ?`
-	}
-	
-	rows, err := ps.db.Query(query,category)
+	query := `SELECT * FROM products`
+	var args []interface{}
+	if category != "" {
+		query += ` WHERE category = ?`
+		args = append(args, category)
+	}
+
+	rows, err := ps.db.Query(query, args...)

Comment on lines +158 to +173
rows, err := ps.db.Query(query,category)
if err != nil{
return nil , err
}

var product []*Product

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

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

ListProducts leaks the sql.Rows handle and silently swallows iteration errors.

Two issues in combination:

  1. Missing defer rows.Close() — if rows.Scan() fails and the function returns early, the *sql.Rows is never closed. This holds the underlying database connection open, exhausting the connection pool over time.

  2. Missing rows.Err() check — after rows.Next() returns false, the caller must check rows.Err() to detect any driver-level error that terminated the iteration. Without it, partial results can be returned with a nil error.

🐛 Proposed fix
 	rows, err := ps.db.Query(query, args...)
 	if err != nil{
 	    return nil , err
 	}
+	defer rows.Close()
 	
 	var product []*Product
 	
 	for rows.Next(){
 	    p:= &Product{}
 	    err := rows.Scan(&p.ID,&p.Name,&p.Price,&p.Quantity,&p.Category)
 	    if err!=nil{
 	        return nil, err
 	    }
 	    product = append(product,p)
 	}
-	return product,nil
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return product, nil

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant