inventory_db.ry
module inventory_db
purpose: Keep a small stock inventory in SQLite and report what needs reordering.
import std.console
import std.filesystem exposing Path
import std.sqlite exposing Connection, DbError, FromRow
public type InventoryError is one of
purpose: Why a stock change could not be applied.
UnknownSku(sku: Text)
end
public type Item
purpose: One product as stored in the items table; field names match the column names.
has sku: Text
has name: Text
has quantity: Integer where quantity is at least 0
has reorder_level: Integer where reorder_level is at least 0
can FromRow
end
let create_table: Text be """
CREATE TABLE IF NOT EXISTS items (
sku TEXT PRIMARY KEY,
name TEXT NOT NULL,
quantity INTEGER NOT NULL,
reorder_level INTEGER NOT NULL
)
"""
public function open_inventory(path: Path) returns Connection or fails with DbError needs filesystem
purpose: Open the database file and make sure the items table exists.
let connection be sqlite.open(path) otherwise fail
ignore connection.execute(sql: create_table, parameters: []) otherwise fail
return connection
end
public function low_stock(connection: Connection)
returns List of Item
or fails with DbError
needs filesystem.read
purpose: Items whose quantity is at or below their reorder level, lowest quantity first.
tags: inventory, sqlite
let sql be "SELECT * FROM items WHERE quantity <= reorder_level ORDER BY quantity"
let items: List of Item be connection.query(sql: sql, parameters: []) otherwise fail
return items
end
public function record_delivery(connection: Connection, sku: Text, amount: Integer)
or fails with DbError or InventoryError
needs filesystem
purpose: Add the delivered amount to the stock of one item; the item must exist.
let sql be "UPDATE items SET quantity = quantity + ? WHERE sku = ?"
let parameters be [sqlite.integer(amount), sqlite.text(sku)]
let changed_rows be connection.execute(sql: sql, parameters: parameters) otherwise fail
if changed_rows is 0 then fail with UnknownSku(sku: sku) end
end
public function main() or fails with DbError or InventoryError needs console, filesystem
purpose: Record one delivery, then list every item that still needs reordering.
let connection be open_inventory(Path("data/inventory.db")) otherwise fail
record_delivery(connection: connection, sku: "BOLT-10", amount: 500) otherwise fail
let items be low_stock(connection) otherwise fail
if items.is_empty() then console.print("nothing to reorder") end
for each item in items
console.print("{item.sku} {item.name}: {item.quantity} left, reorder at {item.reorder_level}")
end
connection.close()
end
test "low stock is listed" needs filesystem replays "fixtures/inventory.json"
let connection be open_inventory(Path("data/inventory_test.db")) otherwise fail
let seed be """
INSERT OR REPLACE INTO items VALUES
('NUT-10', 'Nut', 0, 5),
('BOLT-10', 'Bolt', 2, 8)
"""
ignore connection.execute(sql: seed, parameters: []) otherwise fail
record_delivery(connection: connection, sku: "BOLT-10", amount: 500) otherwise fail
let items be low_stock(connection) otherwise fail
connection.close()
let skus be for each item in items collect item.sku
check skus is ["NUT-10"]
end