1use crate::{Config, Error};
3use common_primitives::schema::{
4 ModelType, PayloadLocation, SchemaId, SchemaSetting, SchemaSettings, SchemaVersion,
5 SchemaVersionResponse,
6};
7use core::fmt::Debug;
8use frame_support::{ensure, pallet_prelude::ConstU32, traits::StorageVersion, BoundedVec};
9use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
10use scale_info::TypeInfo;
11use sp_runtime::DispatchError;
12extern crate alloc;
13use alloc::{string::String, vec, vec::Vec};
14use frame_support::traits::Len;
15
16pub const SCHEMA_STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
18
19pub const SCHEMA_NAME_BYTES_MAX: u32 = 32; pub type SchemaNamePayload = BoundedVec<u8, ConstU32<SCHEMA_NAME_BYTES_MAX>>;
23pub type SchemaNamespace = BoundedVec<u8, ConstU32<NAMESPACE_MAX>>;
25pub type SchemaDescriptor = BoundedVec<u8, ConstU32<DESCRIPTOR_MAX>>;
27pub const NAMESPACE_MIN: u32 = 3;
29pub const NAMESPACE_MAX: u32 = SCHEMA_NAME_BYTES_MAX - (DESCRIPTOR_MIN + 1);
31pub const DESCRIPTOR_MIN: u32 = 1;
33pub const DESCRIPTOR_MAX: u32 = SCHEMA_NAME_BYTES_MAX - (NAMESPACE_MIN + 1);
35pub const SEPARATOR_CHAR: char = '.';
37pub const MAX_NUMBER_OF_VERSIONS: u32 = SchemaVersion::MAX as u32 - 1;
40
41#[derive(Debug, serde::Serialize, serde::Deserialize)]
42pub struct GenesisSchema {
44 pub model_type: ModelType,
46 pub payload_location: PayloadLocation,
48 pub model: String,
50 pub name: String,
52 pub settings: Vec<SchemaSetting>,
54}
55
56#[derive(Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq, MaxEncodedLen)]
57pub struct SchemaInfo {
59 pub model_type: ModelType,
61 pub payload_location: PayloadLocation,
63 pub settings: SchemaSettings,
65 pub has_name: bool,
67}
68
69#[derive(Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq, MaxEncodedLen)]
70pub struct SchemaName {
72 pub namespace: SchemaNamespace,
74 pub descriptor: SchemaDescriptor,
76}
77
78#[derive(Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq, MaxEncodedLen, Default)]
79pub struct SchemaVersionId {
81 pub ids: BoundedVec<SchemaId, ConstU32<MAX_NUMBER_OF_VERSIONS>>,
84}
85
86impl SchemaName {
87 pub fn try_parse<T: Config>(
89 payload: SchemaNamePayload,
90 is_strict: bool,
91 ) -> Result<SchemaName, DispatchError> {
92 let mut str = String::from_utf8(payload.into_inner())
94 .map_err(|_| Error::<T>::InvalidSchemaNameEncoding)?;
95 ensure!(str.is_ascii(), Error::<T>::InvalidSchemaNameEncoding);
96
97 str = String::from(str.to_lowercase().trim());
99
100 ensure!(
102 str.chars().all(|c| c.is_ascii_alphabetic() || c == '-' || c == SEPARATOR_CHAR),
103 Error::<T>::InvalidSchemaNameCharacters
104 );
105
106 let chunks: Vec<_> = str.split(SEPARATOR_CHAR).collect();
108 ensure!(
109 chunks.len() == 2 || (chunks.len() == 1 && !is_strict),
110 Error::<T>::InvalidSchemaNameStructure
111 );
112
113 let namespace = BoundedVec::try_from(chunks[0].as_bytes().to_vec())
115 .map_err(|_| Error::<T>::InvalidSchemaNamespaceLength)?;
116 ensure!(NAMESPACE_MIN <= namespace.len() as u32, Error::<T>::InvalidSchemaNamespaceLength);
117 ensure!(
119 !(namespace.starts_with(b"-") || namespace.ends_with(b"-")),
120 Error::<T>::InvalidSchemaNameStructure
121 );
122
123 let descriptor = match chunks.len() == 2 {
125 true => {
126 let descriptor = BoundedVec::try_from(chunks[1].as_bytes().to_vec())
127 .map_err(|_| Error::<T>::InvalidSchemaDescriptorLength)?;
128 ensure!(
129 DESCRIPTOR_MIN <= descriptor.len() as u32,
130 Error::<T>::InvalidSchemaDescriptorLength
131 );
132 ensure!(
134 !(descriptor.starts_with(b"-") || descriptor.ends_with(b"-")),
135 Error::<T>::InvalidSchemaNameStructure
136 );
137 descriptor
138 },
139 false => BoundedVec::default(),
140 };
141
142 Ok(SchemaName { namespace, descriptor })
143 }
144
145 pub fn get_combined_name(&self) -> Vec<u8> {
147 [
148 self.namespace.clone().into_inner(),
149 vec![SEPARATOR_CHAR as u8],
150 self.descriptor.clone().into_inner(),
151 ]
152 .concat()
153 }
154
155 pub fn new_with_descriptor(&self, descriptor: SchemaDescriptor) -> Self {
157 Self { namespace: self.namespace.clone(), descriptor }
158 }
159
160 pub fn descriptor_exists(&self) -> bool {
162 self.descriptor.len() > 0
163 }
164}
165
166impl SchemaVersionId {
167 pub fn add<T: Config>(&mut self, schema_id: SchemaId) -> Result<SchemaVersion, DispatchError> {
169 let is_new = !self.ids.iter().any(|id| id == &schema_id);
170 ensure!(is_new, Error::<T>::SchemaIdAlreadyExists);
171 self.ids
172 .try_push(schema_id)
173 .map_err(|_| Error::<T>::ExceedsMaxNumberOfVersions)?;
174 let version = self.ids.len() as SchemaVersion;
175 Ok(version)
176 }
177
178 pub fn convert_to_response(&self, schema_name: &SchemaName) -> Vec<SchemaVersionResponse> {
180 self.ids
181 .iter()
182 .enumerate()
183 .map(|(index, schema_id)| SchemaVersionResponse {
184 schema_name: schema_name.get_combined_name(),
185 schema_id: *schema_id,
186 schema_version: (index + 1) as SchemaVersion,
187 })
188 .collect()
189 }
190}