diff --git a/src/api/schema.rs b/src/api/schema.rs index 7e2ebc3c..ea4b9292 100644 --- a/src/api/schema.rs +++ b/src/api/schema.rs @@ -172,6 +172,7 @@ pub struct ObjectSchema { pub description: &'static str, pub additional_properties: bool, pub properties: HashMap<&'static str, (bool, Arc)>, + pub default_key: Option<&'static str>, } impl ObjectSchema { @@ -182,6 +183,7 @@ impl ObjectSchema { description: description, additional_properties: false, properties: properties, + default_key: None, } } @@ -190,6 +192,11 @@ impl ObjectSchema { self } + pub fn default_key(mut self, key: &'static str) -> Self { + self.default_key = Some(key); + self + } + pub fn required>>(mut self, name: &'static str, schema: S) -> Self { self.properties.insert(name, (false, schema.into())); self @@ -253,6 +260,12 @@ impl From for Schema { } } +impl From for Arc { + fn from(object_schema: ObjectSchema) -> Self { + Arc::new(Schema::Object(object_schema)) + } +} + impl From for Schema { fn from(array_schema: ArraySchema) -> Self { Schema::Array(array_schema) @@ -299,6 +312,43 @@ pub fn parse_boolean(value_str: &str) -> Result { } } +fn parse_property_string(value_str: &str, schema: &Schema) -> Result { + + println!("Parse property string: {}", value_str); + + let mut param_list: Vec<(String, String)> = vec![]; + + match schema { + Schema::Object(object_schema) => { + for key_val in value_str.split(',').filter(|s| !s.is_empty()) { + println!("KEYVAL: {}", key_val); + let kv: Vec<&str> = key_val.splitn(2, '=').collect(); + println!("VEC: {:?}", kv); + if kv.len() == 2 { + param_list.push((kv[0].into(), kv[1].into())); + } else { + if let Some(key) = object_schema.default_key { + param_list.push((key.into(), kv[0].into())); + } else { + bail!("Value without key, but schema does not define a default key."); + } + } + } + + return parse_parameter_strings(¶m_list, &object_schema, true) + .map_err(Error::from); + + } + Schema::Array(array_schema) => { + bail!("implement me"); + } + _ => { + bail!("Got unexpetec schema type.") + } + } + +} + fn parse_simple_value(value_str: &str, schema: &Schema) -> Result { let value = match schema { @@ -354,8 +404,8 @@ fn parse_simple_value(value_str: &str, schema: &Schema) -> Result bail!("value is not defined in the enumeration."); } } - ApiStringFormat::Complex(ref _subschema) => { - bail!("implement me!"); + ApiStringFormat::Complex(ref subschema) => { + parse_property_string(&res, subschema)?; } ApiStringFormat::VerifyFn(verify_fn) => { verify_fn(&res)?; @@ -464,7 +514,8 @@ fn test_schema1() { let map = HashMap::new(); map - } + }, + default_key: None, }); println!("TEST Schema: {:?}", schema); @@ -661,3 +712,41 @@ fn test_verify_function() { let res = parse_query_string("p1=test", &schema, true); assert!(res.is_ok()); } + +#[test] +fn test_verify_complex() { + + let nic_models = Arc::new(ApiStringFormat::Enum( + vec!["e1000".into(), "virtio".into()])); + + let param_schema: Arc = ObjectSchema::new("Properties.") + .default_key("model") + .required("model", StringSchema::new("Ethernet device Model.") + .format(nic_models)) + .optional("enable", BooleanSchema::new("Enable device.")) + .into(); + + let schema = ObjectSchema::new("Parameters.") + .required( + "net0", StringSchema::new("First Network device.") + .format(ApiStringFormat::Complex(param_schema).into()) + ); + + let res = parse_query_string("", &schema, true); + assert!(res.is_err()); + + let res = parse_query_string("test=abc", &schema, true); + assert!(res.is_err()); + + let res = parse_query_string("net0=model=abc", &schema, true); + assert!(res.is_err()); + + let res = parse_query_string("net0=model=virtio", &schema, true); + assert!(res.is_ok()); + + let res = parse_query_string("net0=model=virtio,enable=1", &schema, true); + assert!(res.is_ok()); + + let res = parse_query_string("net0=virtio,enable=no", &schema, true); + assert!(res.is_ok()); +}