cratestack_core/schema/
composite_key.rs1use super::field_list::{FieldListSpec, parse_field_list};
9
10const SPEC: FieldListSpec = FieldListSpec {
11 prefix: "@@id(",
12 label: "composite id attribute",
13 example: "@@id([field1, field2])",
14};
15
16pub fn parse_composite_id_attribute(raw: &str) -> Result<Vec<String>, String> {
20 let fields = parse_field_list(raw, &SPEC)?;
21 if fields.len() < 2 {
22 return Err(format!(
23 "composite id attribute `{raw}` must list at least two fields; use a single-field `@id` instead"
24 ));
25 }
26 Ok(fields)
27}
28
29#[cfg(test)]
30mod tests {
31 use super::parse_composite_id_attribute;
32
33 #[test]
34 fn parses_two_fields() {
35 let fields = parse_composite_id_attribute("@@id([accountId, subject])").unwrap();
36 assert_eq!(fields, vec!["accountId".to_string(), "subject".to_string()]);
37 }
38
39 #[test]
40 fn rejects_missing_brackets() {
41 let error = parse_composite_id_attribute("@@id(accountId, subject)").unwrap_err();
42 assert!(error.contains("must list fields as"));
43 }
44
45 #[test]
46 fn rejects_single_field() {
47 let error = parse_composite_id_attribute("@@id([accountId])").unwrap_err();
48 assert!(error.contains("at least two fields"));
49 }
50
51 #[test]
52 fn rejects_duplicate_field() {
53 let error = parse_composite_id_attribute("@@id([accountId, accountId])").unwrap_err();
54 assert!(error.contains("more than once"));
55 }
56
57 #[test]
58 fn rejects_invalid_identifier() {
59 let error = parse_composite_id_attribute("@@id([account-id, subject])").unwrap_err();
60 assert!(error.contains("invalid field name"));
61 }
62}