sql_cli/sql/functions/
particle_charges.rs

1use anyhow::Result;
2
3use super::{ArgCount, FunctionCategory, FunctionSignature, SqlFunction};
4use crate::data::datatable::DataValue;
5
6/// Electron charge (-e)
7pub struct ChargeElectronFunction;
8
9impl SqlFunction for ChargeElectronFunction {
10    fn signature(&self) -> FunctionSignature {
11        FunctionSignature {
12            name: "CHARGE_ELECTRON",
13            category: FunctionCategory::Constant,
14            arg_count: ArgCount::Fixed(0),
15            description: "Returns the electron charge in coulombs (-1.602176634 × 10^-19 C)",
16            returns: "FLOAT",
17            examples: vec![
18                "SELECT CHARGE_ELECTRON()",
19                "SELECT n_electrons * CHARGE_ELECTRON() AS total_charge",
20            ],
21        }
22    }
23
24    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
25        self.validate_args(args)?;
26        Ok(DataValue::Float(-1.602176634e-19)) // Negative charge
27    }
28}
29
30/// Proton charge (+e)
31pub struct ChargeProtonFunction;
32
33impl SqlFunction for ChargeProtonFunction {
34    fn signature(&self) -> FunctionSignature {
35        FunctionSignature {
36            name: "CHARGE_PROTON",
37            category: FunctionCategory::Constant,
38            arg_count: ArgCount::Fixed(0),
39            description: "Returns the proton charge in coulombs (+1.602176634 × 10^-19 C)",
40            returns: "FLOAT",
41            examples: vec![
42                "SELECT CHARGE_PROTON()",
43                "SELECT n_protons * CHARGE_PROTON() AS nuclear_charge",
44            ],
45        }
46    }
47
48    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
49        self.validate_args(args)?;
50        Ok(DataValue::Float(1.602176634e-19)) // Positive charge
51    }
52}
53
54/// Neutron charge (0)
55pub struct ChargeNeutronFunction;
56
57impl SqlFunction for ChargeNeutronFunction {
58    fn signature(&self) -> FunctionSignature {
59        FunctionSignature {
60            name: "CHARGE_NEUTRON",
61            category: FunctionCategory::Constant,
62            arg_count: ArgCount::Fixed(0),
63            description: "Returns the neutron charge in coulombs (0 C)",
64            returns: "FLOAT",
65            examples: vec![
66                "SELECT CHARGE_NEUTRON()",
67                "SELECT CHARGE_NEUTRON() + CHARGE_PROTON() AS net_nucleon_charge",
68            ],
69        }
70    }
71
72    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
73        self.validate_args(args)?;
74        Ok(DataValue::Float(0.0)) // Neutral (no charge)
75    }
76}
77
78/// Up quark charge (+2/3 e)
79pub struct ChargeUpQuarkFunction;
80
81impl SqlFunction for ChargeUpQuarkFunction {
82    fn signature(&self) -> FunctionSignature {
83        FunctionSignature {
84            name: "CHARGE_UP_QUARK",
85            category: FunctionCategory::Constant,
86            arg_count: ArgCount::Fixed(0),
87            description: "Returns the up quark charge in coulombs (+2/3 × 1.602176634 × 10^-19 C)",
88            returns: "FLOAT",
89            examples: vec![
90                "SELECT CHARGE_UP_QUARK()",
91                "SELECT 2 * CHARGE_UP_QUARK() + CHARGE_DOWN_QUARK() AS proton_charge",
92            ],
93        }
94    }
95
96    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
97        self.validate_args(args)?;
98        Ok(DataValue::Float(2.0 / 3.0 * 1.602176634e-19)) // +2/3 e
99    }
100}
101
102/// Down quark charge (-1/3 e)
103pub struct ChargeDownQuarkFunction;
104
105impl SqlFunction for ChargeDownQuarkFunction {
106    fn signature(&self) -> FunctionSignature {
107        FunctionSignature {
108            name: "CHARGE_DOWN_QUARK",
109            category: FunctionCategory::Constant,
110            arg_count: ArgCount::Fixed(0),
111            description:
112                "Returns the down quark charge in coulombs (-1/3 × 1.602176634 × 10^-19 C)",
113            returns: "FLOAT",
114            examples: vec![
115                "SELECT CHARGE_DOWN_QUARK()",
116                "SELECT CHARGE_UP_QUARK() + 2 * CHARGE_DOWN_QUARK() AS neutron_charge",
117            ],
118        }
119    }
120
121    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
122        self.validate_args(args)?;
123        Ok(DataValue::Float(-1.0 / 3.0 * 1.602176634e-19)) // -1/3 e
124    }
125}
126
127/// Positron charge (+e) - antiparticle of electron
128pub struct ChargePositronFunction;
129
130impl SqlFunction for ChargePositronFunction {
131    fn signature(&self) -> FunctionSignature {
132        FunctionSignature {
133            name: "CHARGE_POSITRON",
134            category: FunctionCategory::Constant,
135            arg_count: ArgCount::Fixed(0),
136            description: "Returns the positron charge in coulombs (+1.602176634 × 10^-19 C)",
137            returns: "FLOAT",
138            examples: vec![
139                "SELECT CHARGE_POSITRON()",
140                "SELECT CHARGE_ELECTRON() + CHARGE_POSITRON() AS annihilation_charge",
141            ],
142        }
143    }
144
145    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
146        self.validate_args(args)?;
147        Ok(DataValue::Float(1.602176634e-19)) // Positive charge (antielectron)
148    }
149}
150
151/// Muon charge (-e)
152pub struct ChargeMuonFunction;
153
154impl SqlFunction for ChargeMuonFunction {
155    fn signature(&self) -> FunctionSignature {
156        FunctionSignature {
157            name: "CHARGE_MUON",
158            category: FunctionCategory::Constant,
159            arg_count: ArgCount::Fixed(0),
160            description: "Returns the muon charge in coulombs (-1.602176634 × 10^-19 C)",
161            returns: "FLOAT",
162            examples: vec![
163                "SELECT CHARGE_MUON()",
164                "SELECT CHARGE_MUON() / CHARGE_ELECTRON() AS charge_ratio",
165            ],
166        }
167    }
168
169    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
170        self.validate_args(args)?;
171        Ok(DataValue::Float(-1.602176634e-19)) // Same charge as electron
172    }
173}
174
175/// Tau charge (-e)
176pub struct ChargeTauFunction;
177
178impl SqlFunction for ChargeTauFunction {
179    fn signature(&self) -> FunctionSignature {
180        FunctionSignature {
181            name: "CHARGE_TAU",
182            category: FunctionCategory::Constant,
183            arg_count: ArgCount::Fixed(0),
184            description: "Returns the tau lepton charge in coulombs (-1.602176634 × 10^-19 C)",
185            returns: "FLOAT",
186            examples: vec![
187                "SELECT CHARGE_TAU()",
188                "SELECT CHARGE_TAU() = CHARGE_ELECTRON() AS same_charge",
189            ],
190        }
191    }
192
193    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
194        self.validate_args(args)?;
195        Ok(DataValue::Float(-1.602176634e-19)) // Same charge as electron
196    }
197}
198
199#[cfg(test)]
200mod tests {
201    use super::*;
202
203    #[test]
204    fn test_electron_charge() {
205        let func = ChargeElectronFunction;
206        let result = func.evaluate(&[]).unwrap();
207        match result {
208            DataValue::Float(val) => {
209                assert_eq!(val, -1.602176634e-19);
210                assert!(val < 0.0, "Electron charge should be negative");
211            }
212            _ => panic!("Expected Float"),
213        }
214    }
215
216    #[test]
217    fn test_proton_charge() {
218        let func = ChargeProtonFunction;
219        let result = func.evaluate(&[]).unwrap();
220        match result {
221            DataValue::Float(val) => {
222                assert_eq!(val, 1.602176634e-19);
223                assert!(val > 0.0, "Proton charge should be positive");
224            }
225            _ => panic!("Expected Float"),
226        }
227    }
228
229    #[test]
230    fn test_neutron_charge() {
231        let func = ChargeNeutronFunction;
232        let result = func.evaluate(&[]).unwrap();
233        match result {
234            DataValue::Float(val) => {
235                assert_eq!(val, 0.0);
236                assert_eq!(val, 0.0, "Neutron charge should be zero");
237            }
238            _ => panic!("Expected Float"),
239        }
240    }
241
242    #[test]
243    fn test_charge_conservation() {
244        let electron = ChargeElectronFunction.evaluate(&[]).unwrap();
245        let proton = ChargeProtonFunction.evaluate(&[]).unwrap();
246
247        if let (DataValue::Float(e), DataValue::Float(p)) = (electron, proton) {
248            assert_eq!(e + p, 0.0, "Electron and proton charges should cancel");
249        } else {
250            panic!("Expected Float values");
251        }
252    }
253
254    #[test]
255    fn test_quark_charges() {
256        let up = ChargeUpQuarkFunction.evaluate(&[]).unwrap();
257        let down = ChargeDownQuarkFunction.evaluate(&[]).unwrap();
258
259        if let (DataValue::Float(u), DataValue::Float(d)) = (up, down) {
260            // Proton = 2 up + 1 down
261            let proton_charge = 2.0 * u + d;
262            assert!(
263                (proton_charge - 1.602176634e-19).abs() < 1e-30,
264                "Proton charge from quarks"
265            );
266
267            // Neutron = 1 up + 2 down
268            let neutron_charge = u + 2.0 * d;
269            assert!(neutron_charge.abs() < 1e-30, "Neutron charge from quarks");
270        } else {
271            panic!("Expected Float values");
272        }
273    }
274}