grid_sdk/protocol/schema/
payload.rs1use protobuf::Message;
18use protobuf::RepeatedField;
19
20use std::error::Error as StdError;
21
22use crate::protocol::schema::state::PropertyDefinition;
23use crate::protos;
24use crate::protos::{
25 FromBytes, FromNative, FromProto, IntoBytes, IntoNative, IntoProto, ProtoConversionError,
26};
27
28#[derive(Debug, Clone, PartialEq)]
30pub enum Action {
31 SchemaCreate(SchemaCreateAction),
32 SchemaUpdate(SchemaUpdateAction),
33}
34
35#[derive(Debug, Clone, PartialEq)]
37pub struct SchemaPayload {
38 action: Action,
39}
40
41impl SchemaPayload {
42 pub fn action(&self) -> &Action {
43 &self.action
44 }
45}
46
47impl FromProto<protos::schema_payload::SchemaPayload> for SchemaPayload {
48 fn from_proto(
49 payload: protos::schema_payload::SchemaPayload,
50 ) -> Result<Self, ProtoConversionError> {
51 let action = match payload.get_action() {
52 protos::schema_payload::SchemaPayload_Action::SCHEMA_CREATE => Action::SchemaCreate(
53 SchemaCreateAction::from_proto(payload.get_schema_create().clone())?,
54 ),
55 protos::schema_payload::SchemaPayload_Action::SCHEMA_UPDATE => Action::SchemaUpdate(
56 SchemaUpdateAction::from_proto(payload.get_schema_update().clone())?,
57 ),
58 protos::schema_payload::SchemaPayload_Action::UNSET_ACTION => {
59 return Err(ProtoConversionError::InvalidTypeError(
60 "Cannot convert SchemaPayload_Action with type unset.".to_string(),
61 ));
62 }
63 };
64 Ok(SchemaPayload { action })
65 }
66}
67
68impl FromNative<SchemaPayload> for protos::schema_payload::SchemaPayload {
69 fn from_native(payload: SchemaPayload) -> Result<Self, ProtoConversionError> {
70 let mut proto_payload = protos::schema_payload::SchemaPayload::new();
71 match payload.action() {
72 Action::SchemaCreate(payload) => {
73 proto_payload
74 .set_action(protos::schema_payload::SchemaPayload_Action::SCHEMA_CREATE);
75 proto_payload.set_schema_create(payload.clone().into_proto()?);
76 }
77 Action::SchemaUpdate(payload) => {
78 proto_payload
79 .set_action(protos::schema_payload::SchemaPayload_Action::SCHEMA_UPDATE);
80 proto_payload.set_schema_update(payload.clone().into_proto()?);
81 }
82 }
83 Ok(proto_payload)
84 }
85}
86
87impl FromBytes<SchemaPayload> for SchemaPayload {
88 fn from_bytes(bytes: &[u8]) -> Result<SchemaPayload, ProtoConversionError> {
89 let proto: protos::schema_payload::SchemaPayload = Message::parse_from_bytes(bytes)
90 .map_err(|_| {
91 ProtoConversionError::SerializationError(
92 "Unable to get SchemaPayload from bytes".to_string(),
93 )
94 })?;
95 proto.into_native()
96 }
97}
98
99impl IntoBytes for SchemaPayload {
100 fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
101 let proto = self.into_proto()?;
102 let bytes = proto.write_to_bytes().map_err(|_| {
103 ProtoConversionError::SerializationError(
104 "Unable to get bytes from SchemaPayload".to_string(),
105 )
106 })?;
107 Ok(bytes)
108 }
109}
110
111impl IntoProto<protos::schema_payload::SchemaPayload> for SchemaPayload {}
112impl IntoNative<SchemaPayload> for protos::schema_payload::SchemaPayload {}
113
114#[derive(Debug)]
117pub enum SchemaPayloadBuildError {
118 MissingField(String),
119}
120
121impl StdError for SchemaPayloadBuildError {
122 fn description(&self) -> &str {
123 match *self {
124 SchemaPayloadBuildError::MissingField(ref msg) => msg,
125 }
126 }
127
128 fn cause(&self) -> Option<&dyn StdError> {
129 match *self {
130 SchemaPayloadBuildError::MissingField(_) => None,
131 }
132 }
133}
134
135impl std::fmt::Display for SchemaPayloadBuildError {
136 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
137 match *self {
138 SchemaPayloadBuildError::MissingField(ref s) => write!(f, "MissingField: {}", s),
139 }
140 }
141}
142
143#[derive(Default, Clone)]
145pub struct SchemaPayloadBuilder {
146 action: Option<Action>,
147}
148
149impl SchemaPayloadBuilder {
150 pub fn new() -> Self {
151 SchemaPayloadBuilder::default()
152 }
153
154 pub fn with_action(mut self, action: Action) -> SchemaPayloadBuilder {
155 self.action = Some(action);
156 self
157 }
158
159 pub fn build(self) -> Result<SchemaPayload, SchemaPayloadBuildError> {
160 let action = self.action.ok_or_else(|| {
161 SchemaPayloadBuildError::MissingField("'action' field is required".to_string())
162 })?;
163 Ok(SchemaPayload { action })
164 }
165}
166
167#[derive(Debug, Default, Clone, PartialEq)]
169pub struct SchemaCreateAction {
170 schema_name: String,
171 owner: String,
172 description: String,
173 properties: Vec<PropertyDefinition>,
174}
175
176impl SchemaCreateAction {
177 pub fn schema_name(&self) -> &str {
178 &self.schema_name
179 }
180
181 pub fn owner(&self) -> &str {
182 &self.owner
183 }
184
185 pub fn description(&self) -> &str {
186 &self.description
187 }
188
189 pub fn properties(&self) -> &[PropertyDefinition] {
190 &self.properties
191 }
192}
193
194impl FromProto<protos::schema_payload::SchemaCreateAction> for SchemaCreateAction {
195 fn from_proto(
196 schema_create: protos::schema_payload::SchemaCreateAction,
197 ) -> Result<Self, ProtoConversionError> {
198 Ok(SchemaCreateAction {
199 schema_name: schema_create.get_schema_name().to_string(),
200 owner: schema_create.get_owner().to_string(),
201 description: schema_create.get_description().to_string(),
202 properties: schema_create
203 .get_properties()
204 .iter()
205 .cloned()
206 .map(PropertyDefinition::from_proto)
207 .collect::<Result<Vec<PropertyDefinition>, ProtoConversionError>>()?,
208 })
209 }
210}
211
212impl FromNative<SchemaCreateAction> for protos::schema_payload::SchemaCreateAction {
213 fn from_native(schema_create: SchemaCreateAction) -> Result<Self, ProtoConversionError> {
214 let mut proto_schema_create = protos::schema_payload::SchemaCreateAction::new();
215
216 proto_schema_create.set_schema_name(schema_create.schema_name().to_string());
217 proto_schema_create.set_owner(schema_create.owner().to_string());
218 proto_schema_create.set_description(schema_create.description().to_string());
219 proto_schema_create.set_properties(
220 RepeatedField::from_vec(
221 schema_create.properties().iter().cloned()
222 .map(PropertyDefinition::into_proto)
223 .collect::<Result<Vec<protos::schema_state::PropertyDefinition>, ProtoConversionError>>()?,));
224
225 Ok(proto_schema_create)
226 }
227}
228
229impl FromBytes<SchemaCreateAction> for SchemaCreateAction {
230 fn from_bytes(bytes: &[u8]) -> Result<SchemaCreateAction, ProtoConversionError> {
231 let proto: protos::schema_payload::SchemaCreateAction = Message::parse_from_bytes(bytes)
232 .map_err(|_| {
233 ProtoConversionError::SerializationError(
234 "Unable to get SchemaCreateAction from bytes".to_string(),
235 )
236 })?;
237 proto.into_native()
238 }
239}
240
241impl IntoBytes for SchemaCreateAction {
242 fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
243 let proto = self.into_proto()?;
244 let bytes = proto.write_to_bytes().map_err(|_| {
245 ProtoConversionError::SerializationError(
246 "Unable to get bytes from SchemaCreateAction".to_string(),
247 )
248 })?;
249 Ok(bytes)
250 }
251}
252
253impl IntoProto<protos::schema_payload::SchemaCreateAction> for SchemaCreateAction {}
254impl IntoNative<SchemaCreateAction> for protos::schema_payload::SchemaCreateAction {}
255
256#[derive(Debug)]
259pub enum SchemaCreateBuildError {
260 MissingField(String),
261}
262
263impl StdError for SchemaCreateBuildError {
264 fn description(&self) -> &str {
265 match *self {
266 SchemaCreateBuildError::MissingField(ref msg) => msg,
267 }
268 }
269
270 fn cause(&self) -> Option<&dyn StdError> {
271 match *self {
272 SchemaCreateBuildError::MissingField(_) => None,
273 }
274 }
275}
276
277impl std::fmt::Display for SchemaCreateBuildError {
278 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
279 match *self {
280 SchemaCreateBuildError::MissingField(ref s) => write!(f, "MissingField: {}", s),
281 }
282 }
283}
284
285#[derive(Default, Clone)]
287pub struct SchemaCreateBuilder {
288 schema_name: Option<String>,
289 owner: Option<String>,
290 description: Option<String>,
291 properties: Vec<PropertyDefinition>,
292}
293
294impl SchemaCreateBuilder {
295 pub fn new() -> Self {
296 SchemaCreateBuilder::default()
297 }
298
299 pub fn with_schema_name(mut self, schema_name: String) -> SchemaCreateBuilder {
300 self.schema_name = Some(schema_name);
301 self
302 }
303
304 pub fn with_owner(mut self, owner: String) -> SchemaCreateBuilder {
305 self.owner = Some(owner);
306 self
307 }
308
309 pub fn with_description(mut self, description: String) -> SchemaCreateBuilder {
310 self.description = Some(description);
311 self
312 }
313
314 pub fn with_properties(mut self, properties: Vec<PropertyDefinition>) -> SchemaCreateBuilder {
315 self.properties = properties;
316 self
317 }
318
319 pub fn build(self) -> Result<SchemaCreateAction, SchemaCreateBuildError> {
320 let schema_name = self.schema_name.ok_or_else(|| {
321 SchemaCreateBuildError::MissingField("'schema_name' field is required".to_string())
322 })?;
323
324 let owner = self.owner.ok_or_else(|| {
325 SchemaCreateBuildError::MissingField("'owner' field is required".to_string())
326 })?;
327
328 let description = self.description.unwrap_or_default();
329
330 let properties = {
331 if !self.properties.is_empty() {
332 self.properties
333 } else {
334 return Err(SchemaCreateBuildError::MissingField(
335 "'properties' field is required".to_string(),
336 ));
337 }
338 };
339
340 Ok(SchemaCreateAction {
341 schema_name,
342 owner,
343 description,
344 properties,
345 })
346 }
347}
348
349#[derive(Debug, Default, Clone, PartialEq)]
351pub struct SchemaUpdateAction {
352 schema_name: String,
353 owner: String,
354 properties: Vec<PropertyDefinition>,
355}
356
357impl SchemaUpdateAction {
358 pub fn schema_name(&self) -> &str {
359 &self.schema_name
360 }
361
362 pub fn owner(&self) -> &str {
363 &self.owner
364 }
365
366 pub fn properties(&self) -> &[PropertyDefinition] {
367 &self.properties
368 }
369}
370
371impl FromProto<protos::schema_payload::SchemaUpdateAction> for SchemaUpdateAction {
372 fn from_proto(
373 schema_update: protos::schema_payload::SchemaUpdateAction,
374 ) -> Result<Self, ProtoConversionError> {
375 Ok(SchemaUpdateAction {
376 schema_name: schema_update.get_schema_name().to_string(),
377 owner: schema_update.get_owner().to_string(),
378 properties: schema_update
379 .get_properties()
380 .iter()
381 .cloned()
382 .map(PropertyDefinition::from_proto)
383 .collect::<Result<Vec<PropertyDefinition>, ProtoConversionError>>()?,
384 })
385 }
386}
387
388impl FromNative<SchemaUpdateAction> for protos::schema_payload::SchemaUpdateAction {
389 fn from_native(schema_update: SchemaUpdateAction) -> Result<Self, ProtoConversionError> {
390 let mut proto_schema_update = protos::schema_payload::SchemaUpdateAction::new();
391
392 proto_schema_update.set_schema_name(schema_update.schema_name().to_string());
393 proto_schema_update.set_owner(schema_update.owner().to_string());
394 proto_schema_update.set_properties(
395 RepeatedField::from_vec(
396 schema_update.properties().iter().cloned()
397 .map(PropertyDefinition::into_proto)
398 .collect::<Result<Vec<protos::schema_state::PropertyDefinition>, ProtoConversionError>>()?,));
399
400 Ok(proto_schema_update)
401 }
402}
403
404impl FromBytes<SchemaUpdateAction> for SchemaUpdateAction {
405 fn from_bytes(bytes: &[u8]) -> Result<SchemaUpdateAction, ProtoConversionError> {
406 let proto: protos::schema_payload::SchemaUpdateAction = Message::parse_from_bytes(bytes)
407 .map_err(|_| {
408 ProtoConversionError::SerializationError(
409 "Unable to get SchemaUpdateAction from bytes".to_string(),
410 )
411 })?;
412 proto.into_native()
413 }
414}
415
416impl IntoBytes for SchemaUpdateAction {
417 fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
418 let proto = self.into_proto()?;
419 let bytes = proto.write_to_bytes().map_err(|_| {
420 ProtoConversionError::SerializationError(
421 "Unable to get bytes from SchemaUpdateAction".to_string(),
422 )
423 })?;
424 Ok(bytes)
425 }
426}
427
428impl IntoProto<protos::schema_payload::SchemaUpdateAction> for SchemaUpdateAction {}
429impl IntoNative<SchemaUpdateAction> for protos::schema_payload::SchemaUpdateAction {}
430
431#[derive(Debug)]
434pub enum SchemaUpdateBuildError {
435 MissingField(String),
436}
437
438impl StdError for SchemaUpdateBuildError {
439 fn description(&self) -> &str {
440 match *self {
441 SchemaUpdateBuildError::MissingField(ref msg) => msg,
442 }
443 }
444
445 fn cause(&self) -> Option<&dyn StdError> {
446 match *self {
447 SchemaUpdateBuildError::MissingField(_) => None,
448 }
449 }
450}
451
452impl std::fmt::Display for SchemaUpdateBuildError {
453 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
454 match *self {
455 SchemaUpdateBuildError::MissingField(ref s) => write!(f, "MissingField: {}", s),
456 }
457 }
458}
459
460#[derive(Default, Clone)]
462pub struct SchemaUpdateBuilder {
463 schema_name: Option<String>,
464 owner: Option<String>,
465 properties: Vec<PropertyDefinition>,
466}
467
468impl SchemaUpdateBuilder {
469 pub fn new() -> Self {
470 SchemaUpdateBuilder::default()
471 }
472
473 pub fn with_schema_name(mut self, schema_name: String) -> SchemaUpdateBuilder {
474 self.schema_name = Some(schema_name);
475 self
476 }
477
478 pub fn with_owner(mut self, owner: String) -> SchemaUpdateBuilder {
479 self.owner = Some(owner);
480 self
481 }
482
483 pub fn with_properties(mut self, properties: Vec<PropertyDefinition>) -> SchemaUpdateBuilder {
484 self.properties = properties;
485 self
486 }
487
488 pub fn build(self) -> Result<SchemaUpdateAction, SchemaUpdateBuildError> {
489 let schema_name = self.schema_name.ok_or_else(|| {
490 SchemaUpdateBuildError::MissingField("'schema field is required".to_string())
491 })?;
492
493 let owner = self.owner.ok_or_else(|| {
494 SchemaUpdateBuildError::MissingField("'owner field is required".to_string())
495 })?;
496
497 let properties = {
498 if !self.properties.is_empty() {
499 self.properties
500 } else {
501 return Err(SchemaUpdateBuildError::MissingField(
502 "'properties' field is required".to_string(),
503 ));
504 }
505 };
506
507 Ok(SchemaUpdateAction {
508 schema_name,
509 owner,
510 properties,
511 })
512 }
513}
514
515#[cfg(test)]
516mod tests {
517 use super::*;
518 use crate::protocol::schema::state::{DataType, PropertyDefinitionBuilder};
519
520 #[test]
521 fn check_schema_create_action() {
523 let builder = PropertyDefinitionBuilder::new();
524 let property_definition = builder
525 .with_name("TEST".to_string())
526 .with_data_type(DataType::String)
527 .with_description("Optional".to_string())
528 .build()
529 .unwrap();
530
531 let builder = SchemaCreateBuilder::new();
532 let action = builder
533 .with_schema_name("TestSchema".to_string())
534 .with_owner("test_org".to_string())
535 .with_description("Test Schema".to_string())
536 .with_properties(vec![property_definition.clone()])
537 .build()
538 .unwrap();
539
540 assert_eq!(action.schema_name, "TestSchema");
541 assert_eq!(action.description, "Test Schema");
542 assert_eq!(action.properties, vec![property_definition]);
543 }
544
545 #[test]
546 fn check_schema_create_bytes() {
549 let builder = PropertyDefinitionBuilder::new();
550 let property_definition = builder
551 .with_name("TEST".to_string())
552 .with_data_type(DataType::String)
553 .with_description("Optional".to_string())
554 .build()
555 .unwrap();
556
557 let builder = SchemaCreateBuilder::new();
558 let original = builder
559 .with_schema_name("TestSchema".to_string())
560 .with_owner("test_org".to_string())
561 .with_description("Test Schema".to_string())
562 .with_properties(vec![property_definition.clone()])
563 .build()
564 .unwrap();
565
566 let bytes = original.clone().into_bytes().unwrap();
567
568 let create = SchemaCreateAction::from_bytes(&bytes).unwrap();
569 assert_eq!(create, original);
570 }
571
572 #[test]
573 fn check_schema_update_action() {
575 let builder = PropertyDefinitionBuilder::new();
576 let property_definition = builder
577 .with_name("TEST".to_string())
578 .with_data_type(DataType::String)
579 .with_description("Optional".to_string())
580 .build()
581 .unwrap();
582
583 let builder = SchemaUpdateBuilder::new();
584 let action = builder
585 .with_schema_name("TestSchema".to_string())
586 .with_owner("test_org".to_string())
587 .with_properties(vec![property_definition.clone()])
588 .build()
589 .unwrap();
590
591 assert_eq!(action.schema_name, "TestSchema");
592 assert_eq!(action.properties, vec![property_definition]);
593 }
594
595 #[test]
596 fn check_schema_update_bytes() {
599 let builder = PropertyDefinitionBuilder::new();
600 let property_definition = builder
601 .with_name("TEST".to_string())
602 .with_data_type(DataType::String)
603 .with_description("Optional".to_string())
604 .build()
605 .unwrap();
606
607 let builder = SchemaUpdateBuilder::new();
608 let original = builder
609 .with_schema_name("TestSchema".to_string())
610 .with_owner("test_org".to_string())
611 .with_properties(vec![property_definition.clone()])
612 .build()
613 .unwrap();
614
615 let bytes = original.clone().into_bytes().unwrap();
616
617 let update = SchemaUpdateAction::from_bytes(&bytes).unwrap();
618 assert_eq!(update, original);
619 }
620
621 #[test]
622 fn check_schema_create_action_payload() {
624 let builder = PropertyDefinitionBuilder::new();
625 let property_definition = builder
626 .with_name("TEST".to_string())
627 .with_data_type(DataType::String)
628 .with_description("Optional".to_string())
629 .build()
630 .unwrap();
631
632 let builder = SchemaCreateBuilder::new();
633 let action = builder
634 .with_schema_name("TestSchema".to_string())
635 .with_owner("test_org".to_string())
636 .with_description("Test Schema".to_string())
637 .with_properties(vec![property_definition.clone()])
638 .build()
639 .unwrap();
640
641 let builder = SchemaPayloadBuilder::new();
642 let payload = builder
643 .with_action(Action::SchemaCreate(action.clone()))
644 .build()
645 .unwrap();
646
647 assert_eq!(payload.action, Action::SchemaCreate(action));
648 }
649
650 #[test]
651 fn check_schema_update_action_payload() {
653 let builder = PropertyDefinitionBuilder::new();
654 let property_definition = builder
655 .with_name("TEST".to_string())
656 .with_data_type(DataType::String)
657 .with_description("Optional".to_string())
658 .build()
659 .unwrap();
660
661 let builder = SchemaUpdateBuilder::new();
662 let action = builder
663 .with_schema_name("TestSchema".to_string())
664 .with_owner("test_org".to_string())
665 .with_properties(vec![property_definition.clone()])
666 .build()
667 .unwrap();
668
669 let builder = SchemaPayloadBuilder::new();
670 let payload = builder
671 .with_action(Action::SchemaUpdate(action.clone()))
672 .build()
673 .unwrap();
674
675 assert_eq!(payload.action, Action::SchemaUpdate(action));
676 }
677
678 #[test]
679 fn check_schema_payload_bytes() {
682 let builder = PropertyDefinitionBuilder::new();
683 let property_definition = builder
684 .with_name("TEST".to_string())
685 .with_data_type(DataType::String)
686 .with_description("Optional".to_string())
687 .build()
688 .unwrap();
689
690 let builder = SchemaUpdateBuilder::new();
691 let action = builder
692 .with_schema_name("TestSchema".to_string())
693 .with_owner("test_org".to_string())
694 .with_properties(vec![property_definition.clone()])
695 .build()
696 .unwrap();
697
698 let builder = SchemaPayloadBuilder::new();
699 let original = builder
700 .with_action(Action::SchemaUpdate(action))
701 .build()
702 .unwrap();
703
704 let bytes = original.clone().into_bytes().unwrap();
705
706 let payload = SchemaPayload::from_bytes(&bytes).unwrap();
707 assert_eq!(payload, original);
708 }
709}