Browse Source

Architecture reworkings: values field of Entity type changed to BTreeMap<u16, PropertyValue> where key is index of property in class

iorveth 4 years ago
parent
commit
affd77315b

+ 18 - 0
Cargo.lock

@@ -4648,6 +4648,24 @@ dependencies = [
  "substrate-primitives",
 ]
 
+[[package]]
+name = "substrate-content-directory-module"
+version = "1.0.1"
+dependencies = [
+ "hex-literal 0.1.4",
+ "parity-scale-codec",
+ "quote 0.6.13",
+ "serde",
+ "sr-io",
+ "sr-primitives",
+ "sr-std",
+ "srml-support",
+ "srml-support-procedural",
+ "srml-system",
+ "srml-timestamp",
+ "substrate-primitives",
+]
+
 [[package]]
 name = "substrate-content-working-group-module"
 version = "1.0.0"

+ 2 - 1
Cargo.toml

@@ -16,10 +16,11 @@ members = [
 	"runtime-modules/token-minting",
 	"runtime-modules/versioned-store",
 	"runtime-modules/versioned-store-permissions",
+	"runtime-modules/content-directory",
 	"node",
 	"utils/chain-spec-builder/"
 ]
 
 [profile.release]
 # Substrate runtime requires unwinding.
-panic = "unwind"
+panic = "unwind"

+ 104 - 103
runtime-modules/content-directory/src/example.rs

@@ -385,63 +385,63 @@ fn create_podcast_class_schema() {
             channel_entity_id
         );
 
+        // 0
+        p.next_text_value(b"https://staked.libsyn.com/rss".to_vec());
+        // 1
+        p.next_text_value(b"Staked".to_vec());
+        // 2
+        p.next_text_value(b"Wed, 15 May 2019 20:36:20 +0000".to_vec());
+        // 3
+        p.next_text_value(b"Fri, 23 Aug 2019 11:26:24 +0000".to_vec());
+        // 4
+        p.next_text_value(b"Libsyn WebEngine 2.0".to_vec());
+        // 5
+        p.next_text_value(b"https://twitter.com/staked_podcast".to_vec());
+        // 6
+        p.next_text_value(b"en".to_vec());
+        // 7
+        p.next_value(PropertyValue::Bool(false));
+        // 8
+        p.next_text_value(b"https://twitter.com/staked_podcast".to_vec());
+        // 9
+        p.next_text_value(b"staked@jsgenesis.com (staked@jsgenesis.com)".to_vec());
+        // 10
+        p.next_text_value(b"https://ssl-static.libsyn.com/p/assets/2/d/2/5/2d25eb5fa72739f7/iTunes_Cover.png".to_vec());
+        // 11
+        p.next_text_value(b"Staked".to_vec());
+        // 12
+        p.next_text_value(b"https://twitter.com/staked_podcast".to_vec());
+        // 13
+        p.next_text_value(b"Exploring crypto and blockchain governance.".to_vec());
+        // 14
+        p.next_text_value(b"Staked".to_vec());
+        // 15
+        p.next_text_value(b"crypto,blockchain,governance,staking,bitcoin,ethereum".to_vec());
+        // 16
+        p.next_value(PropertyValue::TextVec(vec![
+            b"Technology".to_vec(), 
+            b"Software How-To".to_vec()
+        ]));
+        // 17
+        p.next_text_value(b"https://ssl-static.libsyn.com/p/assets/2/d/2/5/2d25eb5fa72739f7/iTunes_Cover.png".to_vec());
+        // 18
+        p.next_text_value(b"yes".to_vec());
+        // 19
+        p.next_text_value(b"Martin Wessel-Berg".to_vec());
+        // 20
+        p.next_text_value(b"staked@jsgenesis.com".to_vec());
+        // 21
+        p.next_text_value(b"Exploring crypto and blockchain governance.".to_vec());
+        // 22
+        p.next_text_value(b"Exploring crypto and blockchain governance.".to_vec());
+        // 23
+        p.next_text_value(b"episodic".to_vec());
+
         assert_ok!(
             TestModule::add_entity_schema_support(
                 channel_entity_id,
                 channel_schema_id,
-                vec![
-                    // 0
-                    p.next_text_value(b"https://staked.libsyn.com/rss".to_vec()),
-                    // 1
-                    p.next_text_value(b"Staked".to_vec()),
-                    // 2
-                    p.next_text_value(b"Wed, 15 May 2019 20:36:20 +0000".to_vec()),
-                    // 3
-                    p.next_text_value(b"Fri, 23 Aug 2019 11:26:24 +0000".to_vec()),
-                    // 4
-                    p.next_text_value(b"Libsyn WebEngine 2.0".to_vec()),
-                    // 5
-                    p.next_text_value(b"https://twitter.com/staked_podcast".to_vec()),
-                    // 6
-                    p.next_text_value(b"en".to_vec()),
-                    // 7
-                    p.next_value(PropertyValue::Bool(false)),
-                    // 8
-                    p.next_text_value(b"https://twitter.com/staked_podcast".to_vec()),
-                    // 9
-                    p.next_text_value(b"staked@jsgenesis.com (staked@jsgenesis.com)".to_vec()),
-                    // 10
-                    p.next_text_value(b"https://ssl-static.libsyn.com/p/assets/2/d/2/5/2d25eb5fa72739f7/iTunes_Cover.png".to_vec()),
-                    // 11
-                    p.next_text_value(b"Staked".to_vec()),
-                    // 12
-                    p.next_text_value(b"https://twitter.com/staked_podcast".to_vec()),
-                    // 13
-                    p.next_text_value(b"Exploring crypto and blockchain governance.".to_vec()),
-                    // 14
-                    p.next_text_value(b"Staked".to_vec()),
-                    // 15
-                    p.next_text_value(b"crypto,blockchain,governance,staking,bitcoin,ethereum".to_vec()),
-                    // 16
-                    p.next_value(PropertyValue::TextVec(vec![
-                        b"Technology".to_vec(), 
-                        b"Software How-To".to_vec()
-                    ])),
-                    // 17
-                    p.next_text_value(b"https://ssl-static.libsyn.com/p/assets/2/d/2/5/2d25eb5fa72739f7/iTunes_Cover.png".to_vec()),
-                    // 18
-                    p.next_text_value(b"yes".to_vec()),
-                    // 19
-                    p.next_text_value(b"Martin Wessel-Berg".to_vec()),
-                    // 20
-                    p.next_text_value(b"staked@jsgenesis.com".to_vec()),
-                    // 21
-                    p.next_text_value(b"Exploring crypto and blockchain governance.".to_vec()),
-                    // 22
-                    p.next_text_value(b"Exploring crypto and blockchain governance.".to_vec()),
-                    // 23
-                    p.next_text_value(b"episodic".to_vec()),
-                ]
+                p.get_property_values()
             )
         );
 
