1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
use crate::providers::QuerySchema;
#[cfg(feature = "fp-bindgen")]
use fp_bindgen::prelude::Serializable;
use serde::{Deserialize, Serialize};
/// Defines an array of composite fields.
///
/// This is commonly used for arbitrarily long list of (key, value) pairs,
/// or lists of (key, operator, value) filters.
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq)]
#[cfg_attr(
feature = "fp-bindgen",
derive(Serializable),
fp(rust_module = "fiberplane_models::providers")
)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
pub struct ArrayField {
/// Suggested label to display along the form field.
pub label: String,
/// Name of the field as it will be included in the encoded query or config
/// object.
pub name: String,
/// The minimum number of entries the array must have to be valid.
///
/// Leaving the minimum_length to 0 makes the whole field optional.
pub minimum_length: u32,
/// The maximum number of entries the array can have and still be valid.
///
/// It is None when there is no maximum number
#[serde(default, skip_serializing_if = "Option::is_none")]
pub maximum_length: Option<u32>,
/// The schema of the elements inside a row of the array.
///
/// ### Accessing row fields
///
/// The name of each QueryField inside the element_schema can be used as
/// an indexing key for a field. That means that if `element_schema` contains
/// a [TextField](crate::providers::TextField) with the name `parameter_name`,
/// then you will be able to access the value of that field using
/// `ArrayField::get(i)::get("parameter_name")` for the i-th element.
///
/// ### Serialization
///
/// For example if an array field has this `element_schema`:
/// ```rust,no_run
/// # use fiberplane_models::providers::{ArrayField, TextField, SelectField, IntegerField};
/// ArrayField::new()
/// .with_name("table")
/// .with_label("example".to_string())
/// .with_element_schema(vec![
/// TextField::new().with_name("key").into(),
/// SelectField::new().with_name("operator").with_options([
/// "<".into(),
/// ">".into(),
/// "<=".into(),
/// ">=".into(),
/// "==".into()
/// ]).into(),
/// IntegerField::new().with_name("value").into(),
/// ]);
/// ```
///
/// Then the URL-encoded serialization for the fields is expected to use
/// the bracketed-notation. This means you _can_ encode all the
/// keys in the array in any order you want. It can look like this
/// (line breaks are only kept for legibility):
/// ```txt
/// "table[0][key]=less+than&
/// table[2][operator]=%3E&
/// table[0][operator]=%3C&
/// table[2][key]=greater+than&
/// table[2][value]=10&
/// table[0][value]=12"
/// ```
///
/// or you can do the "logic" ordering too:
/// ```txt
/// "table[0][key]=less+than&
/// table[0][operator]=%3C&
/// table[0][value]=12&
/// table[1][key]=greater+than&
/// table[1][operator]=%3E&
/// table[1][value]=10"
/// ```
///
/// Note that we are allowed to skip indices.
/// Any of those 2 examples above will
/// be read as:
/// ```rust,no_run
/// # #[derive(Debug, PartialEq)]
/// # struct Row { key: String, operator: String, value: u32 }
/// # let table: Vec<Row> = vec![];
/// assert_eq!(table, vec![
/// Row {
/// key: "less than".to_string(),
/// operator: "<".to_string(),
/// value: 12,
/// },
/// Row {
/// key: "greater than".to_string(),
/// operator: ">".to_string(),
/// value: 10,
/// },
/// ]);
/// ```
///
/// ### Required row fields
///
/// Any field that is marked as `required` inside `element_schema` makes it
/// mandatory to create a valid row to the Array Field.
pub element_schema: QuerySchema,
}
impl ArrayField {
/// Creates a new array field with all default values.
pub fn new() -> Self {
Default::default()
}
pub fn with_label(self, label: impl Into<String>) -> Self {
Self {
label: label.into(),
..self
}
}
pub fn with_element_schema(self, schema: QuerySchema) -> Self {
Self {
element_schema: schema,
..self
}
}
pub fn with_name(self, name: impl Into<String>) -> Self {
Self {
name: name.into(),
..self
}
}
pub fn with_minimum_length(self, minimum_length: u32) -> Self {
Self {
minimum_length,
..self
}
}
pub fn with_maximum_length(self, maximum_length: u32) -> Self {
Self {
maximum_length: Some(maximum_length),
..self
}
}
}