1use std::collections::BTreeMap;
5
6use p2panda_rs::document::{DocumentId, DocumentViewFields, DocumentViewId, DocumentViewValue};
7use p2panda_rs::identity::PublicKey;
8use p2panda_rs::operation::traits::AsOperation;
9use p2panda_rs::operation::{
10 OperationAction, OperationBuilder, OperationId, OperationValue, PinnedRelation,
11 PinnedRelationList, Relation, RelationList,
12};
13use p2panda_rs::schema::SchemaId;
14
15use crate::db::models::DocumentViewFieldRow;
16use crate::db::models::OperationFieldsJoinedRow;
17use crate::db::types::StorageOperation;
18
19pub fn parse_operation_rows(
26 operation_rows: Vec<OperationFieldsJoinedRow>,
27) -> Option<StorageOperation> {
28 let first_row = match operation_rows.first() {
29 Some(row) => row,
30 None => return None,
31 };
32
33 let schema_id: SchemaId = first_row.schema_id.parse().unwrap();
35 let public_key = PublicKey::new(&first_row.public_key).unwrap();
36 let operation_id = first_row.operation_id.parse().unwrap();
37 let document_id = first_row.document_id.parse().unwrap();
38 let sorted_index = first_row.sorted_index;
39
40 let mut relation_lists: BTreeMap<String, Vec<DocumentId>> = BTreeMap::new();
41 let mut pinned_relation_lists: BTreeMap<String, Vec<DocumentViewId>> = BTreeMap::new();
42
43 let mut operation_fields = Vec::new();
44
45 if first_row.action != "delete" {
52 operation_rows.iter().for_each(|row| {
53 let field_type = row.field_type.as_ref().unwrap().as_str();
54 let field_name = row.name.as_ref().unwrap();
55 let field_value = row.value.as_ref();
58
59 match field_type {
60 "bool" => {
61 operation_fields.push((
62 field_name.to_string(),
63 OperationValue::Boolean(field_value.unwrap().parse::<bool>().unwrap()),
64 ));
65 }
66 "int" => {
67 operation_fields.push((
68 field_name.to_string(),
69 OperationValue::Integer(field_value.unwrap().parse::<i64>().unwrap()),
70 ));
71 }
72 "float" => {
73 operation_fields.push((
74 field_name.to_string(),
75 OperationValue::Float(field_value.unwrap().parse::<f64>().unwrap()),
76 ));
77 }
78 "str" => {
79 operation_fields.push((
80 field_name.to_string(),
81 OperationValue::String(field_value.unwrap().clone()),
82 ));
83 }
84 "bytes" => {
85 operation_fields.push((
86 field_name.to_string(),
87 OperationValue::Bytes(hex::decode(field_value.unwrap()).expect(
88 "bytes coming from the store are encoded in valid hex strings",
89 )),
90 ));
91 }
92 "relation" => {
93 operation_fields.push((
94 field_name.to_string(),
95 OperationValue::Relation(Relation::new(
96 field_value.unwrap().parse::<DocumentId>().unwrap(),
97 )),
98 ));
99 }
100 "relation_list" => {
103 match relation_lists.get_mut(field_name) {
104 Some(list) => {
107 list.push(field_value.unwrap().parse::<DocumentId>().unwrap())
108 }
109 None => {
110 let list = match field_value {
111 Some(document_id) => {
112 vec![document_id.parse::<DocumentId>().unwrap()]
113 }
114 None => vec![],
115 };
116 relation_lists.insert(field_name.to_string(), list);
117 }
118 };
119 }
120 "pinned_relation" => {
121 operation_fields.push((
122 field_name.to_string(),
123 OperationValue::PinnedRelation(PinnedRelation::new(
124 field_value.unwrap().parse::<DocumentViewId>().unwrap(),
125 )),
126 ));
127 }
128 "pinned_relation_list" => {
131 match pinned_relation_lists.get_mut(field_name) {
132 Some(list) => {
135 list.push(field_value.unwrap().parse::<DocumentViewId>().unwrap())
136 }
137 None => {
138 let list = match field_value {
139 Some(document_view_id) => {
140 vec![document_view_id.parse::<DocumentViewId>().unwrap()]
141 }
142 None => vec![],
143 };
144 pinned_relation_lists.insert(field_name.to_string(), list);
145 }
146 };
147 }
148 _ => (),
149 };
150 })
151 };
152
153 for (field_name, relation_list) in relation_lists {
154 operation_fields.push((
155 field_name,
156 OperationValue::RelationList(RelationList::new(relation_list)),
157 ));
158 }
159
160 for (field_name, pinned_relation_list) in pinned_relation_lists {
161 operation_fields.push((
162 field_name,
163 OperationValue::PinnedRelationList(PinnedRelationList::new(pinned_relation_list)),
164 ));
165 }
166
167 let operation_builder = OperationBuilder::new(&schema_id);
168 let previous = first_row.previous.clone();
169 let previous = previous.map(|previous| previous.parse().unwrap());
170 let fields: Vec<(&str, OperationValue)> = operation_fields
171 .iter()
172 .map(|(name, value)| (name.as_str(), value.to_owned()))
173 .collect();
174
175 let operation = match first_row.action.as_str() {
176 "create" => operation_builder.fields(fields.as_slice()).build(),
177 "update" => operation_builder
178 .action(OperationAction::Update)
179 .fields(fields.as_slice())
180 .previous(previous.as_ref().unwrap())
181 .build(),
182 "delete" => operation_builder
183 .action(OperationAction::Delete)
184 .previous(previous.as_ref().unwrap())
185 .build(),
186 _ => panic!("Operation which was not CREATE, UPDATE or DELETE found."),
187 }
188 .unwrap();
190
191 let operation = StorageOperation {
192 document_id,
193 id: operation_id,
194 version: operation.version(),
195 action: operation.action(),
196 schema_id,
197 previous: operation.previous(),
198 fields: operation.fields(),
199 public_key,
200 sorted_index,
201 };
202
203 Some(operation)
204}
205
206pub fn parse_value_to_string_vec(value: &OperationValue) -> Vec<Option<String>> {
213 match value {
214 OperationValue::Boolean(bool) => vec![Some(bool.to_string())],
215 OperationValue::Integer(int) => vec![Some(int.to_string())],
216 OperationValue::Float(float) => vec![Some(float.to_string())],
217 OperationValue::String(str) => vec![Some(str.to_string())],
218 OperationValue::Relation(relation) => {
219 vec![Some(relation.document_id().as_str().to_string())]
220 }
221 OperationValue::RelationList(relation_list) => {
222 let mut db_values = Vec::new();
223 if relation_list.len() == 0 {
224 db_values.push(None);
225 } else {
226 for document_id in relation_list.iter() {
227 db_values.push(Some(document_id.to_string()))
228 }
229 }
230 db_values
231 }
232 OperationValue::PinnedRelation(pinned_relation) => {
233 vec![Some(pinned_relation.view_id().to_string())]
234 }
235 OperationValue::PinnedRelationList(pinned_relation_list) => {
236 let mut db_values = Vec::new();
237 if pinned_relation_list.len() == 0 {
238 db_values.push(None);
239 } else {
240 for document_view_id in pinned_relation_list.iter() {
241 db_values.push(Some(document_view_id.to_string()))
242 }
243 }
244 db_values
245 }
246 OperationValue::Bytes(bytes) => {
247 vec![Some(hex::encode(bytes))]
249 }
250 }
251}
252
253pub fn parse_document_view_field_rows(
259 document_field_rows: Vec<DocumentViewFieldRow>,
260) -> DocumentViewFields {
261 let mut relation_lists: BTreeMap<String, (OperationId, Vec<DocumentId>)> = BTreeMap::new();
262 let mut pinned_relation_lists: BTreeMap<String, (OperationId, Vec<DocumentViewId>)> =
263 BTreeMap::new();
264
265 let mut document_view_fields = DocumentViewFields::new();
266
267 document_field_rows.iter().for_each(|row| {
274 match row.field_type.as_str() {
275 "bool" => {
276 document_view_fields.insert(
277 &row.name,
278 DocumentViewValue::new(
279 &row.operation_id.parse::<OperationId>().unwrap(),
280 &OperationValue::Boolean(
281 row.value.as_ref().unwrap().parse::<bool>().unwrap(),
282 ),
283 ),
284 );
285 }
286 "int" => {
287 document_view_fields.insert(
288 &row.name,
289 DocumentViewValue::new(
290 &row.operation_id.parse::<OperationId>().unwrap(),
291 &OperationValue::Integer(
292 row.value.as_ref().unwrap().parse::<i64>().unwrap(),
293 ),
294 ),
295 );
296 }
297 "float" => {
298 document_view_fields.insert(
299 &row.name,
300 DocumentViewValue::new(
301 &row.operation_id.parse::<OperationId>().unwrap(),
302 &OperationValue::Float(row.value.as_ref().unwrap().parse::<f64>().unwrap()),
303 ),
304 );
305 }
306 "str" => {
307 document_view_fields.insert(
308 &row.name,
309 DocumentViewValue::new(
310 &row.operation_id.parse::<OperationId>().unwrap(),
311 &OperationValue::String(row.value.as_ref().unwrap().clone()),
312 ),
313 );
314 }
315 "bytes" => {
316 document_view_fields.insert(
317 &row.name,
318 DocumentViewValue::new(
319 &row.operation_id.parse::<OperationId>().unwrap(),
320 &OperationValue::Bytes(
321 hex::decode(row.value.as_ref().unwrap())
322 .expect("bytes coming from the db to be hex encoded"),
323 ),
324 ),
325 );
326 }
327 "relation" => {
328 document_view_fields.insert(
329 &row.name,
330 DocumentViewValue::new(
331 &row.operation_id.parse::<OperationId>().unwrap(),
332 &OperationValue::Relation(Relation::new(
333 row.value.as_ref().unwrap().parse::<DocumentId>().unwrap(),
334 )),
335 ),
336 );
337 }
338 "relation_list" => {
341 match relation_lists.get_mut(&row.name) {
342 Some((_, list)) => {
343 list.push(row.value.as_ref().unwrap().parse::<DocumentId>().unwrap())
344 }
345 None => {
346 let list = match row.value.as_ref() {
347 Some(document_id) => {
348 vec![document_id.parse::<DocumentId>().unwrap()]
349 }
350 None => vec![],
351 };
352 relation_lists
353 .insert(row.name.clone(), (row.operation_id.parse().unwrap(), list));
354 }
355 };
356 }
357 "pinned_relation" => {
358 document_view_fields.insert(
359 &row.name,
360 DocumentViewValue::new(
361 &row.operation_id.parse::<OperationId>().unwrap(),
362 &OperationValue::PinnedRelation(PinnedRelation::new(
363 row.value
364 .as_ref()
365 .unwrap()
366 .parse::<DocumentViewId>()
367 .unwrap(),
368 )),
369 ),
370 );
371 }
372 "pinned_relation_list" => {
375 match pinned_relation_lists.get_mut(&row.name) {
376 Some((_, list)) => list.push(
377 row.value
378 .as_ref()
379 .unwrap()
380 .parse::<DocumentViewId>()
381 .unwrap(),
382 ),
383 None => {
384 let list = match row.value.as_ref() {
385 Some(document_view_id) => {
386 vec![document_view_id.parse::<DocumentViewId>().unwrap()]
387 }
388 None => vec![],
389 };
390 pinned_relation_lists
391 .insert(row.name.clone(), (row.operation_id.parse().unwrap(), list));
392 }
393 };
394 }
395 _ => (),
396 };
397 });
398
399 for (field_name, (operation_id, relation_list)) in relation_lists {
400 document_view_fields.insert(
401 &field_name,
402 DocumentViewValue::new(
403 &operation_id,
404 &OperationValue::RelationList(RelationList::new(relation_list)),
405 ),
406 );
407 }
408
409 for (field_name, (operation_id, pinned_relation_list)) in pinned_relation_lists {
410 document_view_fields.insert(
411 &field_name,
412 DocumentViewValue::new(
413 &operation_id,
414 &OperationValue::PinnedRelationList(PinnedRelationList::new(pinned_relation_list)),
415 ),
416 );
417 }
418
419 document_view_fields
420}
421
422#[cfg(test)]
423mod tests {
424 use std::vec;
425
426 use p2panda_rs::document::DocumentViewValue;
427 use p2panda_rs::operation::traits::AsOperation;
428 use p2panda_rs::operation::{
429 OperationId, OperationValue, PinnedRelation, PinnedRelationList, Relation, RelationList,
430 };
431 use p2panda_rs::schema::SchemaId;
432 use p2panda_rs::test_utils::fixtures::{create_operation, schema_id};
433 use rstest::rstest;
434
435 use crate::db::models::{DocumentViewFieldRow, OperationFieldsJoinedRow};
436 use crate::test_utils::doggo_fields;
437
438 use super::{parse_document_view_field_rows, parse_operation_rows, parse_value_to_string_vec};
439
440 #[test]
441 fn parses_operation_rows() {
442 let operation_rows = vec![
443 OperationFieldsJoinedRow {
444 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
445 .to_string(),
446 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
447 .to_string(),
448 operation_id:
449 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
450 .to_string(),
451 action: "create".to_string(),
452 schema_id:
453 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
454 .to_string(),
455 previous: None,
456 name: Some("age".to_string()),
457 field_type: Some("int".to_string()),
458 value: Some("28".to_string()),
459 list_index: Some(0),
460 sorted_index: None,
461 },
462 OperationFieldsJoinedRow {
463 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
464 .to_string(),
465 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
466 .to_string(),
467 operation_id:
468 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
469 .to_string(),
470 action: "create".to_string(),
471 schema_id:
472 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
473 .to_string(),
474 previous: None,
475 name: Some("data".to_string()),
476 field_type: Some("bytes".to_string()),
477 value: Some("00010203".to_string()),
478 list_index: Some(0),
479 sorted_index: None,
480 },
481 OperationFieldsJoinedRow {
482 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
483 .to_string(),
484 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
485 .to_string(),
486 operation_id:
487 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
488 .to_string(),
489 action: "create".to_string(),
490 schema_id:
491 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
492 .to_string(),
493 previous: None,
494 name: Some("height".to_string()),
495 field_type: Some("float".to_string()),
496 value: Some("3.5".to_string()),
497 list_index: Some(0),
498 sorted_index: None,
499 },
500 OperationFieldsJoinedRow {
501 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
502 .to_string(),
503 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
504 .to_string(),
505 operation_id:
506 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
507 .to_string(),
508 action: "create".to_string(),
509 schema_id:
510 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
511 .to_string(),
512 previous: None,
513 name: Some("is_admin".to_string()),
514 field_type: Some("bool".to_string()),
515 value: Some("false".to_string()),
516 list_index: Some(0),
517 sorted_index: None,
518 },
519 OperationFieldsJoinedRow {
520 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
521 .to_string(),
522 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
523 .to_string(),
524 operation_id:
525 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
526 .to_string(),
527 action: "create".to_string(),
528 schema_id:
529 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
530 .to_string(),
531 previous: None,
532 name: Some("many_profile_pictures".to_string()),
533 field_type: Some("relation_list".to_string()),
534 value: Some(
535 "0020aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
536 .to_string(),
537 ),
538 list_index: Some(0),
539 sorted_index: None,
540 },
541 OperationFieldsJoinedRow {
542 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
543 .to_string(),
544 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
545 .to_string(),
546 operation_id:
547 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
548 .to_string(),
549 action: "create".to_string(),
550 schema_id:
551 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
552 .to_string(),
553 previous: None,
554 name: Some("many_profile_pictures".to_string()),
555 field_type: Some("relation_list".to_string()),
556 value: Some(
557 "0020bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
558 .to_string(),
559 ),
560 list_index: Some(1),
561 sorted_index: None,
562 },
563 OperationFieldsJoinedRow {
564 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
565 .to_string(),
566 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
567 .to_string(),
568 operation_id:
569 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
570 .to_string(),
571 action: "create".to_string(),
572 schema_id:
573 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
574 .to_string(),
575 previous: None,
576 name: Some("many_special_profile_pictures".to_string()),
577 field_type: Some("pinned_relation_list".to_string()),
578 value: Some(
579 "0020cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
580 .to_string(),
581 ),
582 list_index: Some(0),
583 sorted_index: None,
584 },
585 OperationFieldsJoinedRow {
586 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
587 .to_string(),
588 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
589 .to_string(),
590 operation_id:
591 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
592 .to_string(),
593 action: "create".to_string(),
594 schema_id:
595 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
596 .to_string(),
597 previous: None,
598 name: Some("many_special_profile_pictures".to_string()),
599 field_type: Some("pinned_relation_list".to_string()),
600 value: Some(
601 "0020dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
602 .to_string(),
603 ),
604 list_index: Some(1),
605 sorted_index: None,
606 },
607 OperationFieldsJoinedRow {
608 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
609 .to_string(),
610 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
611 .to_string(),
612 operation_id:
613 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
614 .to_string(),
615 action: "create".to_string(),
616 schema_id:
617 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
618 .to_string(),
619 previous: None,
620 name: Some("many_special_dog_pictures".to_string()),
621 field_type: Some("pinned_relation_list".to_string()),
622 value: Some(
623 "0020bcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbc"
624 .to_string(),
625 ),
626 list_index: Some(0),
627 sorted_index: None,
628 },
629 OperationFieldsJoinedRow {
630 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
631 .to_string(),
632 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
633 .to_string(),
634 operation_id:
635 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
636 .to_string(),
637 action: "create".to_string(),
638 schema_id:
639 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
640 .to_string(),
641 previous: None,
642 name: Some("many_special_dog_pictures".to_string()),
643 field_type: Some("pinned_relation_list".to_string()),
644 value: Some(
645 "0020abababababababababababababababababababababababababababababababab"
646 .to_string(),
647 ),
648 list_index: Some(1),
649 sorted_index: None,
650 },
651 OperationFieldsJoinedRow {
652 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
653 .to_string(),
654 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
655 .to_string(),
656 operation_id:
657 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
658 .to_string(),
659 action: "create".to_string(),
660 schema_id:
661 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
662 .to_string(),
663 previous: None,
664 name: Some("profile_picture".to_string()),
665 field_type: Some("relation".to_string()),
666 value: Some(
667 "0020eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
668 .to_string(),
669 ),
670 list_index: Some(0),
671 sorted_index: None,
672 },
673 OperationFieldsJoinedRow {
674 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
675 .to_string(),
676 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
677 .to_string(),
678 operation_id:
679 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
680 .to_string(),
681 action: "create".to_string(),
682 schema_id:
683 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
684 .to_string(),
685 previous: None,
686 name: Some("special_profile_picture".to_string()),
687 field_type: Some("pinned_relation".to_string()),
688 value: Some(
689 "0020ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
690 .to_string(),
691 ),
692 list_index: Some(0),
693 sorted_index: None,
694 },
695 OperationFieldsJoinedRow {
696 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
697 .to_string(),
698 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
699 .to_string(),
700 operation_id:
701 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
702 .to_string(),
703 action: "create".to_string(),
704 schema_id:
705 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
706 .to_string(),
707 previous: None,
708 name: Some("username".to_string()),
709 field_type: Some("str".to_string()),
710 value: Some("bubu".to_string()),
711 list_index: Some(0),
712 sorted_index: None,
713 },
714 OperationFieldsJoinedRow {
715 public_key: "2f8e50c2ede6d936ecc3144187ff1c273808185cfbc5ff3d3748d1ff7353fc96"
716 .to_string(),
717 document_id: "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
718 .to_string(),
719 operation_id:
720 "0020b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543"
721 .to_string(),
722 action: "create".to_string(),
723 schema_id:
724 "venue_0020c65567ae37efea293e34a9c7d13f8f2bf23dbdc3b5c7b9ab46293111c48fc78b"
725 .to_string(),
726 previous: None,
727 name: Some("an_empty_relation_list".to_string()),
728 field_type: Some("pinned_relation_list".to_string()),
729 value: None,
730 list_index: Some(0),
731 sorted_index: None,
732 },
733 ];
734
735 let operation = parse_operation_rows(operation_rows).unwrap();
736
737 assert_eq!(
738 operation.fields().unwrap().get("username").unwrap(),
739 &OperationValue::String("bubu".to_string())
740 );
741 assert_eq!(
742 operation.fields().unwrap().get("data").unwrap(),
743 &OperationValue::Bytes(vec![0, 1, 2, 3])
744 );
745 assert_eq!(
746 operation.fields().unwrap().get("age").unwrap(),
747 &OperationValue::Integer(28)
748 );
749 assert_eq!(
750 operation.fields().unwrap().get("height").unwrap(),
751 &OperationValue::Float(3.5)
752 );
753 assert_eq!(
754 operation.fields().unwrap().get("is_admin").unwrap(),
755 &OperationValue::Boolean(false)
756 );
757 assert_eq!(
758 operation
759 .fields()
760 .unwrap()
761 .get("many_profile_pictures")
762 .unwrap(),
763 &OperationValue::RelationList(RelationList::new(vec![
764 "0020aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
765 .parse()
766 .unwrap(),
767 "0020bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
768 .parse()
769 .unwrap(),
770 ]))
771 );
772 assert_eq!(
773 operation
774 .fields()
775 .unwrap()
776 .get("many_special_profile_pictures")
777 .unwrap(),
778 &OperationValue::PinnedRelationList(PinnedRelationList::new(vec![
779 "0020cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
780 .parse()
781 .unwrap(),
782 "0020dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
783 .parse()
784 .unwrap(),
785 ]))
786 );
787 assert_eq!(
788 operation
789 .fields()
790 .unwrap()
791 .get("many_special_dog_pictures")
792 .unwrap(),
793 &OperationValue::PinnedRelationList(PinnedRelationList::new(vec![
794 "0020bcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbc"
795 .parse()
796 .unwrap(),
797 "0020abababababababababababababababababababababababababababababababab"
798 .parse()
799 .unwrap(),
800 ]))
801 );
802
803 assert_eq!(
804 operation.fields().unwrap().get("profile_picture").unwrap(),
805 &OperationValue::Relation(Relation::new(
806 "0020eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
807 .parse()
808 .unwrap()
809 ))
810 );
811 assert_eq!(
812 operation
813 .fields()
814 .unwrap()
815 .get("special_profile_picture")
816 .unwrap(),
817 &OperationValue::PinnedRelation(PinnedRelation::new(
818 "0020ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
819 .parse()
820 .unwrap()
821 ))
822 );
823 assert_eq!(
824 operation
825 .fields()
826 .unwrap()
827 .get("an_empty_relation_list")
828 .unwrap(),
829 &OperationValue::PinnedRelationList(PinnedRelationList::new(vec![]))
830 )
831 }
832
833 #[rstest]
834 fn operation_values_to_string_vec(schema_id: SchemaId) {
835 let expected_list = vec![
836 Some("28".into()),
837 None, Some("0020abababababababababababababababababababababababababababababababab".into()),
839 Some("0020cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd".into()),
840 Some("00010203".into()),
841 Some("3.5".into()),
842 Some("false".into()),
843 Some("0020aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".into()),
844 Some("0020bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb".into()),
845 Some("0020cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc".into()),
846 Some("0020dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd".into()),
847 Some("0020eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee".into()),
848 Some("0020ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".into()),
849 Some("bubu".into()),
850 ];
851
852 let operation = create_operation(doggo_fields(), schema_id);
853
854 let mut string_value_list = vec![];
855 for (_, value) in operation.fields().unwrap().iter() {
856 string_value_list.push(parse_value_to_string_vec(value));
857 }
858
859 let string_value_list: Vec<Option<String>> =
860 string_value_list.into_iter().flatten().collect();
861 assert_eq!(expected_list, string_value_list)
862 }
863
864 #[rstest]
865 fn parses_empty_relation_lists_correctly(schema_id: SchemaId) {
866 let expected_list = vec![None];
867
868 let operation = create_operation(
869 vec![(
870 "field_name",
871 OperationValue::RelationList(RelationList::new(vec![])),
872 )],
873 schema_id,
874 );
875
876 let mut string_value_list = vec![];
877 for (_, value) in operation.fields().unwrap().iter() {
878 string_value_list.push(parse_value_to_string_vec(value));
879 }
880
881 let string_value_list: Vec<Option<String>> =
882 string_value_list.into_iter().flatten().collect();
883 assert_eq!(expected_list, string_value_list)
884 }
885
886 #[test]
887 fn parses_document_field_rows() {
888 let document_id =
889 "0020713b2777f1222660291cb528d220c358920b4beddc1aea9df88a69cec45a10c0".to_string();
890 let operation_id =
891 "0020dc8fe1cbacac4d411ae25ea264369a7b2dabdfb617129dec03b6661edd963770".to_string();
892 let document_view_id = operation_id.clone();
893
894 let document_field_rows = vec![
895 DocumentViewFieldRow {
896 document_id: document_id.clone(),
897 document_view_id: document_view_id.clone(),
898 operation_id: operation_id.clone(),
899 name: "age".to_string(),
900 list_index: 0,
901 field_type: "int".to_string(),
902 value: Some("28".to_string()),
903 },
904 DocumentViewFieldRow {
905 document_id: document_id.clone(),
906 document_view_id: document_view_id.clone(),
907 operation_id: operation_id.clone(),
908 name: "height".to_string(),
909 list_index: 0,
910 field_type: "float".to_string(),
911 value: Some("3.5".to_string()),
912 },
913 DocumentViewFieldRow {
914 document_id: document_id.clone(),
915 document_view_id: document_view_id.clone(),
916 operation_id: operation_id.clone(),
917 name: "is_admin".to_string(),
918 list_index: 0,
919 field_type: "bool".to_string(),
920 value: Some("false".to_string()),
921 },
922 DocumentViewFieldRow {
923 document_id: document_id.clone(),
924 document_view_id: document_view_id.clone(),
925 operation_id: operation_id.clone(),
926 name: "many_profile_pictures".to_string(),
927 list_index: 0,
928 field_type: "relation_list".to_string(),
929 value: Some(
930 "0020aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
931 .to_string(),
932 ),
933 },
934 DocumentViewFieldRow {
935 document_id: document_id.clone(),
936 document_view_id: document_view_id.clone(),
937 operation_id: operation_id.clone(),
938 name: "many_profile_pictures".to_string(),
939 list_index: 1,
940 field_type: "relation_list".to_string(),
941 value: Some(
942 "0020bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
943 .to_string(),
944 ),
945 },
946 DocumentViewFieldRow {
947 document_id: document_id.clone(),
948 document_view_id: document_view_id.clone(),
949 operation_id: operation_id.clone(),
950 name: "many_special_profile_pictures".to_string(),
951 list_index: 0,
952 field_type: "pinned_relation_list".to_string(),
953 value: Some(
954 "0020cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
955 .to_string(),
956 ),
957 },
958 DocumentViewFieldRow {
959 document_id: document_id.clone(),
960 document_view_id: document_view_id.clone(),
961 operation_id: operation_id.clone(),
962 name: "many_special_profile_pictures".to_string(),
963 list_index: 1,
964 field_type: "pinned_relation_list".to_string(),
965 value: Some(
966 "0020dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
967 .to_string(),
968 ),
969 },
970 DocumentViewFieldRow {
971 document_id: document_id.clone(),
972 document_view_id: document_view_id.clone(),
973 operation_id: operation_id.clone(),
974 name: "profile_picture".to_string(),
975 list_index: 0,
976 field_type: "relation".to_string(),
977 value: Some(
978 "0020eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
979 .to_string(),
980 ),
981 },
982 DocumentViewFieldRow {
983 document_id: document_id.clone(),
984 document_view_id: document_view_id.clone(),
985 operation_id: operation_id.clone(),
986 name: "special_profile_picture".to_string(),
987 list_index: 0,
988 field_type: "pinned_relation".to_string(),
989 value: Some(
990 "0020ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
991 .to_string(),
992 ),
993 },
994 DocumentViewFieldRow {
995 document_id: document_id.clone(),
996 document_view_id: document_view_id.clone(),
997 operation_id: operation_id.clone(),
998 name: "username".to_string(),
999 list_index: 0,
1000 field_type: "str".to_string(),
1001 value: Some("bubu".to_string()),
1002 },
1003 DocumentViewFieldRow {
1004 document_id: document_id.clone(),
1005 document_view_id: document_view_id.clone(),
1006 operation_id: operation_id.clone(),
1007 name: "data".to_string(),
1008 list_index: 0,
1009 field_type: "bytes".to_string(),
1010 value: Some("00010203".to_string()),
1011 },
1012 DocumentViewFieldRow {
1013 document_id: document_id.clone(),
1014 document_view_id: document_view_id.clone(),
1015 operation_id: operation_id.clone(),
1016 name: "an_empty_relation_list".to_string(),
1017 list_index: 0,
1018 field_type: "pinned_relation_list".to_string(),
1019 value: None,
1020 },
1021 ];
1022
1023 let document_fields = parse_document_view_field_rows(document_field_rows);
1024 let operation_id: OperationId =
1025 "0020dc8fe1cbacac4d411ae25ea264369a7b2dabdfb617129dec03b6661edd963770"
1026 .parse()
1027 .unwrap();
1028
1029 assert_eq!(
1030 document_fields.get("username").unwrap(),
1031 &DocumentViewValue::new(&operation_id, &OperationValue::String("bubu".to_string()))
1032 );
1033 assert_eq!(
1034 document_fields.get("data").unwrap(),
1035 &DocumentViewValue::new(&operation_id, &OperationValue::Bytes(vec![0, 1, 2, 3]))
1036 );
1037 assert_eq!(
1038 document_fields.get("age").unwrap(),
1039 &DocumentViewValue::new(&operation_id, &OperationValue::Integer(28))
1040 );
1041 assert_eq!(
1042 document_fields.get("height").unwrap(),
1043 &DocumentViewValue::new(&operation_id, &OperationValue::Float(3.5))
1044 );
1045 assert_eq!(
1046 document_fields.get("is_admin").unwrap(),
1047 &DocumentViewValue::new(&operation_id, &OperationValue::Boolean(false))
1048 );
1049 assert_eq!(
1050 document_fields.get("many_profile_pictures").unwrap(),
1051 &DocumentViewValue::new(
1052 &operation_id,
1053 &OperationValue::RelationList(RelationList::new(vec![
1054 "0020aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
1055 .parse()
1056 .unwrap(),
1057 "0020bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
1058 .parse()
1059 .unwrap(),
1060 ]))
1061 )
1062 );
1063 assert_eq!(
1064 document_fields
1065 .get("many_special_profile_pictures")
1066 .unwrap(),
1067 &DocumentViewValue::new(
1068 &operation_id,
1069 &OperationValue::PinnedRelationList(PinnedRelationList::new(vec![
1070 "0020cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
1071 .parse()
1072 .unwrap(),
1073 "0020dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
1074 .parse()
1075 .unwrap(),
1076 ]))
1077 )
1078 );
1079 assert_eq!(
1080 document_fields.get("profile_picture").unwrap(),
1081 &DocumentViewValue::new(
1082 &operation_id,
1083 &OperationValue::Relation(Relation::new(
1084 "0020eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
1085 .parse()
1086 .unwrap()
1087 ))
1088 )
1089 );
1090 assert_eq!(
1091 document_fields.get("special_profile_picture").unwrap(),
1092 &DocumentViewValue::new(
1093 &operation_id,
1094 &OperationValue::PinnedRelation(PinnedRelation::new(
1095 "0020ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1096 .parse()
1097 .unwrap()
1098 ))
1099 )
1100 );
1101 assert_eq!(
1102 document_fields.get("an_empty_relation_list").unwrap(),
1103 &DocumentViewValue::new(
1104 &operation_id,
1105 &OperationValue::PinnedRelationList(PinnedRelationList::new(vec![]))
1106 )
1107 )
1108 }
1109}