@@ -455,52 +455,52 @@ fn create_podcast_class_schema() {
             episode_2_entity_id
         );
 
+        // 0
+        p.next_text_value(b"Implications of the DAO Report for Crypto Governance".to_vec());
+        // 1
+        p.next_text_value(b"Implications of the DAO Report for Crypto Governance".to_vec());
+        // 2
+        p.next_text_value(b"Wed, 13 Mar 2019 11:20:33 +0000".to_vec());
+        // 3
+        p.next_text_value(b"1bf862ba81ab4ee797526d98e09ad301".to_vec());
+        // 4
+        p.next_text_value(b"http://staked.libsyn.com/implications-of-the-dao-report-for-crypto-governance".to_vec());
+        // 5
+        p.next_text_value(b"https://ssl-static.libsyn.com/p/assets/2/d/2/5/2d25eb5fa72739f7/iTunes_Cover.png".to_vec());
+        // 6
+        p.next_text_value(episode_2_summary.clone());
+        // 7
+        p.next_text_value(episode_2_summary.clone());
+        // 8
+        p.next_text_value(b"87444374".to_vec());
+        // 9
+        p.next_text_value(b"audio/mpeg".to_vec());
+        // 10
+        p.next_text_value(b"https://traffic.libsyn.com/secure/staked/Staked_-_Ep._2_final_cut.mp3?dest-id=1097396".to_vec());
+        // 11
+        p.next_text_value(b"36:27".to_vec());
+        // 12
+        p.next_text_value(b"yes".to_vec());
+        // 13
+        p.next_text_value(b"governance,crypto,sec,securities,dao,bitcoin,blockchain,ethereum".to_vec());
+        // 14
+        p.next_text_value(b"Part I in a series exploring decentralized governance and securities law".to_vec());
+        // 15
+        p.next_text_value(episode_2_summary);
+        // 16
+        p.next_value(PropertyValue::Uint16(1));
+        // 17
+        p.next_value(PropertyValue::Uint16(2));
+        // 18
+        p.next_text_value(b"full".to_vec());
+        // 19
+        p.next_text_value(b"Staked".to_vec());
+
         assert_ok!(
             TestModule::add_entity_schema_support(
                 episode_2_entity_id,
                 episode_schema_id,
-                vec![
-                    // 0
-                    p.next_text_value(b"Implications of the DAO Report for Crypto Governance".to_vec()),
-                    // 1
-                    p.next_text_value(b"Implications of the DAO Report for Crypto Governance".to_vec()),
-                    // 2
-                    p.next_text_value(b"Wed, 13 Mar 2019 11:20:33 +0000".to_vec()),
-                    // 3
-                    p.next_text_value(b"1bf862ba81ab4ee797526d98e09ad301".to_vec()),
-                    // 4
-                    p.next_text_value(b"http://staked.libsyn.com/implications-of-the-dao-report-for-crypto-governance".to_vec()),
-                    // 5
-                    p.next_text_value(b"https://ssl-static.libsyn.com/p/assets/2/d/2/5/2d25eb5fa72739f7/iTunes_Cover.png".to_vec()),
-                    // 6
-                    p.next_text_value(episode_2_summary.clone()),
-                    // 7
-                    p.next_text_value(episode_2_summary.clone()),
-                    // 8
-                    p.next_text_value(b"87444374".to_vec()),
-                    // 9
-                    p.next_text_value(b"audio/mpeg".to_vec()),
-                    // 10
-                    p.next_text_value(b"https://traffic.libsyn.com/secure/staked/Staked_-_Ep._2_final_cut.mp3?dest-id=1097396".to_vec()),
-                    // 11
-                    p.next_text_value(b"36:27".to_vec()),
-                    // 12
-                    p.next_text_value(b"yes".to_vec()),
-                    // 13
-                    p.next_text_value(b"governance,crypto,sec,securities,dao,bitcoin,blockchain,ethereum".to_vec()),
-                    // 14
-                    p.next_text_value(b"Part I in a series exploring decentralized governance and securities law".to_vec()),
-                    // 15
-                    p.next_text_value(episode_2_summary),
-                    // 16
-                    p.next_value(PropertyValue::Uint16(1)),
-                    // 17
-                    p.next_value(PropertyValue::Uint16(2)),
-                    // 18
-                    p.next_text_value(b"full".to_vec()),
-                    // 19
-                    p.next_text_value(b"Staked".to_vec()),
-                ]
+                p.get_property_values()
             )
         );
     })
