11//! Validator for Signed Document Version
22
3- use crate :: {
4- providers:: CatalystSignedDocumentProvider , CatalystSignedDocument , DocLocator , DocumentRef ,
5- } ;
3+ use crate :: { providers:: CatalystSignedDocumentProvider , CatalystSignedDocument } ;
64
75/// Signed Document `ver` field validation rule
86pub ( crate ) struct VerRule ;
@@ -43,17 +41,54 @@ impl VerRule {
4341 & format ! ( "Document Version {ver} cannot be smaller than Document ID {id}" ) ,
4442 ) ;
4543 is_valid = false ;
46- }
44+ } else if let Some ( last_doc) = provider. try_get_last_doc ( id) . await ? {
45+ let Ok ( last_doc_ver) = last_doc. doc_ver ( ) else {
46+ doc. report ( ) . missing_field (
47+ "ver" ,
48+ & format ! (
49+ "Missing `ver` field in the latest known document, for the the id {id}"
50+ ) ,
51+ ) ;
52+ return Ok ( false ) ;
53+ } ;
4754
48- if ver != id {
49- let first_submitted_doc = DocumentRef :: new ( id, id, DocLocator :: default ( ) ) ;
50- if provider. try_get_doc ( & first_submitted_doc) . await ?. is_none ( ) {
55+ if last_doc_ver >= ver {
5156 doc. report ( ) . functional_validation (
52- & format ! ( "` ver` and `id` are not equal, ver: {ver}, id: {id}. Document with `id` and ` ver` being equal MUST exist " ) ,
53- "Cannot get a first version document from the provider, document for which `id` and `ver` are equal." ,
57+ & format ! ( "New document ver should be greater that the submitted latest known. New document ver: {ver}, latest known ver: {last_doc_ver} " ) ,
58+ & format ! ( "Document's `ver` field should continuously incrising, for the the id {id}" ) ,
5459 ) ;
5560 is_valid = false ;
5661 }
62+
63+ let Ok ( last_doc_type) = last_doc. doc_type ( ) else {
64+ doc. report ( ) . missing_field (
65+ "type" ,
66+ & format ! (
67+ "Missing `type` field in the latest known document. Last known document id: {id}, ver: {last_doc_ver}."
68+ ) ,
69+ ) ;
70+ return Ok ( false ) ;
71+ } ;
72+
73+ let Ok ( doc_type) = doc. doc_type ( ) else {
74+ doc. report ( )
75+ . missing_field ( "type" , & format ! ( "Missing `type` field." ) ) ;
76+ return Ok ( false ) ;
77+ } ;
78+
79+ if last_doc_type != doc_type {
80+ doc. report ( ) . functional_validation (
81+ & format ! ( "New document type should be the same that the submitted latest known. New document type: {doc_type}, latest known ver: {last_doc_type}" ) ,
82+ & format ! ( "Document's type should be the same for all documents with the same id {id}" ) ,
83+ ) ;
84+ is_valid = false ;
85+ }
86+ } else if ver != id {
87+ doc. report ( ) . functional_validation (
88+ & format ! ( "`ver` and `id` are not equal, ver: {ver}, id: {id}. Document with `id` and `ver` being equal MUST exist" ) ,
89+ "Cannot get a first version document from the provider, document for which `id` and `ver` are equal." ,
90+ ) ;
91+ is_valid = false ;
5792 }
5893
5994 Ok ( is_valid)
@@ -70,7 +105,7 @@ mod tests {
70105 use super :: * ;
71106 use crate :: {
72107 builder:: tests:: Builder , metadata:: SupportedField ,
73- providers:: tests:: TestCatalystSignedDocumentProvider , UuidV7 ,
108+ providers:: tests:: TestCatalystSignedDocumentProvider , UuidV4 , UuidV7 ,
74109 } ;
75110
76111 #[ test_case(
@@ -86,6 +121,7 @@ mod tests {
86121 ) ]
87122 #[ test_case(
88123 |provider| {
124+ let doc_type = UuidV4 :: new( ) ;
89125 let now = SystemTime :: now( )
90126 . duration_since( SystemTime :: UNIX_EPOCH )
91127 . unwrap( )
@@ -96,6 +132,7 @@ mod tests {
96132 let first_doc = Builder :: new( )
97133 . with_metadata_field( SupportedField :: Id ( id) )
98134 . with_metadata_field( SupportedField :: Ver ( id) )
135+ . with_metadata_field( SupportedField :: Type ( doc_type. into( ) ) )
99136 . build( ) ;
100137 provider. add_document( None , & first_doc) . unwrap( ) ;
101138
@@ -105,23 +142,26 @@ mod tests {
105142 Builder :: new( )
106143 . with_metadata_field( SupportedField :: Id ( id) )
107144 . with_metadata_field( SupportedField :: Ver ( ver) )
145+ . with_metadata_field( SupportedField :: Type ( doc_type. into( ) ) )
108146 . build( )
109147 }
110148 => true ;
111149 "`ver` greater than `id`"
112150 ) ]
113151 #[ test_case(
114152 |provider| {
153+ let doc_type = UuidV4 :: new( ) ;
115154 let now = SystemTime :: now( )
116- . duration_since( SystemTime :: UNIX_EPOCH )
117- . unwrap( )
118- . as_secs( ) ;
155+ . duration_since( SystemTime :: UNIX_EPOCH )
156+ . unwrap( )
157+ . as_secs( ) ;
119158 let id = Uuid :: new_v7( Timestamp :: from_unix_time( now + 1 , 0 , 0 , 0 ) )
120159 . try_into( )
121160 . unwrap( ) ;
122161 let first_doc = Builder :: new( )
123162 . with_metadata_field( SupportedField :: Id ( id) )
124163 . with_metadata_field( SupportedField :: Ver ( id) )
164+ . with_metadata_field( SupportedField :: Type ( doc_type. into( ) ) )
125165 . build( ) ;
126166 provider. add_document( None , & first_doc) . unwrap( ) ;
127167
@@ -131,13 +171,55 @@ mod tests {
131171 Builder :: new( )
132172 . with_metadata_field( SupportedField :: Id ( id) )
133173 . with_metadata_field( SupportedField :: Ver ( ver) )
174+ . with_metadata_field( SupportedField :: Type ( doc_type. into( ) ) )
134175 . build( )
135176 }
136177 => false ;
137178 "`ver` less than `id`"
138179 ) ]
180+ #[ test_case(
181+ |provider| {
182+ let doc_type = UuidV4 :: new( ) ;
183+ let now = SystemTime :: now( )
184+ . duration_since( SystemTime :: UNIX_EPOCH )
185+ . unwrap( )
186+ . as_secs( ) ;
187+ let id = Uuid :: new_v7( Timestamp :: from_unix_time( now + 1 , 0 , 0 , 0 ) )
188+ . try_into( )
189+ . unwrap( ) ;
190+ let doc = Builder :: new( )
191+ . with_metadata_field( SupportedField :: Id ( id) )
192+ . with_metadata_field( SupportedField :: Ver ( id) )
193+ . with_metadata_field( SupportedField :: Type ( doc_type. into( ) ) )
194+ . build( ) ;
195+ provider. add_document( None , & doc) . unwrap( ) ;
196+
197+
198+ let ver = Uuid :: new_v7( Timestamp :: from_unix_time( now + 3 , 0 , 0 , 0 ) )
199+ . try_into( )
200+ . unwrap( ) ;
201+ let doc = Builder :: new( )
202+ . with_metadata_field( SupportedField :: Id ( id) )
203+ . with_metadata_field( SupportedField :: Ver ( ver) )
204+ . with_metadata_field( SupportedField :: Type ( doc_type. into( ) ) )
205+ . build( ) ;
206+ provider. add_document( None , & doc) . unwrap( ) ;
207+
208+ let ver = Uuid :: new_v7( Timestamp :: from_unix_time( now + 2 , 0 , 0 , 0 ) )
209+ . try_into( )
210+ . unwrap( ) ;
211+ Builder :: new( )
212+ . with_metadata_field( SupportedField :: Id ( id) )
213+ . with_metadata_field( SupportedField :: Ver ( ver) )
214+ . with_metadata_field( SupportedField :: Type ( doc_type. into( ) ) )
215+ . build( )
216+ }
217+ => false ;
218+ "`ver` less than `ver` field for of the latest known document"
219+ ) ]
139220 #[ test_case(
140221 |_| {
222+ let doc_type = UuidV4 :: new( ) ;
141223 let now = SystemTime :: now( )
142224 . duration_since( SystemTime :: UNIX_EPOCH )
143225 . unwrap( )
@@ -151,11 +233,96 @@ mod tests {
151233 Builder :: new( )
152234 . with_metadata_field( SupportedField :: Id ( id) )
153235 . with_metadata_field( SupportedField :: Ver ( ver) )
236+ . with_metadata_field( SupportedField :: Type ( doc_type. into( ) ) )
154237 . build( )
155238 }
156239 => false ;
157240 "missing first version document"
158241 ) ]
242+ #[ test_case(
243+ |provider| {
244+ let doc_type = UuidV4 :: new( ) ;
245+ let now = SystemTime :: now( )
246+ . duration_since( SystemTime :: UNIX_EPOCH )
247+ . unwrap( )
248+ . as_secs( ) ;
249+ let id = Uuid :: new_v7( Timestamp :: from_unix_time( now - 1 , 0 , 0 , 0 ) )
250+ . try_into( )
251+ . unwrap( ) ;
252+ let first_doc = Builder :: new( )
253+ . with_metadata_field( SupportedField :: Id ( id) )
254+ . with_metadata_field( SupportedField :: Ver ( id) )
255+ . with_metadata_field( SupportedField :: Type ( doc_type. into( ) ) )
256+ . build( ) ;
257+ provider. add_document( None , & first_doc) . unwrap( ) ;
258+
259+ let ver = Uuid :: new_v7( Timestamp :: from_unix_time( now + 1 , 0 , 0 , 0 ) )
260+ . try_into( )
261+ . unwrap( ) ;
262+ Builder :: new( )
263+ . with_metadata_field( SupportedField :: Id ( id) )
264+ . with_metadata_field( SupportedField :: Ver ( ver) )
265+ . build( )
266+ }
267+ => false ;
268+ "missing `type` field"
269+ ) ]
270+ #[ test_case(
271+ |provider| {
272+ let doc_type = UuidV4 :: new( ) ;
273+ let now = SystemTime :: now( )
274+ . duration_since( SystemTime :: UNIX_EPOCH )
275+ . unwrap( )
276+ . as_secs( ) ;
277+ let id = Uuid :: new_v7( Timestamp :: from_unix_time( now - 1 , 0 , 0 , 0 ) )
278+ . try_into( )
279+ . unwrap( ) ;
280+ let first_doc = Builder :: new( )
281+ . with_metadata_field( SupportedField :: Id ( id) )
282+ . with_metadata_field( SupportedField :: Ver ( id) )
283+ . build( ) ;
284+ provider. add_document( None , & first_doc) . unwrap( ) ;
285+
286+ let ver = Uuid :: new_v7( Timestamp :: from_unix_time( now + 1 , 0 , 0 , 0 ) )
287+ . try_into( )
288+ . unwrap( ) ;
289+ Builder :: new( )
290+ . with_metadata_field( SupportedField :: Id ( id) )
291+ . with_metadata_field( SupportedField :: Ver ( ver) )
292+ . with_metadata_field( SupportedField :: Type ( doc_type. into( ) ) )
293+ . build( )
294+ }
295+ => false ;
296+ "missing `type` field for the latest known document"
297+ ) ]
298+ #[ test_case(
299+ |provider| {
300+ let now = SystemTime :: now( )
301+ . duration_since( SystemTime :: UNIX_EPOCH )
302+ . unwrap( )
303+ . as_secs( ) ;
304+ let id = Uuid :: new_v7( Timestamp :: from_unix_time( now - 1 , 0 , 0 , 0 ) )
305+ . try_into( )
306+ . unwrap( ) ;
307+ let first_doc = Builder :: new( )
308+ . with_metadata_field( SupportedField :: Id ( id) )
309+ . with_metadata_field( SupportedField :: Ver ( id) )
310+ . with_metadata_field( SupportedField :: Type ( UuidV4 :: new( ) . into( ) ) )
311+ . build( ) ;
312+ provider. add_document( None , & first_doc) . unwrap( ) ;
313+
314+ let ver = Uuid :: new_v7( Timestamp :: from_unix_time( now + 1 , 0 , 0 , 0 ) )
315+ . try_into( )
316+ . unwrap( ) ;
317+ Builder :: new( )
318+ . with_metadata_field( SupportedField :: Id ( id) )
319+ . with_metadata_field( SupportedField :: Ver ( ver) )
320+ . with_metadata_field( SupportedField :: Type ( UuidV4 :: new( ) . into( ) ) )
321+ . build( )
322+ }
323+ => false ;
324+ "diverge `type` field with the latest known document"
325+ ) ]
159326 #[ test_case(
160327 |_| {
161328 Builder :: new( )
0 commit comments