&args,
cli_cmd.arg_param,
&cli_cmd.fixed_param,
- &cli_cmd.info.parameters,
+ cli_cmd.info.parameters,
) {
Ok((p, r)) => (p, r),
Err(err) => {
use super::*;
+use crate::api::router::ParameterSchema;
use crate::api::schema::*;
fn record_done_argument(
done: &mut HashMap<String, String>,
- parameters: &ObjectSchema,
+ parameters: ParameterSchema,
key: &str,
value: &str,
) {
let mut errors = ParameterError::new(); // we simply ignore any parsing errors here
let (data, _remaining) = getopts::parse_argument_list(
&args[0..args.len() - 1],
- &cli_cmd.info.parameters,
+ cli_cmd.info.parameters,
&mut errors,
);
for (key, value) in &data {
- record_done_argument(done, &cli_cmd.info.parameters, key, value);
+ record_done_argument(done, cli_cmd.info.parameters, key, value);
}
}
}
let mut completions = Vec::new();
- for (name, _optional, _schema) in cli_cmd.info.parameters.properties {
+ for (name, _optional, _schema) in cli_cmd.info.parameters.properties() {
if done.contains_key(*name) {
continue;
}
CommandLineInterface::Simple(cli_cmd) => {
let mut done: HashMap<String, String> = HashMap::new();
cli_cmd.fixed_param.iter().for_each(|(key, value)| {
- record_done_argument(&mut done, &cli_cmd.info.parameters, &key, &value);
+ record_done_argument(&mut done, cli_cmd.info.parameters, &key, &value);
});
get_simple_completion(cli_cmd, &mut done, &cli_cmd.arg_param, args)
}
let mut options = String::new();
- for (prop, optional, param_schema) in schema.properties {
+ for (prop, optional, param_schema) in schema.properties() {
if done_hash.contains(prop) {
continue;
}
DocumentationFormat::Long => format!("{}{}{}{}\n", indent, prefix, args, option_indicator),
DocumentationFormat::Full => format!(
"{}{}{}{}\n\n{}\n\n",
- indent, prefix, args, option_indicator, schema.description
+ indent,
+ prefix,
+ args,
+ option_indicator,
+ schema.description()
),
DocumentationFormat::ReST => format!(
"``{}{}{}``\n\n{}\n\n",
- prefix, args, option_indicator, schema.description
+ prefix,
+ args,
+ option_indicator,
+ schema.description()
),
};
use anyhow::*;
use serde_json::Value;
+use crate::api::router::ParameterSchema;
use crate::api::schema::*;
#[derive(Debug)]
/// Returns parsed data and the remaining arguments as two separate array
pub(crate) fn parse_argument_list<T: AsRef<str>>(
args: &[T],
- schema: &ObjectSchema,
+ schema: ParameterSchema,
errors: &mut ParameterError,
) -> (Vec<(String, String)>, Vec<String>) {
let mut data: Vec<(String, String)> = vec![];
args: &[T],
arg_param: &[&str],
fixed_param: &HashMap<&'static str, String>,
- schema: &ObjectSchema,
+ schema: ParameterSchema,
) -> Result<(Value, Vec<String>), ParameterError> {
let mut errors = ParameterError::new();
variants.push((vec!["--enable", "false"], false));
for (args, expect) in variants {
- let res = parse_arguments(&args, &vec![], &HashMap::new(), &PARAMETERS);
+ let res = parse_arguments(
+ &args,
+ &vec![],
+ &HashMap::new(),
+ ParameterSchema::from(&PARAMETERS),
+ );
assert!(res.is_ok());
if let Ok((options, remaining)) = res {
assert!(options["enable"] == expect);
);
let args = vec!["-enable", "local"];
- let res = parse_arguments(&args, &vec!["storage"], &HashMap::new(), &PARAMETERS);
+ let res = parse_arguments(
+ &args,
+ &vec!["storage"],
+ &HashMap::new(),
+ ParameterSchema::from(&PARAMETERS),
+ );
assert!(res.is_ok());
if let Ok((options, remaining)) = res {
assert!(options["enable"] == true);
match def {
None => None,
Some(api_method) => {
- let param_descr = dump_api_parameters(api_method.parameters);
+ let param_descr = dump_api_parameters(&api_method.parameters);
let return_descr = dump_api_return_schema(&api_method.returns);
use percent_encoding::percent_decode_str;
use serde_json::Value;
-use crate::api::schema::{self, ObjectSchema, Schema};
+use crate::api::schema::{self, AllOfSchema, ObjectSchema, Schema};
use crate::api::RpcEnvironment;
use super::Permission;
/// &ObjectSchema::new("Hello World Example", &[])
/// );
/// ```
-pub type ApiHandlerFn = &'static (dyn Fn(Value, &ApiMethod, &mut dyn RpcEnvironment) -> Result<Value, Error>
- + Send
- + Sync
- + 'static);
+pub type ApiHandlerFn =
+ &'static (dyn Fn(Value, &ApiMethod, &mut dyn RpcEnvironment) -> Result<Value, Error>
+ + Send
+ + Sync
+ + 'static);
/// Asynchronous API handlers
///
/// &ObjectSchema::new("Hello World Example (async)", &[])
/// );
/// ```
-pub type ApiAsyncHandlerFn = &'static (dyn for<'a> Fn(Value, &'static ApiMethod, &'a mut dyn RpcEnvironment) -> ApiFuture<'a>
+pub type ApiAsyncHandlerFn = &'static (dyn for<'a> Fn(
+ Value,
+ &'static ApiMethod,
+ &'a mut dyn RpcEnvironment,
+) -> ApiFuture<'a>
+ Send
+ Sync);
}
}
+/// Parameters are objects, but we have two types of object schemas, the regular one and the
+/// `AllOf` schema.
+#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "test-harness", derive(Eq, PartialEq))]
+pub enum ParameterSchema {
+ Object(&'static ObjectSchema),
+ AllOf(&'static AllOfSchema),
+}
+
+impl schema::ObjectSchemaType for ParameterSchema {
+ type PropertyIter = Box<dyn Iterator<Item = &'static schema::SchemaPropertyEntry>>;
+
+ fn description(&self) -> &'static str {
+ match self {
+ ParameterSchema::Object(o) => o.description(),
+ ParameterSchema::AllOf(o) => o.description(),
+ }
+ }
+
+ fn lookup(&self, key: &str) -> Option<(bool, &Schema)> {
+ match self {
+ ParameterSchema::Object(o) => o.lookup(key),
+ ParameterSchema::AllOf(o) => o.lookup(key),
+ }
+ }
+
+ fn properties(&self) -> Self::PropertyIter {
+ match self {
+ ParameterSchema::Object(o) => Box::new(o.properties()),
+ ParameterSchema::AllOf(o) => Box::new(o.properties()),
+ }
+ }
+
+ fn additional_properties(&self) -> bool {
+ match self {
+ ParameterSchema::Object(o) => o.additional_properties(),
+ ParameterSchema::AllOf(o) => o.additional_properties(),
+ }
+ }
+}
+
+impl From<&'static ObjectSchema> for ParameterSchema {
+ fn from(schema: &'static ObjectSchema) -> Self {
+ ParameterSchema::Object(schema)
+ }
+}
+
+impl From<&'static AllOfSchema> for ParameterSchema {
+ fn from(schema: &'static AllOfSchema) -> Self {
+ ParameterSchema::AllOf(schema)
+ }
+}
+
/// This struct defines a synchronous API call which returns the result as json `Value`
#[cfg_attr(feature = "test-harness", derive(Eq, PartialEq))]
pub struct ApiMethod {
/// should do a tzset afterwards
pub reload_timezone: bool,
/// Parameter type Schema
- pub parameters: &'static schema::ObjectSchema,
+ pub parameters: ParameterSchema,
/// Return type Schema
pub returns: ReturnType,
/// Handler function
}
impl ApiMethod {
- pub const fn new(handler: &'static ApiHandler, parameters: &'static ObjectSchema) -> Self {
+ pub const fn new_full(handler: &'static ApiHandler, parameters: ParameterSchema) -> Self {
Self {
parameters,
handler,
}
}
+ pub const fn new(handler: &'static ApiHandler, parameters: &'static ObjectSchema) -> Self {
+ Self::new_full(handler, ParameterSchema::Object(parameters))
+ }
+
pub const fn new_dummy(parameters: &'static ObjectSchema) -> Self {
Self {
- parameters,
+ parameters: ParameterSchema::Object(parameters),
handler: &DUMMY_HANDLER,
returns: ReturnType::new(false, &NULL_SCHEMA),
protected: false,
use serde_json::{json, Value};
use url::form_urlencoded;
+use super::router::ParameterSchema;
use crate::api::const_regex::ConstRegexPattern;
/// Error type for schema validation
}
/// Parse a complex property string (`ApiStringFormat::PropertyString`)
-pub fn parse_property_string(value_str: &str, schema: &Schema) -> Result<Value, Error> {
+pub fn parse_property_string(value_str: &str, schema: &'static Schema) -> Result<Value, Error> {
match schema {
Schema::Object(object_schema) => {
let mut param_list: Vec<(String, String)> = vec![];
}
}
- parse_parameter_strings(¶m_list, &object_schema, true).map_err(Error::from)
+ parse_parameter_strings(¶m_list, object_schema, true).map_err(Error::from)
}
Schema::Array(array_schema) => {
let mut array: Vec<Value> = vec![];
///
/// - `test_required`: is set, checks if all required properties are
/// present.
-pub fn parse_parameter_strings(
+pub fn parse_parameter_strings<T: Into<ParameterSchema>>(
data: &[(String, String)],
- schema: &ObjectSchema,
+ schema: T,
+ test_required: bool,
+) -> Result<Value, ParameterError> {
+ do_parse_parameter_strings(data, schema.into(), test_required)
+}
+
+fn do_parse_parameter_strings(
+ data: &[(String, String)],
+ schema: ParameterSchema,
test_required: bool,
) -> Result<Value, ParameterError> {
let mut params = json!({});
let mut errors = ParameterError::new();
- let additional_properties = schema.additional_properties;
+ let additional_properties = schema.additional_properties();
for (key, value) in data {
if let Some((_optional, prop_schema)) = schema.lookup(&key) {
}
if test_required && errors.is_empty() {
- for (name, optional, _prop_schema) in schema.properties {
+ for (name, optional, _prop_schema) in schema.properties() {
if !(*optional) && params[name] == Value::Null {
errors.push(format_err!(
"parameter '{}': parameter is missing and it is not optional.",
/// Parse a `form_urlencoded` query string and verify with object schema
/// - `test_required`: is set, checks if all required properties are
/// present.
-pub fn parse_query_string(
+pub fn parse_query_string<T: Into<ParameterSchema>>(
query: &str,
- schema: &ObjectSchema,
+ schema: T,
test_required: bool,
) -> Result<Value, ParameterError> {
let param_list: Vec<(String, String)> = form_urlencoded::parse(query.as_bytes())
.into_owned()
.collect();
- parse_parameter_strings(¶m_list, schema, test_required)
+ parse_parameter_strings(¶m_list, schema.into(), test_required)
}
/// Verify JSON value with `schema`.