Refactorization and splitting of schema files

This commit is contained in:
Florian "flowdy" Heß
2017-01-19 21:44:22 +01:00
parent 53ef8ff175
commit 336185aee1
23 changed files with 475 additions and 455 deletions

View File

@@ -0,0 +1,66 @@
CREATE TRIGGER balanceTransfer
AFTER INSERT ON Transfer
BEGIN
SELECT RAISE(FAIL, "It is not the debtor who is set to pay")
WHERE (SELECT debtor FROM Debit WHERE billId=NEW.billId)
!= (SELECT account FROM Credit WHERE credId=NEW.credId)
;
SELECT RAISE(FAIL, "Target of a debit cannot be an incoming payment")
FROM Credit c
JOIN Debit d ON c.credId = d.targetCredit
WHERE c.credId = NEW.credId
AND c.value > 0
GROUP BY c.credId
HAVING count(d.billId) == 0
;
INSERT INTO __DO_NOT_MANIPULATE__trigger_memory
SELECT remainingDebt, remainingCredit, min(remainingDebt,remainingCredit)
FROM (SELECT
(SELECT value - paid FROM Debit WHERE billId=NEW.billId) AS remainingDebt,
(SELECT value - spent FROM Credit WHERE credId=NEW.credId) AS remainingCredit
)
;
UPDATE Debit
SET paid = paid + CASE
WHEN (SELECT d FROM __DO_NOT_MANIPULATE__trigger_memory) <= 0
THEN RAISE(FAIL, "Debt settled")
ELSE
(SELECT m FROM __DO_NOT_MANIPULATE__trigger_memory)
END
WHERE billId=NEW.billId;
UPDATE Credit
SET spent = spent + CASE
WHEN (SELECT c FROM __DO_NOT_MANIPULATE__trigger_memory) <= 0
THEN RAISE(FAIL, "Credit spent")
ELSE IFNULL(
(SELECT m FROM __DO_NOT_MANIPULATE__trigger_memory),
RAISE(FAIL,"Oops, lost __DO_NOT_MANIPULATE__trigger_memory record before increasing spent")
)
END
WHERE credId=NEW.credId;
UPDATE Transfer
SET amount = (SELECT m FROM __DO_NOT_MANIPULATE__trigger_memory)
WHERE billId=NEW.billId AND credId=NEW.credId
;
UPDATE Credit
SET value = value + IFNULL(
(SELECT m FROM __DO_NOT_MANIPULATE__trigger_memory),
RAISE(FAIL, "Oops, lost __DO_NOT_MANIPULATE__trigger_memory record before increasing value")
)
WHERE credId = (
SELECT targetCredit
FROM Debit
WHERE billId=NEW.billId
);
DELETE FROM __DO_NOT_MANIPULATE__trigger_memory;
END;

View File

@@ -0,0 +1,13 @@
CREATE TRIGGER checkIBANatTransfer
BEFORE INSERT ON Debit
WHEN NEW.targetCredit IS NULL
BEGIN
SELECT RAISE(FAIL, "IBAN used does not match IBAN currently stored in account record")
FROM (
SELECT instr(NEW.purpose, IBAN) AS fnd
FROM Account
WHERE ID=NEW.debtor
) AS matchingIBAN
WHERE fnd IS NULL OR fnd = 0;
END;

View File

@@ -0,0 +1,12 @@
-- Prevent modification of paid value outside triggers which must adjust it exclusively
-- when new transfer records are inserted
CREATE TRIGGER enforceDebtImmutableOutsideTrigger
BEFORE UPDATE OF paid ON Debit
WHEN NOT EXISTS (SELECT * FROM Transfer t WHERE NEW.billId=t.billId AND amount IS NULL)
BEGIN
SELECT RAISE(FAIL, "paid is set and adjusted automatically according to added Transfer records")
WHERE (NEW.paid + IFNULL(
(SELECT m FROM __DO_NOT_MANIPULATE__trigger_memory WHERE c IS NULL AND d IS NULL), 0
) ) <> OLD.paid;
END;

View File

@@ -0,0 +1,8 @@
CREATE TRIGGER enforceFixedCredit
BEFORE UPDATE OF account, value ON Credit
WHEN EXISTS (SELECT * FROM Transfer WHERE credId=NEW.credId)
AND NOT EXISTS (SELECT * FROM __DO_NOT_MANIPULATE__trigger_memory)
BEGIN
SELECT RAISE(FAIL, "Credit involved in transactions to revoke at first");
END;

View File