@@ -508,23 +508,24 @@ fn create_podcast_class_schema() {
 
 struct PropHelper {
     prop_idx: u16,
+    property_values: BTreeMap<u16, PropertyValue>
 }
 
 impl PropHelper {
     fn new() -> PropHelper {
-        PropHelper { prop_idx: 0 }
+        PropHelper { prop_idx: 0, property_values: BTreeMap::new() }
     }
 
-    fn next_value(&mut self, value: PropertyValue) -> ClassPropertyValue {
-        let value = ClassPropertyValue {
-            in_class_index: self.prop_idx,
-            value: value,
-        };
+    fn next_value(&mut self, value: PropertyValue) {
+        self.property_values.insert(self.prop_idx, value);
         self.prop_idx += 1;
-        value
     }
 
-    fn next_text_value(&mut self, text: Vec<u8>) -> ClassPropertyValue {
+    fn next_text_value(&mut self, text: Vec<u8>) {
         self.next_value(PropertyValue::Text(text))
     }
+
+    fn get_property_values(self) -> BTreeMap<u16, PropertyValue> {
+        self.property_values
+    }
 }

+ 24 - 42
runtime-modules/content-directory/src/lib.rs

@@ -167,12 +167,12 @@ impl <T: Trait> Class<T> {
     }
 
     fn is_active_schema(&self, schema_index: u16) -> bool {
-        // Such indexing safe, when length bounds were previously checked
+        // Such indexing is safe, when length bounds were previously checked
         self.schemas[schema_index as usize].is_active
     }
 
     fn update_schema_status(&mut self, schema_index: u16, schema_status: bool) {
-        // Such indexing safe, when length bounds were previously checked
+        // Such indexing is safe, when length bounds were previously checked
         self.schemas[schema_index as usize].is_active = schema_status;
     }
 
@@ -206,7 +206,7 @@ pub struct Entity {
 
     /// Values for properties on class that are used by some schema used by this entity!
     /// Length is no more than Class.properties.
-    pub values: Vec<ClassPropertyValue>,
+    pub values: BTreeMap<u16, PropertyValue>,
     // pub deleted: bool,
 }
 
@@ -639,7 +639,7 @@ decl_module! {
             as_entity_maintainer: bool,
             entity_id: EntityId,
             schema_id: u16, // Do not type alias u16!! - u16,
-            property_values: Vec<ClassPropertyValue>
+            property_values: BTreeMap<u16, PropertyValue>
         ) -> dispatch::Result {
             let raw_origin = Self::ensure_root_or_signed(origin)?;
             Self::do_add_schema_support_to_entity(&raw_origin, with_credential, as_entity_maintainer, entity_id, schema_id, property_values)
@@ -650,7 +650,7 @@ decl_module! {
             with_credential: Option<T::Credential>,
             as_entity_maintainer: bool,
             entity_id: EntityId,
-            property_values: Vec<ClassPropertyValue>
+            property_values: BTreeMap<u16, PropertyValue>
         ) -> dispatch::Result {
             let raw_origin = Self::ensure_root_or_signed(origin)?;
             Self::do_update_entity_property_values(&raw_origin, with_credential, as_entity_maintainer, entity_id, property_values)
@@ -749,7 +749,7 @@ impl<T: Trait> Module<T> {
         let new_entity = Entity {
             class_id,
             in_class_schema_indexes: vec![],
-            values: vec![],
+            values: BTreeMap::new(),
         };
 
         // Save newly created entity:
@@ -766,7 +766,7 @@ impl<T: Trait> Module<T> {
         with_credential: Option<T::Credential>,
         as_entity_maintainer: bool,
         entity_id: EntityId,
-        property_values: Vec<ClassPropertyValue>,
+        property_values: BTreeMap<u16, PropertyValue>,
     ) -> dispatch::Result {
         let class_id = Self::get_class_id_by_entity_id(entity_id)?;
 
@@ -806,7 +806,7 @@ impl<T: Trait> Module<T> {
 
     pub fn complete_entity_property_values_update(
         entity_id: EntityId,
-        new_property_values: Vec<ClassPropertyValue>,
+        new_property_values: BTreeMap<u16, PropertyValue>
     ) -> dispatch::Result {
         Self::ensure_known_entity_id(entity_id)?;
 
@@ -819,25 +819,17 @@ impl<T: Trait> Module<T> {
 
         // Iterate over a vector of new values and update corresponding properties
         // of this entity if new values are valid.
-        for new_prop_value in new_property_values.iter() {
-            let ClassPropertyValue {
-                in_class_index: id,
-                value: new_value,
-            } = new_prop_value;
+        for (id, new_value) in new_property_values.iter() {
 
             // Try to find a current property value in the entity
             // by matching its id to the id of a property with an updated value.
-            if let Some(current_prop_value) = updated_values
+            if let Some((in_class_index, current_prop_value)) = updated_values
                 .iter_mut()
-                .find(|prop| *id == prop.in_class_index)
+                .find(|(in_class_index, _)| *id == **in_class_index)
             {
-                let ClassPropertyValue {
-                    in_class_index: valid_id,
-                    value: current_value,
-                } = current_prop_value;
 
                 // Get class-level information about this property
-                let class_prop = class.properties.get(*valid_id as usize).unwrap();
+                let class_prop = class.properties.get(*in_class_index as usize).unwrap();
 
                 // Validate a new property value against the type of this property
                 // and check any additional constraints like the length of a vector
@@ -845,7 +837,7 @@ impl<T: Trait> Module<T> {
                 Self::ensure_property_value_is_valid(new_value.clone(), class_prop.clone())?;
 
                 // Update a current prop value in a mutable vector, if a new value is valid.
-                *current_value = new_value.clone();
+                *current_prop_value = new_value.clone();
                 updates_count += 1;
             } else {
                 // Throw an error if a property was not found on entity
@@ -870,7 +862,7 @@ impl<T: Trait> Module<T> {
         as_entity_maintainer: bool,
         entity_id: EntityId,
         schema_id: u16,
-        property_values: Vec<ClassPropertyValue>,
+        property_values: BTreeMap<u16, PropertyValue>,
     ) -> dispatch::Result {
         // class id of the entity being updated
         let class_id = Self::get_class_id_by_entity_id(entity_id)?;
@@ -1035,10 +1027,10 @@ impl<T: Trait> Module<T> {
     // the target entity and class exists and constraint allows it.
     fn ensure_internal_property_values_permitted(
         source_class_id: ClassId,
-        property_values: &[ClassPropertyValue],
+        property_values: &BTreeMap<u16, PropertyValue>,
     ) -> dispatch::Result {
-        for property_value in property_values.iter() {
-            if let PropertyValue::Reference(ref target_entity_id) = property_value.value {
+        for (in_class_index, property_value) in property_values.iter() {
+            if let PropertyValue::Reference(ref target_entity_id) = property_value {
                 // get the class permissions for target class
                 let target_class_id = Self::get_class_id_by_entity_id(*target_entity_id)?;
                 // assert class permissions exists for target class
@@ -1053,7 +1045,7 @@ impl<T: Trait> Module<T> {
                     ReferenceConstraint::Restricted(permitted_properties) => {
                         if permitted_properties.contains(&PropertyOfClass {
                             class_id: source_class_id,
-                            property_index: property_value.in_class_index,
+                            property_index: *in_class_index,
                         }) {
                             Ok(())
                         } else {
@@ -1145,7 +1137,7 @@ impl<T: Trait> Module<T> {
         pub fn add_entity_schema_support(
             entity_id: EntityId,
             schema_id: u16,
-            property_values: Vec<ClassPropertyValue>,
+            property_values: BTreeMap<u16, PropertyValue>,
         ) -> dispatch::Result {
             Self::ensure_known_entity_id(entity_id)?;
     
@@ -1169,7 +1161,7 @@ impl<T: Trait> Module<T> {
             for &prop_id in schema_prop_ids.iter() {
                 let prop_already_added = current_entity_values
                     .iter()
-                    .any(|prop| prop.in_class_index == prop_id);
+                    .any(|(property_in_class_index, _)| *property_in_class_index == prop_id);
     
                 if prop_already_added {
                     // A property is already added to the entity and cannot be updated
@@ -1182,20 +1174,13 @@ impl<T: Trait> Module<T> {
                 // If a value was not povided for the property of this schema:
                 match property_values
                     .iter()
-                    .find(|prop| prop.in_class_index == prop_id)
+                    .find(|(property_in_class_index, _)| **property_in_class_index == prop_id)
                 {
-                    Some(new_prop) => {
-                        let ClassPropertyValue {
-                            in_class_index: new_id,
-                            value: new_value,
-                        } = new_prop;
+                    Some((new_id, new_value)) => {
     
                         Self::ensure_property_value_is_valid(new_value.clone(), class_prop.clone())?;
     
-                        appended_entity_values.push(ClassPropertyValue {
-                            in_class_index: *new_id,
-                            value: new_value.clone(),
-                        });
+                        appended_entity_values.insert(*new_id, new_value.to_owned());
                     }
                     None => {
                         // All required prop values should be are provided
@@ -1204,10 +1189,7 @@ impl<T: Trait> Module<T> {
                         }
                         // Add all missing non required schema prop values as PropertyValue::None
                         else {
-                            appended_entity_values.push(ClassPropertyValue {
-                                in_class_index: prop_id,
-                                value: PropertyValue::Bool(false),
-                            });
+                            appended_entity_values.insert(prop_id, PropertyValue::Bool(false));
                         }
                     }
                 }

+ 15 - 16
runtime-modules/content-directory/src/mock.rs

@@ -198,11 +198,10 @@ pub fn simple_test_schema() -> Vec<Property> {
     }]
 }
 
-pub fn simple_test_entity_property_values() -> Vec<ClassPropertyValue> {
-    vec![ClassPropertyValue {
-        in_class_index: 0,
-        value: PropertyValue::Int64(1337),
-    }]
+pub fn simple_test_entity_property_values() -> BTreeMap<u16, PropertyValue>  {
+    let mut property_values = BTreeMap::new();
+    property_values.insert(0, PropertyValue::Int64(1337));
+    property_values
 }
 
 pub fn create_simple_class(permissions: ClassPermissionsType<Runtime>) -> ClassId {
@@ -252,10 +251,12 @@ pub fn create_entity_of_class(class_id: ClassId) -> EntityId {
 
 pub fn create_entity_with_schema_support() -> EntityId {
     let (_, schema_id, entity_id) = create_class_with_schema_and_entity();
+    let mut property_values = BTreeMap::new();
+    property_values.insert(PROP_ID_BOOL, PropertyValue::Bool(true));
     assert_ok!(TestModule::add_entity_schema_support(
         entity_id,
         schema_id,
-        vec![prop_value(PROP_ID_BOOL, PropertyValue::Bool(true))]
+        property_values
     ));
     entity_id
 }
@@ -332,18 +333,16 @@ pub fn good_prop_ids() -> Vec<u16> {
     vec![0, 1]
 }
 
-pub fn bool_prop_value() -> ClassPropertyValue {
-    ClassPropertyValue {
-        in_class_index: 0,
-        value: PropertyValue::Bool(true),
-    }
+pub fn bool_prop_value() -> BTreeMap<u16, PropertyValue> {
+    let mut property_values = BTreeMap::new();
+    property_values.insert(0, PropertyValue::Bool(true));
+    property_values
 }
 
-pub fn prop_value(index: u16, value: PropertyValue) -> ClassPropertyValue {
-    ClassPropertyValue {
-        in_class_index: index,
-        value: value,
-    }
+pub fn prop_value(index: u16, value: PropertyValue) -> BTreeMap<u16, PropertyValue> {
+    let mut property_values = BTreeMap::new();
+    property_values.insert(index, value);
+    property_values
 }
 
 // pub type System = system::Module;

+ 4 - 7
runtime-modules/content-directory/src/operations.rs

@@ -83,8 +83,8 @@ pub fn parametrized_entity_to_entity_id(
 pub fn parametrized_property_values_to_property_values(
     created_entities: &BTreeMap<usize, EntityId>,
     parametrized_property_values: Vec<ParametrizedClassPropertyValue>,
-) -> Result<Vec<ClassPropertyValue>, &'static str> {
-    let mut class_property_values: Vec<ClassPropertyValue> = vec![];
+) -> Result<BTreeMap<u16, PropertyValue>, &'static str> {
+    let mut class_property_values = BTreeMap::new();
 
     for parametrized_class_property_value in parametrized_property_values.into_iter() {
         let property_value = match parametrized_class_property_value.value {
@@ -124,11 +124,8 @@ pub fn parametrized_property_values_to_property_values(
                 PropertyValue::ReferenceVec(entities)
             }
         };
-
-        class_property_values.push(ClassPropertyValue {
-            in_class_index: parametrized_class_property_value.in_class_index,
-            value: property_value,
-        });
+        
+        class_property_values.insert(parametrized_class_property_value.in_class_index, property_value);
     }
 
     Ok(class_property_values)

+ 38 - 51
runtime-modules/content-directory/src/tests.rs

@@ -667,10 +667,7 @@ fn batch_transaction_vector_of_entities() {
             Entity {
                 class_id: new_class_id,
                 in_class_schema_indexes: vec![0],
-                values: vec![ClassPropertyValue {
-                    in_class_index: 0,
-                    value: PropertyValue::ReferenceVec(vec![entity_id + 1, entity_id + 2,])
-                }]
+                values: prop_value(0, PropertyValue::ReferenceVec(vec![entity_id + 1, entity_id + 2,]))
             }
         );
     })
@@ -975,7 +972,7 @@ fn cannot_add_schema_to_entity_when_entity_not_found() {
         assert_entity_not_found(TestModule::add_entity_schema_support(
             UNKNOWN_ENTITY_ID,
             1,
-            vec![],
+            BTreeMap::new(),
         ));
     })
 }
@@ -994,7 +991,7 @@ fn cannot_add_schema_to_entity_when_schema_is_not_active() {
 
         // Secondly we try to add support for the same schema.
         assert_err!(
-            TestModule::add_entity_schema_support(entity_id, schema_id, vec![bool_prop_value()]),
+            TestModule::add_entity_schema_support(entity_id, schema_id, bool_prop_value()),
             ERROR_CLASS_SCHEMA_NOT_ACTIVE
         );
     })
@@ -1009,12 +1006,12 @@ fn cannot_add_schema_to_entity_when_schema_already_added_to_entity() {
         assert_ok!(TestModule::add_entity_schema_support(
             entity_id,
             schema_id,
-            vec![bool_prop_value()]
+            bool_prop_value()
         ));
 
         // Secondly we try to add support for the same schema.
         assert_err!(
-            TestModule::add_entity_schema_support(entity_id, schema_id, vec![]),
+            TestModule::add_entity_schema_support(entity_id, schema_id, BTreeMap::new()),
             ERROR_SCHEMA_ALREADY_ADDED_TO_ENTITY
         );
     })
@@ -1029,7 +1026,7 @@ fn cannot_add_schema_to_entity_when_schema_id_is_unknown() {
             TestModule::add_entity_schema_support(
                 entity_id,
                 unknown_schema_id,
-                vec![prop_value(0, PropertyValue::Bool(false))]
+                prop_value(0, PropertyValue::Bool(false))
             ),
             ERROR_UNKNOWN_CLASS_SCHEMA_ID
         );
@@ -1040,14 +1037,13 @@ fn cannot_add_schema_to_entity_when_schema_id_is_unknown() {
 fn cannot_add_schema_to_entity_when_prop_value_dont_match_type() {
     with_test_externalities(|| {
         let (_, schema_id, entity_id) = create_class_with_schema_and_entity();
+        let mut prop_values = bool_prop_value();
+        prop_values.append(&mut prop_value(PROP_ID_U32, PropertyValue::Bool(true)));
         assert_err!(
             TestModule::add_entity_schema_support(
                 entity_id,
                 schema_id,
-                vec![
-                    bool_prop_value(),
-                    prop_value(PROP_ID_U32, PropertyValue::Bool(true))
-                ]
+                prop_values
             ),
             ERROR_PROP_VALUE_DONT_MATCH_TYPE
         );
@@ -1058,17 +1054,16 @@ fn cannot_add_schema_to_entity_when_prop_value_dont_match_type() {
 fn cannot_add_schema_to_entity_when_unknown_internal_entity_id() {
     with_test_externalities(|| {
         let (_, schema_id, entity_id) = create_class_with_schema_and_entity();
+        let mut prop_values = bool_prop_value();
+        prop_values.append(&mut prop_value(
+            PROP_ID_INTERNAL,
+            PropertyValue::Reference(UNKNOWN_ENTITY_ID)
+        ));
         assert_err!(
             TestModule::add_entity_schema_support(
                 entity_id,
                 schema_id,
-                vec![
-                    bool_prop_value(),
-                    prop_value(
-                        PROP_ID_INTERNAL,
-                        PropertyValue::Reference(UNKNOWN_ENTITY_ID)
-                    )
-                ]
+                prop_values
             ),
             ERROR_ENTITY_NOT_FOUND
         );
@@ -1083,7 +1078,7 @@ fn cannot_add_schema_to_entity_when_missing_required_prop() {
             TestModule::add_entity_schema_support(
                 entity_id,
                 schema_id,
-                vec![prop_value(PROP_ID_U32, PropertyValue::Uint32(456))]
+                prop_value(PROP_ID_U32, PropertyValue::Uint32(456))
             ),
             ERROR_MISSING_REQUIRED_PROP
         );
@@ -1094,25 +1089,23 @@ fn cannot_add_schema_to_entity_when_missing_required_prop() {
 fn should_add_schema_to_entity_when_some_optional_props_provided() {
     with_test_externalities(|| {
         let (_, schema_id, entity_id) = create_class_with_schema_and_entity();
+        let mut prop_values = bool_prop_value();
+        prop_values.append(&mut prop_value(PROP_ID_U32, PropertyValue::Uint32(123)));
         assert_ok!(TestModule::add_entity_schema_support(
             entity_id,
             schema_id,
-            vec![
-                bool_prop_value(),
-                prop_value(PROP_ID_U32, PropertyValue::Uint32(123)),
-                // Note that an optional internal prop is not provided here.
-            ]
+            // Note that an optional internal prop is not provided here.
+            prop_values
         ));
 
         let entity = TestModule::entity_by_id(entity_id);
         assert_eq!(entity.in_class_schema_indexes, [SCHEMA_ID_0]);
+        prop_values = bool_prop_value();
+        prop_values.append(&mut prop_value(PROP_ID_U32, PropertyValue::Uint32(123)));
+        prop_values.append(&mut prop_value(PROP_ID_INTERNAL, PropertyValue::Bool(false)));
         assert_eq!(
             entity.values,
-            vec![
-                bool_prop_value(),
-                prop_value(PROP_ID_U32, PropertyValue::Uint32(123)),
-                prop_value(PROP_ID_INTERNAL, PropertyValue::Bool(false)),
-            ]
+            prop_values
         );
     })
 }
@@ -1125,7 +1118,7 @@ fn cannot_update_entity_props_when_entity_not_found() {
     with_test_externalities(|| {
         assert_entity_not_found(TestModule::complete_entity_property_values_update(
             UNKNOWN_ENTITY_ID,
-            vec![],
+            BTreeMap::new(),
         ));
     })
 }
@@ -1137,7 +1130,7 @@ fn cannot_update_entity_props_when_prop_value_dont_match_type() {
         assert_err!(
             TestModule::complete_entity_property_values_update(
                 entity_id,
-                vec![prop_value(PROP_ID_BOOL, PropertyValue::Uint32(1))]
+                prop_value(PROP_ID_BOOL, PropertyValue::Uint32(1))
             ),
             ERROR_PROP_VALUE_DONT_MATCH_TYPE
         );
@@ -1151,10 +1144,10 @@ fn cannot_update_entity_props_when_unknown_internal_entity_id() {
         assert_err!(
             TestModule::complete_entity_property_values_update(
                 entity_id,
-                vec![prop_value(
+                prop_value(
                     PROP_ID_INTERNAL,
                     PropertyValue::Reference(UNKNOWN_ENTITY_ID)
-                )]
+                )
             ),
             ERROR_ENTITY_NOT_FOUND
         );
@@ -1168,7 +1161,7 @@ fn cannot_update_entity_props_when_unknown_entity_prop_id() {
         assert_err!(
             TestModule::complete_entity_property_values_update(
                 entity_id,
-                vec![prop_value(UNKNOWN_PROP_ID, PropertyValue::Bool(true))]
+                prop_value(UNKNOWN_PROP_ID, PropertyValue::Bool(true))
             ),
             ERROR_UNKNOWN_ENTITY_PROP_ID
         );
@@ -1179,29 +1172,23 @@ fn cannot_update_entity_props_when_unknown_entity_prop_id() {
 fn update_entity_props_successfully() {
     with_test_externalities(|| {
         let entity_id = create_entity_with_schema_support();
+        let mut prop_values = prop_value(PROP_ID_BOOL, PropertyValue::Bool(true));
+        prop_values.append(&mut prop_value(PROP_ID_U32, PropertyValue::Bool(false)));
+        prop_values.append(&mut prop_value(PROP_ID_INTERNAL, PropertyValue::Bool(false)));
         assert_eq!(
             TestModule::entity_by_id(entity_id).values,
-            vec![
-                prop_value(PROP_ID_BOOL, PropertyValue::Bool(true)),
-                prop_value(PROP_ID_U32, PropertyValue::Bool(false)),
-                prop_value(PROP_ID_INTERNAL, PropertyValue::Bool(false)),
-            ]
+            prop_values
         );
+        prop_values = prop_value(PROP_ID_BOOL, PropertyValue::Bool(false));
+        prop_values.append(&mut prop_value(PROP_ID_U32, PropertyValue::Uint32(123)));
+        prop_values.append(&mut prop_value(PROP_ID_INTERNAL, PropertyValue::Reference(entity_id)));
         assert_ok!(TestModule::complete_entity_property_values_update(
             entity_id,
-            vec![
-                prop_value(PROP_ID_BOOL, PropertyValue::Bool(false)),
-                prop_value(PROP_ID_U32, PropertyValue::Uint32(123)),
-                prop_value(PROP_ID_INTERNAL, PropertyValue::Reference(entity_id)),
-            ]
+            prop_values.clone()
         ));
         assert_eq!(
             TestModule::entity_by_id(entity_id).values,
-            vec![
-                prop_value(PROP_ID_BOOL, PropertyValue::Bool(false)),
-                prop_value(PROP_ID_U32, PropertyValue::Uint32(123)),
-                prop_value(PROP_ID_INTERNAL, PropertyValue::Reference(entity_id)),
-            ]
+            prop_values
         );
     })
 }