|
@@ -1,10 +1,12 @@
|
|
|
mod convert;
|
|
|
mod input;
|
|
|
mod output;
|
|
|
+mod property;
|
|
|
|
|
|
pub use convert::*;
|
|
|
pub use input::*;
|
|
|
pub use output::*;
|
|
|
+pub use property::*;
|
|
|
|
|
|
pub use crate::{permissions::EntityAccessLevel, *};
|
|
|
pub use codec::{Decode, Encode};
|
|
@@ -12,176 +14,9 @@ use core::ops::Deref;
|
|
|
#[cfg(feature = "std")]
|
|
|
pub use serde::{Deserialize, Serialize};
|
|
|
|
|
|
-/// Type representing max length of vector property type
|
|
|
-pub type VecMaxLength = u16;
|
|
|
-
|
|
|
-/// Type representing max length of text property type
|
|
|
-pub type TextMaxLength = u16;
|
|
|
-
|
|
|
-/// Type representing max length of text property type, that will be subsequently hashed
|
|
|
-pub type HashedTextMaxLength = Option<u16>;
|
|
|
-
|
|
|
-/// Type identificator for property id
|
|
|
-pub type PropertyId = u16;
|
|
|
-
|
|
|
/// Type identificator for schema id
|
|
|
pub type SchemaId = u16;
|
|
|
|
|
|
-/// Used to force property values to only reference entities, owned by the same controller
|
|
|
-pub type SameController = bool;
|
|
|
-
|
|
|
-/// Locking policy, representing `Property` locking status for both controller and maintainer
|
|
|
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
|
|
-#[derive(Encode, Default, Decode, Clone, Copy, PartialEq, Eq)]
|
|
|
-pub struct PropertyLockingPolicy {
|
|
|
- /// If property is locked from maintainer
|
|
|
- pub is_locked_from_maintainer: bool,
|
|
|
- /// If property is locked from controller
|
|
|
- pub is_locked_from_controller: bool,
|
|
|
-}
|
|
|
-
|
|
|
-/// Enum, used for `PropertyType` representation
|
|
|
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
|
|
-#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq)]
|
|
|
-pub enum Type<T: Trait> {
|
|
|
- Bool,
|
|
|
- Uint16,
|
|
|
- Uint32,
|
|
|
- Uint64,
|
|
|
- Int16,
|
|
|
- Int32,
|
|
|
- Int64,
|
|
|
- /// Max length of text item.
|
|
|
- Text(TextMaxLength),
|
|
|
- Hash(HashedTextMaxLength),
|
|
|
- /// Can reference only specific class id entities
|
|
|
- Reference(T::ClassId, SameController),
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Trait> Default for Type<T> {
|
|
|
- fn default() -> Self {
|
|
|
- Self::Bool
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Trait> Type<T> {
|
|
|
- /// Ensure `Type` specific `TextMaxLengthConstraint` or `HashedTextMaxLengthConstraint` satisfied
|
|
|
- pub fn ensure_property_type_size_is_valid(&self) -> Result<(), Error<T>> {
|
|
|
- if let Type::Text(text_max_len) = self {
|
|
|
- ensure!(
|
|
|
- *text_max_len <= T::TextMaxLengthConstraint::get(),
|
|
|
- Error::<T>::TextPropertyTooLong
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- if let Type::Hash(hashed_text_max_len) = self {
|
|
|
- ensure!(
|
|
|
- *hashed_text_max_len <= T::HashedTextMaxLengthConstraint::get(),
|
|
|
- Error::<T>::HashedTextPropertyTooLong
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/// Vector property type representation
|
|
|
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
|
|
-#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq)]
|
|
|
-pub struct VecPropertyType<T: Trait> {
|
|
|
- vec_type: Type<T>,
|
|
|
- /// Max length of vector, corresponding to a given type
|
|
|
- max_length: VecMaxLength,
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Trait> Default for VecPropertyType<T> {
|
|
|
- fn default() -> Self {
|
|
|
- Self {
|
|
|
- vec_type: Type::default(),
|
|
|
- max_length: 0,
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Trait> VecPropertyType<T> {
|
|
|
- /// Create new `VecPropertyType` from provided `type` and `max_length`
|
|
|
- pub fn new(vec_type: Type<T>, max_length: VecMaxLength) -> Self {
|
|
|
- Self {
|
|
|
- vec_type,
|
|
|
- max_length,
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure `Type` specific `TextMaxLengthConstraint` & `VecMaxLengthConstraint` satisfied
|
|
|
- fn ensure_property_type_size_is_valid(&self) -> Result<(), Error<T>> {
|
|
|
- // Ensure Type specific TextMaxLengthConstraint or HashedTextMaxLengthConstraint satisfied
|
|
|
- self.vec_type.ensure_property_type_size_is_valid()?;
|
|
|
-
|
|
|
- ensure!(
|
|
|
- self.max_length <= T::VecMaxLengthConstraint::get(),
|
|
|
- Error::<T>::VecPropertyTooLong
|
|
|
- );
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- fn get_vec_type(&self) -> &Type<T> {
|
|
|
- &self.vec_type
|
|
|
- }
|
|
|
-
|
|
|
- fn get_max_len(&self) -> VecMaxLength {
|
|
|
- self.max_length
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/// Enum, representing either `Type` or `VecPropertyType`
|
|
|
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
|
|
-#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq)]
|
|
|
-pub enum PropertyType<T: Trait> {
|
|
|
- Single(Type<T>),
|
|
|
- Vector(VecPropertyType<T>),
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Trait> Default for PropertyType<T> {
|
|
|
- fn default() -> Self {
|
|
|
- Self::Single(Type::default())
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Trait> PropertyType<T> {
|
|
|
- fn as_single_value_type(&self) -> Option<&Type<T>> {
|
|
|
- if let PropertyType::Single(single_value_property_type) = self {
|
|
|
- Some(single_value_property_type)
|
|
|
- } else {
|
|
|
- None
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- pub fn as_vec_type(&self) -> Option<&VecPropertyType<T>> {
|
|
|
- if let PropertyType::Vector(vec_value_property_type) = self {
|
|
|
- Some(vec_value_property_type)
|
|
|
- } else {
|
|
|
- None
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn get_inner_type(&self) -> &Type<T> {
|
|
|
- match self {
|
|
|
- PropertyType::Single(single_property_type) => single_property_type,
|
|
|
- PropertyType::Vector(vec_property_type) => vec_property_type.get_vec_type(),
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Retrives `same_controller` flag.
|
|
|
- /// Always returns false if `Type` is not a reference,
|
|
|
- pub fn same_controller_status(&self) -> SameController {
|
|
|
- if let Type::Reference(_, same_controller) = self.get_inner_type() {
|
|
|
- *same_controller
|
|
|
- } else {
|
|
|
- false
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/// A schema defines what properties describe an entity
|
|
|
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
|
|
#[derive(Encode, Decode, Clone, PartialEq, Eq)]
|
|
@@ -254,481 +89,3 @@ impl Schema {
|
|
|
self.is_active = is_active;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-/// `Property` representation, related to a given `Class`
|
|
|
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
|
|
|
-#[derive(Encode, Decode, Clone, PartialEq, Eq)]
|
|
|
-pub struct Property<T: Trait> {
|
|
|
- /// The type of `Property`
|
|
|
- pub property_type: PropertyType<T>,
|
|
|
- /// If property value can be skipped, when adding entity schema support
|
|
|
- pub required: bool,
|
|
|
- /// Used to enforce uniquness of a property across all entities that have this property
|
|
|
- pub unique: bool,
|
|
|
- /// Property name
|
|
|
- pub name: Vec<u8>,
|
|
|
- /// Property description
|
|
|
- pub description: Vec<u8>,
|
|
|
- /// Locking policy, representing `Property` locking status for both controller and maintainer
|
|
|
- pub locking_policy: PropertyLockingPolicy,
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Trait> Default for Property<T> {
|
|
|
- fn default() -> Self {
|
|
|
- Self {
|
|
|
- property_type: PropertyType::<T>::default(),
|
|
|
- required: false,
|
|
|
- unique: false,
|
|
|
- name: vec![],
|
|
|
- description: vec![],
|
|
|
- locking_policy: PropertyLockingPolicy::default(),
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Trait> core::fmt::Debug for Property<T> {
|
|
|
- fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
|
- write!(formatter, "Property {:?}", self)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Trait> Property<T> {
|
|
|
- /// Check if property is locked from actor with provided `EntityAccessLevel`
|
|
|
- pub fn is_locked_from(&self, access_level: EntityAccessLevel) -> bool {
|
|
|
- let is_locked_from_controller = self.locking_policy.is_locked_from_controller;
|
|
|
- let is_locked_from_maintainer = self.locking_policy.is_locked_from_maintainer;
|
|
|
- match access_level {
|
|
|
- EntityAccessLevel::EntityControllerAndMaintainer => {
|
|
|
- is_locked_from_controller && is_locked_from_maintainer
|
|
|
- }
|
|
|
- EntityAccessLevel::EntityController => is_locked_from_controller,
|
|
|
- EntityAccessLevel::EntityMaintainer => is_locked_from_maintainer,
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure `Property` is unlocked from `Actor` with given `EntityAccessLevel`
|
|
|
- pub fn ensure_unlocked_from(&self, access_level: EntityAccessLevel) -> Result<(), Error<T>> {
|
|
|
- ensure!(
|
|
|
- !self.is_locked_from(access_level),
|
|
|
- Error::<T>::ClassPropertyTypeLockedForGivenActor
|
|
|
- );
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- /// Validate new `InputPropertyValue` against the type of this `Property`
|
|
|
- /// and check any additional constraints
|
|
|
- pub fn ensure_property_value_to_update_is_valid(
|
|
|
- &self,
|
|
|
- value: &InputPropertyValue<T>,
|
|
|
- current_entity_controller: &EntityController<T>,
|
|
|
- ) -> Result<(), Error<T>> {
|
|
|
- // Ensure provided InputPropertyValue matches its Type
|
|
|
- self.ensure_property_value_matches_its_type(value)?;
|
|
|
-
|
|
|
- // Perform all required checks to ensure provided InputPropertyValue is valid, when current PropertyType is Reference
|
|
|
- self.ensure_property_value_is_valid_reference(value, current_entity_controller)?;
|
|
|
-
|
|
|
- // Ensure text property does not exceed its max length
|
|
|
- self.validate_max_len_if_text_property(value)?;
|
|
|
-
|
|
|
- // Ensure vector property does not exceed its max length
|
|
|
- self.validate_max_len_if_vec_property(value)?;
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure property vector length after value inserted is valid
|
|
|
- fn validate_property_vector_length_after_value_insert<V>(
|
|
|
- vec: &[V],
|
|
|
- max_len: VecMaxLength,
|
|
|
- ) -> Result<(), Error<T>> {
|
|
|
- ensure!(
|
|
|
- vec.len() < max_len as usize,
|
|
|
- Error::<T>::EntityPropertyValueVectorIsTooLong
|
|
|
- );
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure `SingleInputPropertyValue` type is equal to the `VecInputPropertyValue` type
|
|
|
- /// and check all constraints
|
|
|
- pub fn ensure_property_value_can_be_inserted_at_property_vector(
|
|
|
- &self,
|
|
|
- single_value: &InputValue<T>,
|
|
|
- vec_value: &VecStoredPropertyValue<T>,
|
|
|
- index_in_property_vec: VecMaxLength,
|
|
|
- current_entity_controller: &EntityController<T>,
|
|
|
- ) -> Result<(), Error<T>> {
|
|
|
- // Ensure, provided index_in_property_vec is valid index of VecInputValue
|
|
|
- vec_value.ensure_index_in_property_vector_is_valid(index_in_property_vec)?;
|
|
|
-
|
|
|
- let property_type_vec = self
|
|
|
- .property_type
|
|
|
- .as_vec_type()
|
|
|
- .ok_or(Error::<T>::PropertyValueTypeDoesNotMatchInternalVectorType)?;
|
|
|
-
|
|
|
- let max_vec_len = property_type_vec.get_max_len();
|
|
|
-
|
|
|
- match (
|
|
|
- single_value,
|
|
|
- vec_value.get_vec_value_ref(),
|
|
|
- property_type_vec.get_vec_type(),
|
|
|
- ) {
|
|
|
- // Single values
|
|
|
- (InputValue::Bool(_), VecStoredValue::Bool(vec), Type::Bool) => {
|
|
|
- Self::validate_property_vector_length_after_value_insert(vec, max_vec_len)
|
|
|
- }
|
|
|
- (InputValue::Uint16(_), VecStoredValue::Uint16(vec), Type::Uint16) => {
|
|
|
- Self::validate_property_vector_length_after_value_insert(vec, max_vec_len)
|
|
|
- }
|
|
|
- (InputValue::Uint32(_), VecStoredValue::Uint32(vec), Type::Uint32) => {
|
|
|
- Self::validate_property_vector_length_after_value_insert(vec, max_vec_len)
|
|
|
- }
|
|
|
- (InputValue::Uint64(_), VecStoredValue::Uint64(vec), Type::Uint64) => {
|
|
|
- Self::validate_property_vector_length_after_value_insert(vec, max_vec_len)
|
|
|
- }
|
|
|
- (InputValue::Int16(_), VecStoredValue::Int16(vec), Type::Int16) => {
|
|
|
- Self::validate_property_vector_length_after_value_insert(vec, max_vec_len)
|
|
|
- }
|
|
|
- (InputValue::Int32(_), VecStoredValue::Int32(vec), Type::Int32) => {
|
|
|
- Self::validate_property_vector_length_after_value_insert(vec, max_vec_len)
|
|
|
- }
|
|
|
- (InputValue::Int64(_), VecStoredValue::Int64(vec), Type::Int64) => {
|
|
|
- Self::validate_property_vector_length_after_value_insert(vec, max_vec_len)
|
|
|
- }
|
|
|
- (InputValue::Text(text_item), VecStoredValue::Text(vec), Type::Text(text_max_len)) => {
|
|
|
- Self::validate_max_len_of_text(text_item, *text_max_len)?;
|
|
|
- Self::validate_property_vector_length_after_value_insert(vec, max_vec_len)
|
|
|
- }
|
|
|
- (
|
|
|
- InputValue::TextToHash(text_item),
|
|
|
- VecStoredValue::Hash(vec),
|
|
|
- Type::Hash(text_max_len),
|
|
|
- ) => {
|
|
|
- if let Some(text_max_len) = text_max_len {
|
|
|
- Self::validate_max_len_of_text_to_be_hashed(text_item, *text_max_len)?;
|
|
|
- }
|
|
|
- Self::validate_property_vector_length_after_value_insert(vec, max_vec_len)
|
|
|
- }
|
|
|
- (
|
|
|
- InputValue::Reference(entity_id),
|
|
|
- VecStoredValue::Reference(vec),
|
|
|
- Type::Reference(class_id, same_controller_status),
|
|
|
- ) => {
|
|
|
- // Ensure class_id of Entity under provided entity_id references Entity,
|
|
|
- // which class_id is equal to class_id, declared in corresponding PropertyType
|
|
|
- // Retrieve corresponding Entity
|
|
|
- let entity = Self::ensure_referenced_entity_match_its_class(*entity_id, *class_id)?;
|
|
|
- // Ensure Entity can be referenced.
|
|
|
- Self::ensure_entity_can_be_referenced(
|
|
|
- entity,
|
|
|
- *same_controller_status,
|
|
|
- current_entity_controller,
|
|
|
- )?;
|
|
|
- Self::validate_property_vector_length_after_value_insert(vec, max_vec_len)
|
|
|
- }
|
|
|
- _ => Err(Error::<T>::PropertyValueTypeDoesNotMatchInternalVectorType),
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure text property does not exceed its max len
|
|
|
- pub fn validate_max_len_if_text_property(
|
|
|
- &self,
|
|
|
- value: &InputPropertyValue<T>,
|
|
|
- ) -> Result<(), Error<T>> {
|
|
|
- let single_value = value.as_single_value();
|
|
|
-
|
|
|
- match (single_value, &self.property_type.as_single_value_type()) {
|
|
|
- (Some(InputValue::Text(text)), Some(Type::Text(text_max_len))) => {
|
|
|
- Self::validate_max_len_of_text(text, *text_max_len)
|
|
|
- }
|
|
|
- (
|
|
|
- Some(InputValue::TextToHash(text_to_be_hashed)),
|
|
|
- Some(Type::Hash(Some(text_to_be_hashed_max_len))),
|
|
|
- ) => Self::validate_max_len_of_text_to_be_hashed(
|
|
|
- text_to_be_hashed,
|
|
|
- *text_to_be_hashed_max_len,
|
|
|
- ),
|
|
|
- _ => Ok(()),
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn validate_max_len_of_text(text: &[u8], text_max_len: TextMaxLength) -> Result<(), Error<T>> {
|
|
|
- ensure!(
|
|
|
- text.len() <= text_max_len as usize,
|
|
|
- Error::<T>::TextPropertyTooLong
|
|
|
- );
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- fn validate_max_len_of_text_to_be_hashed(
|
|
|
- text_to_be_hashed: &[u8],
|
|
|
- text_to_be_hashed_max_len: u16,
|
|
|
- ) -> Result<(), Error<T>> {
|
|
|
- ensure!(
|
|
|
- text_to_be_hashed.len() <= text_to_be_hashed_max_len as usize,
|
|
|
- Error::<T>::HashedTextPropertyTooLong
|
|
|
- );
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- fn validate_vec_len<V>(vec: &[V], max_len: VecMaxLength) -> Result<(), Error<T>> {
|
|
|
- ensure!(
|
|
|
- vec.len() <= max_len as usize,
|
|
|
- Error::<T>::VecPropertyTooLong
|
|
|
- );
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure `VecInputValue` does not exceed its max len
|
|
|
- pub fn validate_max_len_if_vec_property(
|
|
|
- &self,
|
|
|
- value: &InputPropertyValue<T>,
|
|
|
- ) -> Result<(), Error<T>> {
|
|
|
- let (vec_value, vec_property_type) = if let (Some(vec_value), Some(vec_property_type)) =
|
|
|
- (value.as_vec_value(), self.property_type.as_vec_type())
|
|
|
- {
|
|
|
- (vec_value, vec_property_type)
|
|
|
- } else {
|
|
|
- return Ok(());
|
|
|
- };
|
|
|
-
|
|
|
- let max_len = vec_property_type.get_max_len();
|
|
|
-
|
|
|
- match vec_value {
|
|
|
- VecInputValue::Bool(vec) => Self::validate_vec_len(vec, max_len),
|
|
|
- VecInputValue::Uint16(vec) => Self::validate_vec_len(vec, max_len),
|
|
|
- VecInputValue::Uint32(vec) => Self::validate_vec_len(vec, max_len),
|
|
|
- VecInputValue::Uint64(vec) => Self::validate_vec_len(vec, max_len),
|
|
|
- VecInputValue::Int16(vec) => Self::validate_vec_len(vec, max_len),
|
|
|
- VecInputValue::Int32(vec) => Self::validate_vec_len(vec, max_len),
|
|
|
- VecInputValue::Int64(vec) => Self::validate_vec_len(vec, max_len),
|
|
|
- VecInputValue::TextToHash(vec) => {
|
|
|
- Self::validate_vec_len(vec, max_len)?;
|
|
|
- if let Type::Hash(Some(text_to_be_hashed_max_len)) =
|
|
|
- vec_property_type.get_vec_type()
|
|
|
- {
|
|
|
- for text_to_be_hashed_item in vec.iter() {
|
|
|
- Self::validate_max_len_of_text_to_be_hashed(
|
|
|
- text_to_be_hashed_item,
|
|
|
- *text_to_be_hashed_max_len,
|
|
|
- )?;
|
|
|
- }
|
|
|
- }
|
|
|
- Ok(())
|
|
|
- }
|
|
|
- VecInputValue::Text(vec) => {
|
|
|
- Self::validate_vec_len(vec, max_len)?;
|
|
|
- if let Type::Text(text_max_len) = vec_property_type.get_vec_type() {
|
|
|
- for text_item in vec.iter() {
|
|
|
- Self::validate_max_len_of_text(text_item, *text_max_len)?;
|
|
|
- }
|
|
|
- }
|
|
|
- Ok(())
|
|
|
- }
|
|
|
- VecInputValue::Reference(vec) => Self::validate_vec_len(vec, max_len),
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure provided `InputPropertyValue` matches its `Type`
|
|
|
- pub fn ensure_property_value_matches_its_type(
|
|
|
- &self,
|
|
|
- value: &InputPropertyValue<T>,
|
|
|
- ) -> Result<(), Error<T>> {
|
|
|
- ensure!(
|
|
|
- self.does_prop_value_match_type(value),
|
|
|
- Error::<T>::PropertyValueDoNotMatchType
|
|
|
- );
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- /// Check if provided `InputPropertyValue` matches its `Type`
|
|
|
- pub fn does_prop_value_match_type(&self, value: &InputPropertyValue<T>) -> bool {
|
|
|
- // A non required property can be updated to Bool(false):
|
|
|
- if !self.required && *value == InputPropertyValue::default() {
|
|
|
- return true;
|
|
|
- }
|
|
|
- match (value, &self.property_type) {
|
|
|
- (
|
|
|
- InputPropertyValue::Single(single_property_value),
|
|
|
- PropertyType::Single(ref single_property_type),
|
|
|
- ) => match (single_property_value, single_property_type.deref()) {
|
|
|
- (InputValue::Bool(_), Type::Bool)
|
|
|
- | (InputValue::Uint16(_), Type::Uint16)
|
|
|
- | (InputValue::Uint32(_), Type::Uint32)
|
|
|
- | (InputValue::Uint64(_), Type::Uint64)
|
|
|
- | (InputValue::Int16(_), Type::Int16)
|
|
|
- | (InputValue::Int32(_), Type::Int32)
|
|
|
- | (InputValue::Int64(_), Type::Int64)
|
|
|
- | (InputValue::Text(_), Type::Text(_))
|
|
|
- | (InputValue::TextToHash(_), Type::Hash(_))
|
|
|
- | (InputValue::Reference(_), Type::Reference(_, _)) => true,
|
|
|
- _ => false,
|
|
|
- },
|
|
|
- (
|
|
|
- InputPropertyValue::Vector(vec_value),
|
|
|
- PropertyType::Vector(ref vec_property_type),
|
|
|
- ) => match (vec_value, vec_property_type.get_vec_type()) {
|
|
|
- (VecInputValue::Bool(_), Type::Bool)
|
|
|
- | (VecInputValue::Uint16(_), Type::Uint16)
|
|
|
- | (VecInputValue::Uint32(_), Type::Uint32)
|
|
|
- | (VecInputValue::Uint64(_), Type::Uint64)
|
|
|
- | (VecInputValue::Int16(_), Type::Int16)
|
|
|
- | (VecInputValue::Int32(_), Type::Int32)
|
|
|
- | (VecInputValue::Int64(_), Type::Int64)
|
|
|
- | (VecInputValue::Text(_), Type::Text(_))
|
|
|
- | (VecInputValue::TextToHash(_), Type::Hash(_))
|
|
|
- | (VecInputValue::Reference(_), Type::Reference(_, _)) => true,
|
|
|
- _ => false,
|
|
|
- },
|
|
|
- _ => false,
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Perform all required checks to ensure provided `InputPropertyValue` is valid,
|
|
|
- /// when current `PropertyType` is `Reference`
|
|
|
- pub fn ensure_property_value_is_valid_reference(
|
|
|
- &self,
|
|
|
- value: &InputPropertyValue<T>,
|
|
|
- current_entity_controller: &EntityController<T>,
|
|
|
- ) -> Result<(), Error<T>> {
|
|
|
- match (value, &self.property_type) {
|
|
|
- (
|
|
|
- InputPropertyValue::Single(single_property_value),
|
|
|
- PropertyType::Single(single_property_type),
|
|
|
- ) => {
|
|
|
- if let (
|
|
|
- InputValue::Reference(entity_id),
|
|
|
- Type::Reference(class_id, same_controller_status),
|
|
|
- ) = (single_property_value, single_property_type.deref())
|
|
|
- {
|
|
|
- // Ensure class_id of Entity under provided entity_id references Entity,
|
|
|
- // which class_id is equal to class_id, declared in corresponding PropertyType
|
|
|
- // Retrieve corresponding Entity
|
|
|
- let entity =
|
|
|
- Self::ensure_referenced_entity_match_its_class(*entity_id, *class_id)?;
|
|
|
-
|
|
|
- // Ensure Entity can be referenced.
|
|
|
- Self::ensure_entity_can_be_referenced(
|
|
|
- entity,
|
|
|
- *same_controller_status,
|
|
|
- current_entity_controller,
|
|
|
- )?;
|
|
|
- }
|
|
|
- }
|
|
|
- (InputPropertyValue::Vector(vec_value), PropertyType::Vector(vec_property_type)) => {
|
|
|
- if let (
|
|
|
- VecInputValue::Reference(entity_ids),
|
|
|
- Type::Reference(class_id, same_controller_status),
|
|
|
- ) = (vec_value, vec_property_type.get_vec_type())
|
|
|
- {
|
|
|
- for entity_id in entity_ids.iter() {
|
|
|
- // Ensure class_id of Entity under provided entity_id references Entity,
|
|
|
- // which class_id is equal to class_id, declared in corresponding PropertyType
|
|
|
- // Retrieve corresponding Entity
|
|
|
- let entity =
|
|
|
- Self::ensure_referenced_entity_match_its_class(*entity_id, *class_id)?;
|
|
|
-
|
|
|
- // Ensure Entity can be referenced.
|
|
|
- Self::ensure_entity_can_be_referenced(
|
|
|
- entity,
|
|
|
- *same_controller_status,
|
|
|
- current_entity_controller,
|
|
|
- )?;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- _ => (),
|
|
|
- }
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure `class_id` of `Entity` under provided `entity_id` references `Entity`, which `class_id` is equal to `class_id`,
|
|
|
- /// declared in corresponding `PropertyType`.
|
|
|
- /// Returns corresponding `Entity` instance
|
|
|
- pub fn ensure_referenced_entity_match_its_class(
|
|
|
- entity_id: T::EntityId,
|
|
|
- class_id: T::ClassId,
|
|
|
- ) -> Result<Entity<T>, Error<T>> {
|
|
|
- // Ensure Entity under given id exists
|
|
|
- Module::<T>::ensure_known_entity_id(entity_id)?;
|
|
|
-
|
|
|
- let entity = Module::<T>::entity_by_id(entity_id);
|
|
|
- ensure!(
|
|
|
- entity.get_class_id() == class_id,
|
|
|
- Error::<T>::ReferencedEntityDoesNotMatchItsClass
|
|
|
- );
|
|
|
- Ok(entity)
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure `Entity` can be referenced.
|
|
|
- pub fn ensure_entity_can_be_referenced(
|
|
|
- entity: Entity<T>,
|
|
|
- same_controller_status: bool,
|
|
|
- current_entity_controller: &EntityController<T>,
|
|
|
- ) -> Result<(), Error<T>> {
|
|
|
- let entity_permissions = entity.get_permissions();
|
|
|
-
|
|
|
- // Ensure Entity is referencable
|
|
|
- ensure!(
|
|
|
- entity_permissions.is_referancable(),
|
|
|
- Error::<T>::EntityCanNotBeReferenced
|
|
|
- );
|
|
|
-
|
|
|
- if same_controller_status {
|
|
|
- // Ensure Entity controller is equal to the provided one
|
|
|
- ensure!(
|
|
|
- entity_permissions.controller_is_equal_to(current_entity_controller),
|
|
|
- Error::<T>::SameControllerConstraintViolation
|
|
|
- );
|
|
|
- }
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure `PropertyNameLengthConstraint` satisfied
|
|
|
- pub fn ensure_name_is_valid(&self) -> Result<(), Error<T>> {
|
|
|
- T::PropertyNameLengthConstraint::get().ensure_valid(
|
|
|
- self.name.len(),
|
|
|
- Error::<T>::PropertyNameTooShort,
|
|
|
- Error::<T>::PropertyNameTooLong,
|
|
|
- )
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure `PropertyDescriptionLengthConstraint` satisfied
|
|
|
- pub fn ensure_description_is_valid(&self) -> Result<(), Error<T>> {
|
|
|
- T::PropertyDescriptionLengthConstraint::get().ensure_valid(
|
|
|
- self.description.len(),
|
|
|
- Error::<T>::PropertyDescriptionTooShort,
|
|
|
- Error::<T>::PropertyDescriptionTooLong,
|
|
|
- )
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure `Type` specific constraints satisfied
|
|
|
- pub fn ensure_property_type_size_is_valid(&self) -> Result<(), Error<T>> {
|
|
|
- match &self.property_type {
|
|
|
- PropertyType::Single(single_property_type) => {
|
|
|
- // Ensure Type specific TextMaxLengthConstraint satisfied
|
|
|
- single_property_type.ensure_property_type_size_is_valid()
|
|
|
- }
|
|
|
- PropertyType::Vector(vec_property_type) => {
|
|
|
- // Ensure Type specific TextMaxLengthConstraint & VecMaxLengthConstraint satisfied
|
|
|
- vec_property_type.ensure_property_type_size_is_valid()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Ensure refers to existing `class_id`, if If `Property` `Type` is `Reference`,
|
|
|
- pub fn ensure_property_type_reference_is_valid(&self) -> Result<(), Error<T>> {
|
|
|
- let has_unknown_reference =
|
|
|
- if let Type::Reference(other_class_id, _) = self.property_type.get_inner_type() {
|
|
|
- !<ClassById<T>>::contains_key(other_class_id)
|
|
|
- } else {
|
|
|
- false
|
|
|
- };
|
|
|
-
|
|
|
- ensure!(
|
|
|
- !has_unknown_reference,
|
|
|
- Error::<T>::ClassSchemaRefersUnknownClass
|
|
|
- );
|
|
|
-
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-}
|