@@ -0,0 +1,7 @@
CREATE TRIGGER enforceFixedDebit
BEFORE UPDATE OF debtor, transferCredit, value ON Debit
WHEN EXISTS (SELECT * FROM Transfer WHERE billId=NEW.billId)
BEGIN
SELECT RAISE(FAIL, "Debt is involved in transfers to revoke at first");
END;

View File

@@ -0,0 +1,7 @@
CREATE TRIGGER enforceImmutableTransfer
BEFORE UPDATE ON Transfer
WHEN OLD.amount IS NOT NULL
BEGIN
SELECT RAISE(FAIL, "Transfer cannot be updated, but needs to be replaced to make triggers run");
END;

View File

@@ -0,0 +1,12 @@
-- Prevent modification of spent value outside triggers which must adjust it exclusively
-- when new transfer records are inserted
CREATE TRIGGER enforceSpentImmutableOutsideTrigger
BEFORE UPDATE OF spent ON Credit
WHEN NOT EXISTS (SELECT * FROM Transfer t WHERE NEW.credId=t.credId AND amount IS NULL)
BEGIN
SELECT RAISE(FAIL, "spent is set and adjusted automatically according to added Transfer records")
WHERE (NEW.spent + IFNULL(
(SELECT m FROM __DO_NOT_MANIPULATE__trigger_memory WHERE c IS NULL AND d IS NULL), 0
) ) <> OLD.spent;
END;

View File

@@ -0,0 +1,7 @@
CREATE TRIGGER enforceZeroPaidAtStart
BEFORE INSERT ON Debit
BEGIN
SELECT RAISE(FAIL, "Debt must be initially unpaid")
WHERE NEW.paid <> 0;
END;

View File

@@ -0,0 +1,7 @@
CREATE TRIGGER enforceZeroSpentAtStart
BEFORE INSERT ON Credit
BEGIN
SELECT RAISE(FAIL, "credit must be initially unused")
WHERE NEW.spent != 0;
END;

View File

@@ -0,0 +1,16 @@
-- When we enter a transfer, the targetCredit of the associated bill might already be the credId
-- of a transfer for other dues itself. We can update (replace) the transfer for an unfullfilled one.
-- That way, a transfer may issue recursively chained transfers.
CREATE TRIGGER rebalanceIncreasedCredit
AFTER UPDATE OF value ON Credit
WHEN NEW.value > OLD.spent
BEGIN
REPLACE INTO Transfer (credId, billId)
SELECT OLD.credId, t.billId
FROM Transfer t
JOIN CurrentArrears ca ON t.billId = ca.billId
WHERE OLD.credId = t.credId
;
END;

View File

@@ -0,0 +1,43 @@
-- When a transfer is revoked, the targetCredit of the associated bill is reduced. Hence we must
-- check if we can still have paid the debts linked to this transfer in an "is paid from" relation,
-- otherwise we have to revoke these transfers as well.
CREATE TRIGGER rebalanceReducedCredit
AFTER UPDATE OF value ON Credit
WHEN NEW.value < OLD.spent
BEGIN
REPLACE INTO __DO_NOT_MANIPULATE__trigger_memory (d, m)
SELECT
'from_' || NEW.credId,
billId
FROM Transfer
WHERE credId = NEW.credId
ORDER BY timestamp DESC
LIMIT 1
;
DELETE
FROM Transfer
WHERE credId = NEW.credId
AND billId IN (
SELECT billId
FROM __DO_NOT_MANIPULATE__trigger_memory
WHERE c = 'from_' || NEW.credId
)
;
INSERT INTO Transfer (credId, billId)
SELECT NEW.credId, m
FROM __DO_NOT_MANIPULATE__trigger_memory
WHERE d = 'from_' || NEW.credId
AND NEW.value > (
SELECT spent
FROM Credit
WHERE credId = NEW.credId
)
;
DELETE FROM __DO_NOT_MANIPULATE__trigger_memory WHERE d = 'from_' || NEW.credId;
END;

View File

@@ -0,0 +1,27 @@
CREATE TRIGGER revokeTransfer
BEFORE DELETE ON Transfer
BEGIN
INSERT INTO __DO_NOT_MANIPULATE__trigger_memory VALUES (null,null,OLD.amount);
UPDATE Debit
SET paid = paid - OLD.amount
WHERE billId=OLD.billId
;
UPDATE Credit
SET value = value - OLD.amount
WHERE credId = (
SELECT targetCredit
FROM Debit
WHERE billId=OLD.billId
);
UPDATE Credit
SET spent = spent - OLD.amount
WHERE credId = OLD.credId;
DELETE FROM __DO_NOT_MANIPULATE__trigger_memory;
END;