-
Notifications
You must be signed in to change notification settings - Fork 10
/
init.postgresql.shards copy.sql
145 lines (123 loc) · 3.58 KB
/
init.postgresql.shards copy.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
CREATE UNLOGGED TABLE clientes (
id SERIAL,
saldo INTEGER NOT NULL DEFAULT 0,
shard INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (id, shard)
);
CREATE UNLOGGED TABLE transacoes (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
cliente_id INTEGER NOT NULL,
valor INTEGER NOT NULL,
tipo CHAR(1) NOT NULL,
descricao VARCHAR(10) NOT NULL,
realizada_em TIMESTAMP(6) NOT NULL
);
CREATE INDEX idx_realizada_em ON transacoes (realizada_em);
INSERT INTO clientes(id, saldo, shard) VALUES
(1,0,0), (2,0,0), (3,0,0), (4,0,0), (5,0,0),
(1,0,1), (2,0,1), (3,0,1), (4,0,1), (5,0,1);
CREATE EXTENSION IF NOT EXISTS pg_prewarm;
SELECT pg_prewarm('clientes');
SELECT pg_prewarm('transacoes');
CREATE OR REPLACE FUNCTION limite_cliente(p_cliente_id INTEGER)
RETURNS INTEGER AS $$
BEGIN
RETURN CASE p_cliente_id
WHEN 1 THEN 100000
WHEN 2 THEN 80000
WHEN 3 THEN 1000000
WHEN 4 THEN 10000000
WHEN 5 THEN 500000
ELSE -1
END;
END;
$$ LANGUAGE plpgsql;
CREATE TYPE json_result AS (
status_code INT,
body json
);
CREATE OR REPLACE FUNCTION proc_transacao(p_shard INT, p_cliente_id INT, p_valor INT, p_tipo CHAR, p_descricao CHAR(10))
RETURNS json_result as $$
DECLARE
diff INT;
v_saldo INT;
v_limite INT;
v_sum INT;
result json_result;
BEGIN
SELECT limite_cliente(p_cliente_id) INTO v_limite;
-- m_shard := p_valor % 10
SELECT saldo
INTO v_saldo
FROM clientes
WHERE
id = p_cliente_id
AND shard = p_shard
FOR UPDATE;
SELECT SUM(saldo)
INTO v_sum
FROM clientes
WHERE id = p_cliente_id;
IF p_tipo = 'd' THEN
diff := p_valor * -1;
IF (v_sum + diff) < (-1 * v_limite) THEN
result.body := 'LIMITE_INDISPONIVEL';
result.status_code := 422;
RETURN result;
END IF;
ELSE
diff := p_valor;
END IF;
INSERT INTO transacoes
(cliente_id, valor, tipo, descricao, realizada_em)
VALUES (p_cliente_id, p_valor, p_tipo, p_descricao, now());
UPDATE clientes
SET saldo = saldo + diff
WHERE id = p_cliente_id
AND shard = p_shard;
SELECT json_build_object(
'saldo', v_sum + diff,
'limite', v_limite
) into result.body;
result.status_code := 200;
RETURN result;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION proc_extrato(p_cliente_id int)
RETURNS json_result AS $$
DECLARE
result json_result;
row_count integer;
v_saldo numeric;
v_limite numeric;
BEGIN
SELECT SUM(saldo)
INTO v_saldo
FROM clientes
WHERE id = p_cliente_id;
IF NOT FOUND THEN
result.body := 'CLIENTE_NAO_ENCONTRADO';
result.status_code := 404;
RETURN result;
END IF;
SELECT limite_cliente(p_cliente_id) INTO v_limite;
SELECT json_build_object(
'saldo', json_build_object(
'total', v_saldo,
'data_extrato', TO_CHAR(now(), 'YYYY-MM-DD HH:MI:SS.US'),
'limite', v_limite
),
'ultimas_transacoes', COALESCE((
SELECT json_agg(row_to_json(t)) FROM (
SELECT valor, tipo, descricao, TO_CHAR(realizada_em, 'YYYY-MM-DD HH:MI:SS.US') as realizada_em
FROM transacoes
WHERE cliente_id = p_cliente_id
ORDER BY realizada_em DESC
LIMIT 10
) t
), '[]')
) INTO result.body;
result.status_code := 200;
RETURN result;
END;
$$ LANGUAGE plpgsql;