Skip to main content

rbp_database/
schema.rs

1//! Database schema implementations for domain types.
2//!
3//! Implements Schema/Derive traits directly on types from other crates.
4//! This is possible because Schema/Derive are local to this crate.
5use super::*;
6use rbp_cards::*;
7use rbp_gameplay::*;
8
9impl Schema for Street {
10    fn name() -> &'static str {
11        STREET
12    }
13    fn creates() -> &'static str {
14        const_format::concatcp!(
15            "CREATE TABLE IF NOT EXISTS ",
16            STREET,
17            " (
18                street     SMALLINT,
19                nobs       INTEGER,
20                nabs       INTEGER
21            );
22            TRUNCATE TABLE ",
23            STREET,
24            ";
25            CREATE OR REPLACE FUNCTION get_nabs(s SMALLINT) RETURNS INTEGER AS
26            $$ BEGIN RETURN (SELECT COUNT(*) FROM ",
27            ABSTRACTION,
28            " a WHERE a.street = s); END; $$
29            LANGUAGE plpgsql;"
30        )
31    }
32    fn indices() -> &'static str {
33        const_format::concatcp!(
34            "CREATE INDEX IF NOT EXISTS idx_",
35            STREET,
36            "_st ON ",
37            STREET,
38            " (street);"
39        )
40    }
41    fn copy() -> &'static str {
42        unimplemented!("Street is derived, not loaded from files")
43    }
44    fn truncates() -> &'static str {
45        const_format::concatcp!("TRUNCATE TABLE ", STREET, ";")
46    }
47    fn freeze() -> &'static str {
48        const_format::concatcp!(
49            "ALTER TABLE ",
50            STREET,
51            " SET (fillfactor = 100);
52            ALTER TABLE ",
53            STREET,
54            " SET (autovacuum_enabled = false);"
55        )
56    }
57    fn columns() -> &'static [tokio_postgres::types::Type] {
58        unimplemented!("Street is derived, not loaded from files")
59    }
60}
61
62impl Derive for Street {
63    fn exhaust() -> Vec<Self> {
64        Street::all().iter().rev().copied().collect()
65    }
66    fn inserts(&self) -> String {
67        let s = *self as i16;
68        let n = self.n_isomorphisms() as i32;
69        format!(
70            "INSERT INTO {} (street, nobs, nabs) VALUES ({}, {}, get_nabs({}::SMALLINT));",
71            STREET, s, n, s
72        )
73    }
74}
75
76impl Schema for Abstraction {
77    fn name() -> &'static str {
78        ABSTRACTION
79    }
80    fn creates() -> &'static str {
81        const_format::concatcp!(
82            "CREATE TABLE IF NOT EXISTS ",
83            ABSTRACTION,
84            " (
85                abs         SMALLINT,
86                street      SMALLINT,
87                population  INTEGER,
88                equity      REAL
89            );
90            TRUNCATE TABLE ",
91            ABSTRACTION,
92            ";
93            CREATE OR REPLACE FUNCTION get_population(xxx SMALLINT) RETURNS INTEGER AS
94            $$ BEGIN RETURN (SELECT COUNT(*) FROM ",
95            ISOMORPHISM,
96            " e WHERE e.abs = xxx); END; $$
97            LANGUAGE plpgsql;
98            CREATE OR REPLACE FUNCTION get_street_abs(abs SMALLINT) RETURNS SMALLINT AS
99            $$ BEGIN RETURN ((abs >> 8) & 255)::SMALLINT; END; $$
100            LANGUAGE plpgsql;
101            CREATE OR REPLACE FUNCTION get_equity(parent SMALLINT) RETURNS REAL AS
102            $$ BEGIN RETURN CASE WHEN get_street_abs(parent) = 3
103                THEN (parent & 255)::REAL / 100
104                ELSE (
105                    SELECT COALESCE(SUM(t.dx * r.equity) / NULLIF(SUM(t.dx), 0), 0)
106                    FROM ",
107            TRANSITIONS,
108            " t
109                    JOIN ",
110            ABSTRACTION,
111            " r ON t.next = r.abs
112             WHERE t.prev = parent) END; END; $$
113            LANGUAGE plpgsql;"
114        )
115    }
116    fn indices() -> &'static str {
117        const_format::concatcp!(
118            "CREATE INDEX IF NOT EXISTS idx_",
119            ABSTRACTION,
120            "_abs ON ",
121            ABSTRACTION,
122            " (abs);
123             CREATE INDEX IF NOT EXISTS idx_",
124            ABSTRACTION,
125            "_st  ON ",
126            ABSTRACTION,
127            " (street);
128             CREATE INDEX IF NOT EXISTS idx_",
129            ABSTRACTION,
130            "_eq  ON ",
131            ABSTRACTION,
132            " (equity);
133             CREATE INDEX IF NOT EXISTS idx_",
134            ABSTRACTION,
135            "_pop ON ",
136            ABSTRACTION,
137            " (population);"
138        )
139    }
140    fn copy() -> &'static str {
141        unimplemented!("Abstraction is derived, not loaded from files")
142    }
143    fn truncates() -> &'static str {
144        const_format::concatcp!("TRUNCATE TABLE ", ABSTRACTION, ";")
145    }
146    fn freeze() -> &'static str {
147        const_format::concatcp!(
148            "ALTER TABLE ",
149            ABSTRACTION,
150            " SET (fillfactor = 100);
151            ALTER TABLE ",
152            ABSTRACTION,
153            " SET (autovacuum_enabled = false);"
154        )
155    }
156    fn columns() -> &'static [tokio_postgres::types::Type] {
157        unimplemented!("Abstraction is derived, not loaded from files")
158    }
159}
160
161impl Derive for Abstraction {
162    fn exhaust() -> Vec<Self> {
163        Street::all()
164            .iter()
165            .rev()
166            .copied()
167            .flat_map(Abstraction::all)
168            .collect()
169    }
170    fn inserts(&self) -> String {
171        let abs = i16::from(*self);
172        format!(
173            "INSERT INTO {} (abs, street, equity, population) VALUES ({}, get_street_abs({}::SMALLINT), get_equity({}::SMALLINT), get_population({}::SMALLINT));",
174            ABSTRACTION, abs, abs, abs, abs
175        )
176    }
177}