fraiseql_core/runtime/
jsonb_strategy.rs1use serde::Deserialize;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9#[non_exhaustive]
10pub enum JsonbStrategy {
11 #[default]
13 Project,
14 Stream,
16}
17
18impl std::str::FromStr for JsonbStrategy {
19 type Err = String;
20
21 fn from_str(s: &str) -> Result<Self, Self::Err> {
22 match s.to_lowercase().as_str() {
23 "project" => Ok(JsonbStrategy::Project),
24 "stream" => Ok(JsonbStrategy::Stream),
25 other => {
26 Err(format!("Invalid JSONB strategy '{}', must be 'project' or 'stream'", other))
27 },
28 }
29 }
30}
31
32impl<'de> Deserialize<'de> for JsonbStrategy {
33 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
34 where
35 D: serde::Deserializer<'de>,
36 {
37 let s = String::deserialize(deserializer)?;
38 std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom)
39 }
40}
41
42#[derive(Debug, Clone)]
44pub struct JsonbOptimizationOptions {
45 pub default_strategy: JsonbStrategy,
47
48 pub auto_threshold_percent: u32,
50}
51
52impl Default for JsonbOptimizationOptions {
53 fn default() -> Self {
54 Self {
55 default_strategy: JsonbStrategy::Project,
56 auto_threshold_percent: 80,
57 }
58 }
59}
60
61impl JsonbOptimizationOptions {
62 #[must_use]
64 pub fn choose_strategy(&self, requested_fields: usize, total_fields: usize) -> JsonbStrategy {
65 if total_fields == 0 {
66 return self.default_strategy;
67 }
68
69 #[allow(clippy::cast_precision_loss)]
70 let percent = (requested_fields as f64 / total_fields as f64) * 100.0;
72
73 if percent >= f64::from(self.auto_threshold_percent) {
74 JsonbStrategy::Stream
75 } else {
76 self.default_strategy
77 }
78 }
79}