CREATE DATABASE IF NOT EXISTS argent_shard_01 CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci; USE argent_shard_01; CREATE TABLE ledger_statuses ( status_id TINYINT PRIMARY KEY, name VARCHAR(20) UNIQUE NOT NULL ) ENGINE=InnoDB; CREATE TABLE ledger_entry_types ( type_id TINYINT PRIMARY KEY, name VARCHAR(20) UNIQUE NOT NULL ) ENGINE=InnoDB; CREATE TABLE ledger ( entry_id BINARY(16) NOT NULL, batch_id BINARY(16) NOT NULL, user_id BINARY(16) NOT NULL, group_id BINARY(16) DEFAULT NULL, amount DECIMAL(15, 2) NOT NULL, currency_code CHAR(3) NOT NULL, description VARCHAR(255), status_id TINYINT DEFAULT 1, type_id TINYINT NOT NULL, created_at DATETIME NOT NULL, PRIMARY KEY (user_id, entry_id), FOREIGN KEY (status_id) REFERENCES ledger_statuses(status_id), FOREIGN KEY (type_id) REFERENCES ledger_entry_types(type_id), INDEX (batch_id), INDEX (group_id), INDEX (status_id) ) ENGINE=InnoDB; CREATE TABLE user_balances ( user_id BINARY(16) NOT NULL, currency_code CHAR(3) NOT NULL, total_proposed DECIMAL(15, 2) DEFAULT 0.00, total_ratified DECIMAL(15, 2) DEFAULT 0.00, total_disputed DECIMAL(15, 2) DEFAULT 0.00, total_settled DECIMAL(15, 2) DEFAULT 0.00, total_spent DECIMAL(15, 2) DEFAULT 0.00, PRIMARY KEY (user_id, currency_code) ) ENGINE=InnoDB; CREATE TABLE group_user_balances ( group_id BINARY(16) NOT NULL, user_id BINARY(16) NOT NULL, currency_code CHAR(3) NOT NULL, net_balance DECIMAL(15, 2) DEFAULT 0.00, total_contributed DECIMAL(15, 2) DEFAULT 0.00, PRIMARY KEY (group_id, user_id, currency_code), INDEX (user_id) ) ENGINE=InnoDB; INSERT INTO ledger_statuses (status_id, name) VALUES (1, 'proposed'), (2, 'ratified'), (3, 'disputed'), (4, 'settled'); INSERT INTO ledger_entry_types (type_id, name) VALUES (1, 'expense'), (2, 'settlement'); DELIMITER // CREATE PROCEDURE sync_all_balances( IN p_uid BINARY(16), IN p_gid BINARY(16), IN p_curr CHAR(3), IN p_amt DECIMAL(15,2), IN p_status TINYINT, IN p_type TINYINT, IN p_mod INT ) BEGIN INSERT INTO user_balances (user_id, currency_code) VALUES (p_uid, p_curr) ON DUPLICATE KEY UPDATE user_id = user_id; UPDATE user_balances SET total_proposed = total_proposed + IF(p_status = 1, p_amt * p_mod, 0), total_ratified = total_ratified + IF(p_status = 2, p_amt * p_mod, 0), total_disputed = total_disputed + IF(p_status = 3, p_amt * p_mod, 0), total_settled = total_settled + IF(p_status = 4, p_amt * p_mod, 0), total_spent = total_spent + IF(p_type = 1 AND p_amt > 0, p_amt * p_mod, 0) WHERE user_id = p_uid AND currency_code = p_curr; IF p_gid IS NOT NULL THEN INSERT INTO group_user_balances (group_id, user_id, currency_code, net_balance, total_contributed) VALUES (p_gid, p_uid, p_curr, p_amt * p_mod, IF(p_type = 1 AND p_amt > 0, p_amt * p_mod, 0)) ON DUPLICATE KEY UPDATE net_balance = net_balance + (p_amt * p_mod), total_contributed = total_contributed + IF(p_type = 1 AND p_amt > 0, p_amt * p_mod, 0); END IF; END // CREATE TRIGGER after_ledger_insert AFTER INSERT ON ledger FOR EACH ROW BEGIN CALL sync_all_balances(NEW.user_id, NEW.group_id, NEW.currency_code, NEW.amount, NEW.status_id, NEW.type_id, 1); END // CREATE TRIGGER after_ledger_update AFTER UPDATE ON ledger FOR EACH ROW BEGIN CALL sync_all_balances(OLD.user_id, OLD.group_id, OLD.currency_code, OLD.amount, OLD.status_id, OLD.type_id, -1); CALL sync_all_balances(NEW.user_id, NEW.group_id, NEW.currency_code, NEW.amount, NEW.status_id, NEW.type_id, 1); END // CREATE TRIGGER after_ledger_delete AFTER DELETE ON ledger FOR EACH ROW BEGIN CALL sync_all_balances(OLD.user_id, OLD.group_id, OLD.currency_code, OLD.amount, OLD.status_id, OLD.type_id, -1); END // DELIMITER ;