bonsaidb_local/database/
compat.rs1use std::any::type_name;
2use std::collections::HashMap;
3use std::marker::PhantomData;
4
5use bonsaidb_core::arc_bytes::serde::Bytes;
6use bonsaidb_core::document::DocumentId;
7use bonsaidb_core::schema::CollectionName;
8use bonsaidb_core::transaction::{ChangedDocument, ChangedKey, Changes, DocumentChanges};
9use serde::{Deserialize, Serialize};
10use transmog_versions::Versioned;
11
12#[derive(thiserror::Error)]
13pub struct UnknownVersion<T>(PhantomData<T>);
14
15impl<T> Default for UnknownVersion<T> {
16 fn default() -> Self {
17 Self(PhantomData)
18 }
19}
20
21impl<T> std::fmt::Debug for UnknownVersion<T> {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 f.debug_tuple("UnknownVersion")
24 .field(&type_name::<T>())
25 .finish()
26 }
27}
28
29impl<T> std::fmt::Display for UnknownVersion<T> {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 write!(f, "incompatilbe version of {}", type_name::<T>())
32 }
33}
34
35#[derive(Clone, Copy, Debug)]
36enum ChangesVersions {
37 Legacy = 0,
38 V1 = 1,
39}
40
41impl Versioned for ChangesVersions {
42 fn version(&self) -> u64 {
43 *self as u64
44 }
45}
46
47impl TryFrom<u64> for ChangesVersions {
48 type Error = UnknownVersion<Changes>;
49
50 fn try_from(value: u64) -> Result<Self, Self::Error> {
51 match value {
52 0 => Ok(ChangesVersions::Legacy),
53 1 => Ok(ChangesVersions::V1),
54 _ => Err(UnknownVersion::default()),
55 }
56 }
57}
58
59pub fn deserialize_executed_transaction_changes(data: &[u8]) -> Result<Changes, crate::Error> {
60 let (version, data) = transmog_versions::unwrap_version(data);
61 match ChangesVersions::try_from(version)? {
62 ChangesVersions::Legacy => {
63 let legacy: ChangesV0 = match pot::from_slice(data) {
64 Ok(changes) => changes,
65 Err(pot::Error::NotAPot) => ChangesV0::Documents(bincode::deserialize(data)?),
66 other => other?,
67 };
68 Changes::try_from(legacy).map_err(crate::Error::from)
69 }
70 ChangesVersions::V1 => pot::from_slice(data).map_err(crate::Error::from),
71 }
72}
73
74pub fn serialize_executed_transaction_changes(changes: &Changes) -> Result<Vec<u8>, crate::Error> {
75 let mut serialized = Vec::new();
76 transmog_versions::write_header(&ChangesVersions::V1, &mut serialized)?;
77 pot::to_writer(changes, &mut serialized)?;
78 Ok(serialized)
79}
80
81#[derive(Clone, Debug, Serialize, Deserialize)]
83pub enum ChangesV0 {
84 Documents(Vec<ChangedDocumentV0>),
86 Keys(Vec<ChangedKey>),
88}
89
90impl TryFrom<ChangesV0> for Changes {
91 type Error = bonsaidb_core::Error;
92
93 fn try_from(legacy: ChangesV0) -> Result<Self, Self::Error> {
94 match legacy {
95 ChangesV0::Documents(legacy_documents) => {
96 let mut changed_documents = Vec::with_capacity(legacy_documents.len());
97 let mut collections = Vec::new();
98 let mut collection_indexes = HashMap::new();
99 for changed in legacy_documents {
100 let collection = if let Some(id) = collection_indexes.get(&changed.collection) {
101 *id
102 } else {
103 let id = u16::try_from(collections.len()).unwrap();
104 collection_indexes.insert(changed.collection.clone(), id);
105 collections.push(changed.collection);
106 id
107 };
108 changed_documents.push(ChangedDocument {
109 collection,
110 id: changed.id.try_into()?,
111 deleted: changed.deleted,
112 });
113 }
114 Ok(Self::Documents(DocumentChanges {
115 collections,
116 documents: changed_documents,
117 }))
118 }
119 ChangesV0::Keys(changes) => Ok(Self::Keys(changes)),
120 }
121 }
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct ChangedDocumentV0 {
127 pub collection: CollectionName,
129
130 pub id: LegacyDocumentId,
132
133 pub deleted: bool,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
138#[serde(untagged)]
139pub enum LegacyDocumentId {
140 U64(u64),
141 Document(Bytes),
142}
143
144impl TryFrom<LegacyDocumentId> for DocumentId {
145 type Error = bonsaidb_core::Error;
146
147 fn try_from(id: LegacyDocumentId) -> Result<Self, Self::Error> {
148 match id {
149 LegacyDocumentId::Document(id) => DocumentId::try_from(&id[..]),
150 LegacyDocumentId::U64(version) => Ok(DocumentId::from_u64(version)),
151 }
152 }
153}