Skip to content
Open
Show file tree
Hide file tree
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
65 changes: 65 additions & 0 deletions db/example_queries.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
-- example_queries.sql
USE product_inventory;

-- 1) Search products by attribute (manufacturer) using generated column
SELECT id, sku_master, name, JSON_EXTRACT(attributes, '$.color') AS color
FROM product
WHERE manufacturer = 'Acme Corp';

-- 2) Find total inventory for an SKU across all locations
SELECT s.sku_code, SUM(ii.quantity) AS total_qty
FROM sku s
JOIN inventory_item ii ON ii.sku_id = s.id
WHERE s.sku_code = 'SKU-12345'
GROUP BY s.sku_code;

-- 3) Reserve stock transactionally (simple example)
-- Business assumption: reservation reduces available quantity immediately.
START TRANSACTION;

-- lock the inventory row
SELECT * FROM inventory_item
WHERE sku_id = 1 AND location_id = 1 FOR UPDATE;

-- check quantity and update
UPDATE inventory_item
SET quantity = quantity - 2
WHERE sku_id = 1 AND location_id = 1 AND quantity >= 2;

-- insert audit transaction
INSERT INTO stock_transaction (inventory_item_id, txn_type, qty_delta, metadata)
VALUES (1, 'reserve', -2, JSON_OBJECT('order_id', 'ORD-1001'));

COMMIT;

-- 4) Consume FIFO lots stored in JSON 'lots_batches' (conceptual)
-- lots_batches example: [{"lot":"L1","qty":10,"received_at":"2026-01-12"}, {...}]
-- Pseudocode / approach: read JSON, iterate oldest lots in app code, update lots_batches JSON and inventory_item.quantity, and insert stock_transaction entries.

-- 5) Create a PO with lines stored as JSON
INSERT INTO purchase_order (supplier_id, po_number, lines, status)
VALUES (1, 'PO-2026-0001',
JSON_ARRAY(JSON_OBJECT('sku_id', 1, 'qty', 100, 'unit_cost', 5.25)),
'open');

-- 6) Receive PO lines and update inventory (example for one line)
START TRANSACTION;
-- find or create inventory_item for sku/location
INSERT INTO inventory_item (sku_id, location_id, quantity, lots_batches)
VALUES (1, 1, 100, JSON_ARRAY(JSON_OBJECT('lot','L2026-01-01','qty',100,'received_at',NOW())))
ON DUPLICATE KEY UPDATE quantity = quantity + VALUES(quantity),
lots_batches = JSON_ARRAY_APPEND(COALESCE(lots_batches, JSON_ARRAY()), '$', JSON_OBJECT('lot','L2026-01-01','qty',100,'received_at',NOW()));

-- insert stock transaction
INSERT INTO stock_transaction (inventory_item_id, txn_type, qty_delta, metadata)
VALUES (LAST_INSERT_ID(), 'po_receipt', 100, JSON_OBJECT('po_number','PO-2026-0001','sku_id',1));

COMMIT;

-- 7) Audit: get all transactions for an SKU in date range
SELECT st.*
FROM stock_transaction st
JOIN inventory_item ii ON st.inventory_item_id = ii.id
JOIN sku s ON ii.sku_id = s.id
WHERE s.sku_code = 'SKU-12345' AND st.txn_at BETWEEN '2026-01-01' AND '2026-12-31'
ORDER BY st.txn_at;
104 changes: 104 additions & 0 deletions db/migrations/001_create_schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
-- 001_create_schema.sql
-- Hybrid relational + JSON schema for Products & Inventory

CREATE DATABASE IF NOT EXISTS product_inventory;
USE product_inventory;

CREATE TABLE product (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
sku_master VARCHAR(100) NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
attributes JSON NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX (sku_master),
FULLTEXT KEY ft_name (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE sku (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
product_id BIGINT NOT NULL,
sku_code VARCHAR(100) NOT NULL,
barcode VARCHAR(128),
sku_attributes JSON NULL,
weight DECIMAL(10,3),
length DECIMAL(10,3),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES product(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE category (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(150) NOT NULL,
description TEXT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE product_category (
product_id BIGINT NOT NULL,
category_id BIGINT NOT NULL,
PRIMARY KEY (product_id, category_id),
FOREIGN KEY (product_id) REFERENCES product(id) ON DELETE CASCADE,
FOREIGN KEY (category_id) REFERENCES category(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE inventory_location (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
code VARCHAR(50) UNIQUE,
name VARCHAR(255),
type VARCHAR(50),
metadata JSON NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE inventory_item (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
sku_id BIGINT NOT NULL,
location_id BIGINT NOT NULL,
quantity INT NOT NULL DEFAULT 0,
lots_batches JSON NULL,
last_counted_at DATETIME NULL,
FOREIGN KEY (sku_id) REFERENCES sku(id) ON DELETE CASCADE,
FOREIGN KEY (location_id) REFERENCES inventory_location(id) ON DELETE CASCADE,
UNIQUE KEY ux_sku_location (sku_id, location_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE stock_transaction (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
inventory_item_id BIGINT NOT NULL,
txn_type VARCHAR(50) NOT NULL,
qty_delta INT NOT NULL,
txn_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
metadata JSON NULL,
FOREIGN KEY (inventory_item_id) REFERENCES inventory_item(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE supplier (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
contact JSON NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE purchase_order (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
supplier_id BIGINT,
po_number VARCHAR(100) NOT NULL,
po_lines JSON NULL,
status VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (supplier_id) REFERENCES supplier(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- Example: create generated column from JSON 'attributes.manufacturer' and index it
ALTER TABLE product
ADD COLUMN manufacturer VARCHAR(200) GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(attributes, '$.manufacturer'))) STORED;
CREATE INDEX idx_product_manufacturer ON product(manufacturer);

-- Example: index a SKU JSON attribute (color)
ALTER TABLE sku
ADD COLUMN color VARCHAR(100) GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(sku_attributes, '$.color'))) STORED;
CREATE INDEX idx_sku_color ON sku(color);

-- Notes:
-- - Use transactions when updating inventory_item.quantity and inserting stock_transaction to keep balances consistent.
-- - Consider partitioning stock_transaction by date for very large volumes.
-- - Use application-level logic or stored procedures to enforce lot FIFO when consuming lots in JSON 'lots_batches'.
Loading