1use std::{
2 collections::BTreeMap,
3 path::{Path, PathBuf},
4};
5
6pub(crate) const DEFAULT_SQL_READONLY_ENABLED: bool = false;
7pub(crate) const DEFAULT_SQL_DDL_ENABLED: bool = false;
8pub(crate) const DEFAULT_SQL_FIXTURES_ENABLED: bool = false;
9pub(crate) const DEFAULT_SQL_INTROSPECTION_LOCAL_ENABLED: bool = true;
10pub(crate) const DEFAULT_SQL_INTROSPECTION_IC_ENABLED: bool = false;
11pub(crate) const DEFAULT_SQL_UPDATE_POLICY: Option<GeneratedSqlUpdatePolicy> = None;
12pub(crate) const DEFAULT_METRICS_ENABLED: bool = false;
13pub(crate) const DEFAULT_METRICS_EXTENDED_ENABLED: bool = false;
14pub(crate) const DEFAULT_SNAPSHOT_ENABLED: bool = false;
15pub(crate) const DEFAULT_SCHEMA_ENABLED: bool = false;
16
17#[derive(Clone, Debug, Default, Eq, PartialEq)]
19pub struct ResolvedIcydbConfig {
20 config_path: Option<PathBuf>,
21 config: GeneratedIcydbConfig,
22}
23
24impl ResolvedIcydbConfig {
25 #[must_use]
27 pub fn config_path(&self) -> Option<&Path> {
28 self.config_path.as_deref()
29 }
30
31 #[must_use]
33 pub const fn config(&self) -> &GeneratedIcydbConfig {
34 &self.config
35 }
36
37 pub(crate) const fn new(config_path: Option<PathBuf>, config: GeneratedIcydbConfig) -> Self {
38 Self {
39 config_path,
40 config,
41 }
42 }
43}
44
45#[derive(Clone, Debug, Default, Eq, PartialEq)]
47pub struct GeneratedIcydbConfig {
48 canisters: BTreeMap<String, GeneratedCanisterConfig>,
49 build_target: GeneratedBuildTarget,
50}
51
52impl GeneratedIcydbConfig {
53 #[must_use]
55 pub const fn canisters(&self) -> &BTreeMap<String, GeneratedCanisterConfig> {
56 &self.canisters
57 }
58
59 #[must_use]
61 pub const fn build_target(&self) -> GeneratedBuildTarget {
62 self.build_target
63 }
64
65 #[must_use]
67 pub fn canister_sql_readonly_enabled(&self, canister_name: &str) -> bool {
68 self.canister_enabled(
69 canister_name,
70 DEFAULT_SQL_READONLY_ENABLED,
71 GeneratedCanisterConfig::sql_readonly,
72 )
73 }
74
75 #[must_use]
77 pub fn canister_sql_ddl_enabled(&self, canister_name: &str) -> bool {
78 self.canister_enabled(
79 canister_name,
80 DEFAULT_SQL_DDL_ENABLED,
81 GeneratedCanisterConfig::sql_ddl,
82 )
83 }
84
85 #[must_use]
87 pub fn canister_sql_fixtures_enabled(&self, canister_name: &str) -> bool {
88 self.canister_enabled(
89 canister_name,
90 DEFAULT_SQL_FIXTURES_ENABLED,
91 GeneratedCanisterConfig::sql_fixtures,
92 )
93 }
94
95 #[must_use]
97 pub fn canister_sql_introspection_enabled(&self, canister_name: &str) -> bool {
98 self.canister_sql_introspection_policy(canister_name)
99 .enabled_for(self.build_target)
100 }
101
102 #[must_use]
104 pub fn canister_sql_introspection_policy(
105 &self,
106 canister_name: &str,
107 ) -> GeneratedSqlIntrospectionPolicy {
108 self.canisters.get(canister_name).map_or_else(
109 GeneratedSqlIntrospectionPolicy::default,
110 GeneratedCanisterConfig::sql_introspection_policy,
111 )
112 }
113
114 #[must_use]
116 pub fn canister_sql_update_policy(
117 &self,
118 canister_name: &str,
119 ) -> Option<GeneratedSqlUpdatePolicy> {
120 self.canisters.get(canister_name).map_or(
121 DEFAULT_SQL_UPDATE_POLICY,
122 GeneratedCanisterConfig::sql_update_policy,
123 )
124 }
125
126 #[must_use]
128 pub fn canister_metrics_enabled(&self, canister_name: &str) -> bool {
129 self.canister_enabled(
130 canister_name,
131 DEFAULT_METRICS_ENABLED,
132 GeneratedCanisterConfig::metrics,
133 )
134 }
135
136 #[must_use]
138 pub fn canister_metrics_extended_enabled(&self, canister_name: &str) -> bool {
139 self.canister_enabled(
140 canister_name,
141 DEFAULT_METRICS_EXTENDED_ENABLED,
142 GeneratedCanisterConfig::metrics_extended,
143 )
144 }
145
146 #[must_use]
148 pub fn canister_snapshot_enabled(&self, canister_name: &str) -> bool {
149 self.canister_enabled(
150 canister_name,
151 DEFAULT_SNAPSHOT_ENABLED,
152 GeneratedCanisterConfig::snapshot,
153 )
154 }
155
156 #[must_use]
158 pub fn canister_schema_enabled(&self, canister_name: &str) -> bool {
159 self.canister_enabled(
160 canister_name,
161 DEFAULT_SCHEMA_ENABLED,
162 GeneratedCanisterConfig::schema,
163 )
164 }
165
166 pub(crate) const fn new(canisters: BTreeMap<String, GeneratedCanisterConfig>) -> Self {
167 Self {
168 canisters,
169 build_target: GeneratedBuildTarget::Unknown,
170 }
171 }
172
173 pub(crate) const fn with_build_target(mut self, build_target: GeneratedBuildTarget) -> Self {
174 self.build_target = build_target;
175
176 self
177 }
178
179 fn canister_enabled(
180 &self,
181 canister_name: &str,
182 default: bool,
183 is_enabled: impl FnOnce(&GeneratedCanisterConfig) -> bool,
184 ) -> bool {
185 self.canisters
186 .get(canister_name)
187 .map_or(default, is_enabled)
188 }
189}
190
191#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
193pub struct GeneratedCanisterConfig {
194 sql: GeneratedCanisterSqlConfig,
195 metrics: GeneratedCanisterMetricsConfig,
196 snapshot: bool,
197 schema: bool,
198}
199
200impl GeneratedCanisterConfig {
201 pub(crate) const fn new(
202 sql: GeneratedCanisterSqlConfig,
203 metrics: GeneratedCanisterMetricsConfig,
204 snapshot: bool,
205 schema: bool,
206 ) -> Self {
207 Self {
208 sql,
209 metrics,
210 snapshot,
211 schema,
212 }
213 }
214
215 #[must_use]
217 pub const fn sql_readonly(&self) -> bool {
218 self.sql.readonly
219 }
220
221 #[must_use]
223 pub const fn sql_ddl(&self) -> bool {
224 self.sql.ddl
225 }
226
227 #[must_use]
229 pub const fn sql_fixtures(&self) -> bool {
230 self.sql.fixtures
231 }
232
233 #[must_use]
235 pub const fn sql_introspection_policy(&self) -> GeneratedSqlIntrospectionPolicy {
236 self.sql.introspection_policy
237 }
238
239 #[must_use]
241 pub const fn sql_update_policy(&self) -> Option<GeneratedSqlUpdatePolicy> {
242 self.sql.update_policy
243 }
244
245 #[must_use]
247 pub const fn metrics(&self) -> bool {
248 self.metrics.enabled
249 }
250
251 #[must_use]
253 pub const fn metrics_extended(&self) -> bool {
254 self.metrics.extended
255 }
256
257 #[must_use]
259 pub const fn snapshot(&self) -> bool {
260 self.snapshot
261 }
262
263 #[must_use]
265 pub const fn schema(&self) -> bool {
266 self.schema
267 }
268}
269
270#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
272pub(crate) struct GeneratedCanisterSqlConfig {
273 readonly: bool,
274 ddl: bool,
275 fixtures: bool,
276 introspection_policy: GeneratedSqlIntrospectionPolicy,
277 update_policy: Option<GeneratedSqlUpdatePolicy>,
278}
279
280impl GeneratedCanisterSqlConfig {
281 pub(crate) const fn new(
282 readonly: bool,
283 ddl: bool,
284 fixtures: bool,
285 introspection_policy: GeneratedSqlIntrospectionPolicy,
286 update_policy: Option<GeneratedSqlUpdatePolicy>,
287 ) -> Self {
288 Self {
289 readonly,
290 ddl,
291 fixtures,
292 introspection_policy,
293 update_policy,
294 }
295 }
296}
297
298#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
300pub enum GeneratedBuildTarget {
301 Local,
303 Ic,
305 #[default]
307 Unknown,
308}
309
310impl GeneratedBuildTarget {
311 #[must_use]
313 pub fn from_env_value(value: &str) -> Self {
314 match value {
315 "local" => Self::Local,
316 "ic" => Self::Ic,
317 _ => Self::Unknown,
318 }
319 }
320
321 #[must_use]
323 pub const fn env_value(self) -> &'static str {
324 match self {
325 Self::Local => "local",
326 Self::Ic => "ic",
327 Self::Unknown => "unknown",
328 }
329 }
330}
331
332#[derive(Clone, Copy, Debug, Eq, PartialEq)]
334pub struct GeneratedSqlIntrospectionPolicy {
335 local: bool,
336 ic: bool,
337}
338
339impl GeneratedSqlIntrospectionPolicy {
340 #[must_use]
342 pub const fn new(local: bool, ic: bool) -> Self {
343 Self { local, ic }
344 }
345
346 #[must_use]
348 pub const fn local(self) -> bool {
349 self.local
350 }
351
352 #[must_use]
354 pub const fn ic(self) -> bool {
355 self.ic
356 }
357
358 #[must_use]
360 pub const fn enabled_for(self, build_target: GeneratedBuildTarget) -> bool {
361 match build_target {
362 GeneratedBuildTarget::Local => self.local,
363 GeneratedBuildTarget::Ic => self.ic,
364 GeneratedBuildTarget::Unknown => false,
365 }
366 }
367}
368
369impl Default for GeneratedSqlIntrospectionPolicy {
370 fn default() -> Self {
371 Self::new(
372 DEFAULT_SQL_INTROSPECTION_LOCAL_ENABLED,
373 DEFAULT_SQL_INTROSPECTION_IC_ENABLED,
374 )
375 }
376}
377
378#[derive(Clone, Copy, Debug, Eq, PartialEq)]
380pub enum GeneratedSqlUpdatePolicy {
381 PublicPrimaryKeyOnly,
383 PublicBoundedDeterministic,
385}
386
387#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
389pub(crate) struct GeneratedCanisterMetricsConfig {
390 enabled: bool,
391 extended: bool,
392}
393
394impl GeneratedCanisterMetricsConfig {
395 pub(crate) const fn new(enabled: bool, extended: bool) -> Self {
396 Self { enabled, extended }
397 }
398}