diff --git a/sql/registry.sql b/sql/registry.sql index 6e39a39..1767682 100644 --- a/sql/registry.sql +++ b/sql/registry.sql @@ -8,7 +8,7 @@ CREATE TABLE shards ( db_name VARCHAR(50) NOT NULL, host_address VARCHAR(255) NOT NULL, port INT NOT NULL DEFAULT 53096 -); +) ENGINE=InnoDB; CREATE TABLE user_shard_map ( user_id BINARY(16) PRIMARY KEY, @@ -19,45 +19,38 @@ CREATE TABLE user_shard_map ( is_active TINYINT(1) NOT NULL DEFAULT 1, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (shard_id) REFERENCES shards(shard_id) -); +) ENGINE=InnoDB; CREATE TABLE cost_group_statuses ( status_id TINYINT PRIMARY KEY, name VARCHAR(20) UNIQUE NOT NULL -); +) ENGINE=InnoDB; CREATE TABLE cost_groups ( group_id BINARY(16) PRIMARY KEY, name VARCHAR(100) NOT NULL, created_by BINARY(16), - status_id TINYINT NOT NULL DEFAULT '1', + status_id TINYINT NOT NULL DEFAULT 1, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (created_by) REFERENCES user_shard_map(user_id), FOREIGN KEY (status_id) REFERENCES cost_group_statuses(status_id) -); +) ENGINE=InnoDB; CREATE TABLE group_roles ( role_id TINYINT PRIMARY KEY, name VARCHAR(20) UNIQUE NOT NULL -); +) ENGINE=InnoDB; CREATE TABLE group_members ( group_id BINARY(16), user_id BINARY(16), - role_id TINYINT DEFAULT '3', + role_id TINYINT DEFAULT 3, joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (group_id, user_id), FOREIGN KEY (group_id) REFERENCES cost_groups(group_id), - FOREIGN KEY (role_id) REFERENCES group_roles(role_id), - FOREIGN KEY (user_id) REFERENCES user_shard_map(user_id) -); + FOREIGN KEY (user_id) REFERENCES user_shard_map(user_id), + FOREIGN KEY (role_id) REFERENCES group_roles(role_id) +) ENGINE=InnoDB; -INSERT INTO cost_group_statuses (status_id, name) VALUES -(1, 'active'), -(2, 'settled'), -(3, 'archived'); - -INSERT INTO group_roles (role_id, name) VALUES -(1, 'owner'), -(2, 'editor'), -(3, 'participant'); +INSERT INTO cost_group_statuses (status_id, name) VALUES (1, 'active'), (2, 'settled'), (3, 'archived'); +INSERT INTO group_roles (role_id, name) VALUES (1, 'owner'), (2, 'editor'), (3, 'participant'); diff --git a/sql/shard.sql b/sql/shard.sql index b3f17bf..a14e2e8 100644 --- a/sql/shard.sql +++ b/sql/shard.sql @@ -5,88 +5,95 @@ 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, - category_id INT, amount DECIMAL(15, 2) NOT NULL, currency_code CHAR(3) NOT NULL, description VARCHAR(255), - status_id TINYINT DEFAULT '1', + status_id TINYINT DEFAULT 1, + type_id TINYINT NOT NULL, created_at DATETIME NOT NULL, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - 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_confirmed DECIMAL(15, 2) DEFAULT 0.00, - total_pending DECIMAL(15, 2) DEFAULT 0.00, + 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; -INSERT INTO ledger_statuses (status_id, name) VALUES -(1, 'proposed'), -(2, 'ratified'), -(3, 'disputed'), -(4, 'settled'); +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 TRIGGER after_ledger_insert -AFTER INSERT ON ledger -FOR EACH ROW +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 - IF NEW.status_id = 1 THEN - UPDATE user_balances - SET total_pending = total_pending + NEW.amount - WHERE user_id = NEW.user_id AND currency_code = NEW.currency_code; - ELSEIF NEW.status_id IN (2, 4) THEN - UPDATE user_balances - SET total_confirmed = total_confirmed + NEW.amount - WHERE user_id = NEW.user_id AND currency_code = NEW.currency_code; + 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_update -AFTER UPDATE ON ledger -FOR EACH ROW +CREATE TRIGGER after_ledger_insert AFTER INSERT ON ledger FOR EACH ROW BEGIN - IF OLD.status_id = 1 THEN - UPDATE user_balances SET total_pending = total_pending - OLD.amount - WHERE user_id = OLD.user_id AND currency_code = OLD.currency_code; - ELSEIF OLD.status_id IN (2, 4) THEN - UPDATE user_balances SET total_confirmed = total_confirmed - OLD.amount - WHERE user_id = OLD.user_id AND currency_code = OLD.currency_code; - END IF; - IF NEW.status_id = 1 THEN - UPDATE user_balances SET total_pending = total_pending + NEW.amount - WHERE user_id = NEW.user_id AND currency_code = NEW.currency_code; - ELSEIF NEW.status_id IN (2, 4) THEN - UPDATE user_balances SET total_confirmed = total_confirmed + NEW.amount - WHERE user_id = NEW.user_id AND currency_code = NEW.currency_code; - END IF; + 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 +CREATE TRIGGER after_ledger_update AFTER UPDATE ON ledger FOR EACH ROW BEGIN - IF OLD.status_id = 1 THEN - UPDATE user_balances SET total_pending = total_pending - OLD.amount - WHERE user_id = OLD.user_id AND currency_code = OLD.currency_code; - ELSEIF OLD.status_id IN (2, 4) THEN - UPDATE user_balances SET total_confirmed = total_confirmed - OLD.amount - WHERE user_id = OLD.user_id AND currency_code = OLD.currency_code; - END IF; + 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 ; - -