dm_database_sqllog2db/pipeline/
output.rs1pub const FIELD_NAMES: &[&str] = &[
3 "ts", "ep", "sess_id", "thrd_id", "username", "trx_id", "statement", "appname", "client_ip", "tag", "sql", "exec_time_ms", "row_count", "exec_id", "normalized_sql", ];
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct FieldMask(pub u16);
23
24impl FieldMask {
25 pub const ALL: Self = Self(0x7FFF);
27
28 pub fn from_names(names: &[String]) -> std::result::Result<Self, String> {
34 let mut mask = 0u16;
35 for name in names {
36 match FIELD_NAMES.iter().position(|&n| n == name.as_str()) {
37 Some(idx) => mask |= 1u16 << idx,
38 None => return Err(format!("unknown field: '{name}'")),
39 }
40 }
41 Ok(Self(mask))
42 }
43
44 #[inline]
46 #[must_use]
47 pub(crate) fn is_active(self, idx: usize) -> bool {
48 idx < 15 && (self.0 >> idx) & 1 == 1
49 }
50
51 #[inline]
53 #[must_use]
54 pub fn includes_normalized_sql(self) -> bool {
55 self.is_active(14)
56 }
57}
58
59impl Default for FieldMask {
60 fn default() -> Self {
61 Self::ALL
62 }
63}
64
65use serde::Deserialize;
66
67#[derive(Debug, Deserialize, Clone, Default)]
69pub struct OutputConfig {
70 #[serde(default)]
72 pub fields: Option<Vec<String>>,
73}
74
75impl OutputConfig {
76 #[must_use]
78 pub fn field_mask(&self) -> FieldMask {
79 match &self.fields {
80 None => FieldMask::ALL,
81 Some(names) if names.is_empty() => FieldMask::ALL,
82 Some(names) => FieldMask::from_names(names).unwrap_or(FieldMask::ALL),
83 }
84 }
85
86 #[must_use]
88 pub fn ordered_field_indices(&self) -> Vec<usize> {
89 match &self.fields {
90 None => (0..FIELD_NAMES.len()).collect(),
91 Some(names) if names.is_empty() => (0..FIELD_NAMES.len()).collect(),
92 Some(names) => names
93 .iter()
94 .filter_map(|name| FIELD_NAMES.iter().position(|&n| n == name.as_str()))
95 .collect(),
96 }
97 }
98}