1#![allow(missing_docs)]
8
9use crate::prelude::*;
10use crate::record::RecordStatus;
11use crate::record::SignedActionHashedExt;
12use conversions::WrongActionError;
13use derive_more::From;
14use holo_hash::EntryHash;
15use holochain_zome_types::op::EntryCreationAction;
16
17#[derive(
18 Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash, derive_more::From,
19)]
20pub enum NewEntryAction {
22 Create(Create),
24 Update(Update),
27}
28
29#[allow(missing_docs)]
30#[derive(Debug, From)]
31pub enum NewEntryActionRef<'a> {
33 Create(&'a Create),
34 Update(&'a Update),
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Ord, PartialOrd)]
38pub enum WireNewEntryAction {
40 Create(WireCreate),
41 Update(WireUpdate),
42}
43
44#[derive(
45 Debug, Clone, derive_more::Constructor, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd,
46)]
47pub struct WireActionStatus<W> {
49 pub action: W,
51 pub validation_status: ValidationStatus,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Ord, PartialOrd)]
58pub struct WireCreate {
59 pub timestamp: holochain_zome_types::timestamp::Timestamp,
62 pub author: AgentPubKey,
63 pub action_seq: u32,
64 pub prev_action: ActionHash,
65 pub signature: Signature,
66 pub weight: EntryRateWeight,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Ord, PartialOrd)]
72pub struct WireUpdate {
73 pub timestamp: holochain_zome_types::timestamp::Timestamp,
76 pub author: AgentPubKey,
77 pub action_seq: u32,
78 pub prev_action: ActionHash,
79 pub original_entry_address: EntryHash,
80 pub original_action_address: ActionHash,
81 pub signature: Signature,
82 pub weight: EntryRateWeight,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes)]
95pub struct WireUpdateRelationship {
96 pub timestamp: holochain_zome_types::timestamp::Timestamp,
99 pub author: AgentPubKey,
100 pub action_seq: u32,
101 pub prev_action: ActionHash,
102 pub original_action_address: ActionHash,
104 pub new_entry_address: EntryHash,
106 pub new_entry_type: EntryType,
108 pub signature: Signature,
109 pub weight: EntryRateWeight,
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes)]
113pub struct WireDelete {
114 pub delete: Delete,
115 pub signature: Signature,
116}
117
118impl NewEntryAction {
119 pub fn entry(&self) -> &EntryHash {
121 match self {
122 NewEntryAction::Create(Create { entry_hash, .. })
123 | NewEntryAction::Update(Update { entry_hash, .. }) => entry_hash,
124 }
125 }
126
127 pub fn entry_type(&self) -> &EntryType {
129 match self {
130 NewEntryAction::Create(Create { entry_type, .. })
131 | NewEntryAction::Update(Update { entry_type, .. }) => entry_type,
132 }
133 }
134
135 pub fn visibility(&self) -> &EntryVisibility {
137 match self {
138 NewEntryAction::Create(Create { entry_type, .. })
139 | NewEntryAction::Update(Update { entry_type, .. }) => entry_type.visibility(),
140 }
141 }
142
143 pub fn timestamp(&self) -> holochain_zome_types::timestamp::Timestamp {
145 match self {
146 NewEntryAction::Create(Create { timestamp, .. })
147 | NewEntryAction::Update(Update { timestamp, .. }) => *timestamp,
148 }
149 }
150
151 pub fn author(&self) -> &AgentPubKey {
153 match self {
154 NewEntryAction::Create(Create { author, .. })
155 | NewEntryAction::Update(Update { author, .. }) => author,
156 }
157 }
158
159 pub fn action_seq(&self) -> u32 {
161 match self {
162 NewEntryAction::Create(Create { action_seq, .. })
163 | NewEntryAction::Update(Update { action_seq, .. }) => *action_seq,
164 }
165 }
166}
167
168impl From<NewEntryAction> for Action {
169 fn from(a: NewEntryAction) -> Self {
170 match a {
171 NewEntryAction::Create(a) => Action::Create(a),
172 NewEntryAction::Update(a) => Action::Update(a),
173 }
174 }
175}
176
177impl From<NewEntryAction> for EntryCreationAction {
178 fn from(action: NewEntryAction) -> Self {
179 match action {
180 NewEntryAction::Create(create) => EntryCreationAction::Create(create),
181 NewEntryAction::Update(update) => EntryCreationAction::Update(update),
182 }
183 }
184}
185
186impl From<(Create, Signature)> for WireCreate {
187 fn from((ec, signature): (Create, Signature)) -> Self {
188 Self {
189 timestamp: ec.timestamp,
190 author: ec.author,
191 action_seq: ec.action_seq,
192 prev_action: ec.prev_action,
193 signature,
194 weight: ec.weight,
195 }
196 }
197}
198
199impl From<(Update, Signature)> for WireUpdate {
200 fn from((eu, signature): (Update, Signature)) -> Self {
201 Self {
202 timestamp: eu.timestamp,
203 author: eu.author,
204 action_seq: eu.action_seq,
205 prev_action: eu.prev_action,
206 original_entry_address: eu.original_entry_address,
207 original_action_address: eu.original_action_address,
208 signature,
209 weight: eu.weight,
210 }
211 }
212}
213
214impl WireDelete {
215 pub fn into_record(self) -> Record {
216 Record::new(
217 SignedActionHashed::from_content_sync(SignedAction::new(
218 self.delete.into(),
219 self.signature,
220 )),
221 None,
222 )
223 }
224}
225
226impl WireUpdateRelationship {
227 pub fn into_record(self, original_entry_address: EntryHash) -> Record {
230 Record::new(
231 SignedActionHashed::from_content_sync(self.into_signed_action(original_entry_address)),
232 None,
233 )
234 }
235
236 pub fn into_signed_action(self, original_entry_address: EntryHash) -> SignedAction {
238 let eu = Update {
239 author: self.author,
240 timestamp: self.timestamp,
241 action_seq: self.action_seq,
242 prev_action: self.prev_action,
243 original_action_address: self.original_action_address,
244 original_entry_address,
245 entry_type: self.new_entry_type,
246 entry_hash: self.new_entry_address,
247 weight: self.weight,
248 };
249 SignedAction::new(Action::Update(eu), self.signature)
250 }
251}
252
253impl NewEntryActionRef<'_> {
254 pub fn entry_type(&self) -> &EntryType {
255 match self {
256 NewEntryActionRef::Create(Create { entry_type, .. })
257 | NewEntryActionRef::Update(Update { entry_type, .. }) => entry_type,
258 }
259 }
260 pub fn entry_hash(&self) -> &EntryHash {
261 match self {
262 NewEntryActionRef::Create(Create { entry_hash, .. })
263 | NewEntryActionRef::Update(Update { entry_hash, .. }) => entry_hash,
264 }
265 }
266 pub fn to_new_entry_action(&self) -> NewEntryAction {
267 match self {
268 NewEntryActionRef::Create(create) => NewEntryAction::Create((*create).to_owned()),
269 NewEntryActionRef::Update(update) => NewEntryAction::Update((*update).to_owned()),
270 }
271 }
272}
273
274impl TryFrom<SignedActionHashed> for WireDelete {
275 type Error = WrongActionError;
276 fn try_from(sah: SignedActionHashed) -> Result<Self, Self::Error> {
277 let (a, signature) = sah.into_inner();
278 Ok(Self {
279 delete: a.into_content().try_into()?,
280 signature,
281 })
282 }
283}
284
285impl TryFrom<SignedAction> for WireDelete {
286 type Error = WrongActionError;
287 fn try_from(sa: SignedAction) -> Result<Self, Self::Error> {
288 let (a, signature) = sa.into();
289 Ok(Self {
290 delete: a.try_into()?,
291 signature,
292 })
293 }
294}
295
296impl TryFrom<SignedActionHashed> for WireUpdate {
297 type Error = WrongActionError;
298 fn try_from(sah: SignedActionHashed) -> Result<Self, Self::Error> {
299 let (a, signature) = sah.into_inner();
300 let d: Update = a.into_content().try_into()?;
301 Ok(Self {
302 signature,
303 timestamp: d.timestamp,
304 author: d.author,
305 action_seq: d.action_seq,
306 prev_action: d.prev_action,
307 original_entry_address: d.original_entry_address,
308 original_action_address: d.original_action_address,
309 weight: d.weight,
310 })
311 }
312}
313
314impl TryFrom<SignedActionHashed> for WireUpdateRelationship {
315 type Error = WrongActionError;
316 fn try_from(sah: SignedActionHashed) -> Result<Self, Self::Error> {
317 let (a, s) = sah.into_inner();
318 SignedAction::new(a.into_content(), s).try_into()
319 }
320}
321
322impl TryFrom<SignedAction> for WireUpdateRelationship {
323 type Error = WrongActionError;
324 fn try_from(sa: SignedAction) -> Result<Self, Self::Error> {
325 let (a, signature) = sa.into();
326 let d: Update = a.try_into()?;
327 Ok(Self {
328 signature,
329 timestamp: d.timestamp,
330 author: d.author,
331 action_seq: d.action_seq,
332 prev_action: d.prev_action,
333 original_action_address: d.original_action_address,
334 new_entry_address: d.entry_hash,
335 new_entry_type: d.entry_type,
336 weight: d.weight,
337 })
338 }
339}
340
341impl WireNewEntryAction {
342 pub fn into_record(self, entry_type: EntryType, entry: Entry) -> Record {
343 let entry_hash = EntryHash::with_data_sync(&entry);
344 Record::new(self.into_action(entry_type, entry_hash), Some(entry))
345 }
346
347 pub fn into_action(self, entry_type: EntryType, entry_hash: EntryHash) -> SignedActionHashed {
348 SignedActionHashed::from_content_sync(self.into_signed_action(entry_type, entry_hash))
349 }
350
351 pub fn into_signed_action(self, entry_type: EntryType, entry_hash: EntryHash) -> SignedAction {
352 match self {
353 WireNewEntryAction::Create(ec) => {
354 let signature = ec.signature;
355 let ec = Create {
356 author: ec.author,
357 timestamp: ec.timestamp,
358 action_seq: ec.action_seq,
359 prev_action: ec.prev_action,
360 weight: ec.weight,
361 entry_type,
362 entry_hash,
363 };
364 SignedAction::new(ec.into(), signature)
365 }
366 WireNewEntryAction::Update(eu) => {
367 let signature = eu.signature;
368 let eu = Update {
369 author: eu.author,
370 timestamp: eu.timestamp,
371 action_seq: eu.action_seq,
372 prev_action: eu.prev_action,
373 original_entry_address: eu.original_entry_address,
374 original_action_address: eu.original_action_address,
375 weight: eu.weight,
376 entry_type,
377 entry_hash,
378 };
379 SignedAction::new(eu.into(), signature)
380 }
381 }
382 }
383}
384
385impl WireActionStatus<WireNewEntryAction> {
386 pub fn into_record_status(self, entry_type: EntryType, entry: Entry) -> RecordStatus {
387 RecordStatus::new(
388 self.action.into_record(entry_type, entry),
389 self.validation_status,
390 )
391 }
392}
393
394impl WireActionStatus<WireUpdateRelationship> {
395 pub fn into_record_status(self, entry_hash: EntryHash) -> RecordStatus {
396 RecordStatus::new(self.action.into_record(entry_hash), self.validation_status)
397 }
398}
399
400impl WireActionStatus<WireDelete> {
401 pub fn into_record_status(self) -> RecordStatus {
402 RecordStatus::new(self.action.into_record(), self.validation_status)
403 }
404}
405
406impl<H, W, E> TryFrom<(H, ValidationStatus)> for WireActionStatus<W>
407where
408 E: Into<ActionError>,
409 H: TryInto<W, Error = E>,
410{
411 type Error = ActionError;
412
413 fn try_from(value: (H, ValidationStatus)) -> Result<Self, Self::Error> {
414 Ok(Self::new(value.0.try_into().map_err(Into::into)?, value.1))
415 }
416}
417
418impl TryFrom<SignedActionHashed> for WireNewEntryAction {
419 type Error = ActionError;
420 fn try_from(sah: SignedActionHashed) -> Result<Self, Self::Error> {
421 let action = sah.hashed.content;
422 let signature = sah.signature;
423 match action {
424 Action::Create(ec) => Ok(Self::Create((ec, signature).into())),
425 Action::Update(eu) => Ok(Self::Update((eu, signature).into())),
426 _ => Err(ActionError::NotNewEntry),
427 }
428 }
429}
430
431impl TryFrom<SignedAction> for WireNewEntryAction {
432 type Error = ActionError;
433 fn try_from(sa: SignedAction) -> Result<Self, Self::Error> {
434 let (action, s) = sa.into();
435 match action {
436 Action::Create(ec) => Ok(Self::Create((ec, s).into())),
437 Action::Update(eu) => Ok(Self::Update((eu, s).into())),
438 _ => Err(ActionError::NotNewEntry),
439 }
440 }
441}
442
443impl TryFrom<Action> for NewEntryAction {
444 type Error = WrongActionError;
445 fn try_from(value: Action) -> Result<Self, Self::Error> {
446 match value {
447 Action::Create(a) => Ok(NewEntryAction::Create(a)),
448 Action::Update(a) => Ok(NewEntryAction::Update(a)),
449 _ => Err(WrongActionError(format!("{:?}", value))),
450 }
451 }
452}
453
454impl<'a> TryFrom<&'a Action> for NewEntryActionRef<'a> {
455 type Error = WrongActionError;
456 fn try_from(value: &'a Action) -> Result<Self, Self::Error> {
457 match value {
458 Action::Create(a) => Ok(NewEntryActionRef::Create(a)),
459 Action::Update(a) => Ok(NewEntryActionRef::Update(a)),
460 _ => Err(WrongActionError(format!("{:?}", value))),
461 }
462 }
463}
464
465impl<'a> From<&'a NewEntryAction> for NewEntryActionRef<'a> {
466 fn from(n: &'a NewEntryAction) -> Self {
467 match n {
468 NewEntryAction::Create(ec) => NewEntryActionRef::Create(ec),
469 NewEntryAction::Update(eu) => NewEntryActionRef::Update(eu),
470 }
471 }
472}
473
474#[cfg(test)]
475mod tests {
476 use super::*;
477 use crate::test_utils::fake_dna_hash;
478 use crate::test_utils::fake_entry_hash;
479 use ::fixt::prelude::Unpredictable;
480
481 #[test]
482 fn test_action_msgpack_roundtrip() {
483 let orig: Action = Dna::from_builder(
484 fake_dna_hash(1),
485 ActionBuilderCommonFixturator::new(Unpredictable)
486 .next()
487 .unwrap(),
488 )
489 .into();
490 let bytes = holochain_serialized_bytes::encode(&orig).unwrap();
491 let res: Action = holochain_serialized_bytes::decode(&bytes).unwrap();
492 assert_eq!(orig, res);
493 }
494
495 #[test]
496 fn test_action_json_roundtrip() {
497 let orig: Action = Dna::from_builder(
498 fake_dna_hash(1),
499 ActionBuilderCommonFixturator::new(Unpredictable)
500 .next()
501 .unwrap(),
502 )
503 .into();
504 let orig = ActionHashed::from_content_sync(orig);
505 let json = serde_json::to_string(&orig).unwrap();
506 dbg!(&json);
507 let res: ActionHashed = serde_json::from_str(&json).unwrap();
508 assert_eq!(orig, res);
509 }
510
511 #[test]
512 fn test_create_entry_msgpack_roundtrip() {
513 let orig: Action = Create::from_builder(
514 ActionBuilderCommonFixturator::new(Unpredictable)
515 .next()
516 .unwrap(),
517 EntryType::App(AppEntryDef::new(
518 0.into(),
519 0.into(),
520 EntryVisibility::Public,
521 )),
522 fake_entry_hash(1),
523 )
524 .into();
525 let bytes = holochain_serialized_bytes::encode(&orig).unwrap();
526 println!("{:?}", bytes);
527 let res: Action = holochain_serialized_bytes::decode(&bytes).unwrap();
528 assert_eq!(orig, res);
529 }
530
531 #[test]
532 fn test_create_entry_serializedbytes_roundtrip() {
533 let orig: Action = Create::from_builder(
534 ActionBuilderCommonFixturator::new(Unpredictable)
535 .next()
536 .unwrap(),
537 EntryType::App(AppEntryDef::new(
538 0.into(),
539 0.into(),
540 EntryVisibility::Public,
541 )),
542 fake_entry_hash(1),
543 )
544 .into();
545 let bytes: SerializedBytes = orig.clone().try_into().unwrap();
546 let res: Action = bytes.try_into().unwrap();
547 assert_eq!(orig, res);
548 }
549}