persy_expimp/
lib.rs

1//! Export/Import Persy storage data to a external structure.
2//!
3//! ## Supported format:  
4//! ### Custom
5//!  Hust extract/import the data through defined structs and use a custom write/read
6//! Functions:  
7//!  [export](fn.export.html),  [import](fn.import.html).  
8//! ### JSON
9//! export/import to a JSON serialized Read/Write
10//! Functions:  
11//! [export_json](fn.export_json.html), [import_json](fn.import_json.html).  
12//!
13//! # Examples
14//!
15//! ## Custom Export Example
16//!
17//! ```
18//! use persy::{Persy, Config};
19//! use persy_expimp::export;
20//! use std::vec::Vec;
21//! # use persy_expimp::EIRes;
22//! # fn foo() -> EIRes<()> {
23//! let persy = Persy::open("file.persy", Config::new())?;
24//! for info in export(&persy)? {
25//!     // Custom logic
26//! }
27//! # Ok(())
28//! # }
29//! ```
30//! ## Custom Import Example
31//!
32//! ```
33//! use persy::{Persy, Config};
34//! use persy_expimp::{import,Info};
35//! # use persy_expimp::EIRes;
36//! # fn foo() -> EIRes<()> {
37//! Persy::create("imported.persy")?;
38//! let persy = Persy::open("imported.persy", Config::new())?;
39//! // Source informations from a custom source
40//! let source = Vec::<Info>::new();
41//! import(&persy,source.into_iter())?;
42//! # Ok(())
43//! # }
44//! ```
45//!
46//!
47//!
48
49//!
50use persy::{
51    ByteVec, IndexId, IndexInfo, IndexType, IndexTypeId, Persy, PersyError, PersyId, SegmentId, Snapshot, Transaction,
52    ValueIter, ValueMode,
53};
54use std::io;
55use std::iter::Iterator;
56use std::ops::RangeBounds;
57
58pub type EIRes<T> = Result<T, Error>;
59
60#[cfg(feature = "serde")]
61use serde_derive::{Deserialize, Serialize};
62
63#[cfg(feature = "serde")]
64mod serde;
65#[cfg(feature = "serde")]
66use crate::serde::{
67    bytevec_deserialize, bytevec_serialize, index_id_deserialize, index_id_serialize, index_type_id_deserialize,
68    index_type_id_serialize, persy_id_deserialize, persy_id_serialize, segment_id_deserialize, segment_id_serialize,
69    value_mode_deserialize, value_mode_serialize, vec_bytevec_deserialize, vec_bytevec_serialize,
70    vec_persy_id_deserialize, vec_persy_id_serialize,
71};
72
73#[cfg(feature = "json")]
74mod json;
75#[cfg(feature = "json")]
76pub use json::{export_json, export_json_from_snapshot, import_json};
77
78#[cfg(feature = "binary")]
79mod binary;
80#[cfg(feature = "binary")]
81pub use binary::{export_binary, export_binary_from_snapshot, import_binary};
82
83#[derive(Debug)]
84pub enum Error {
85    PersyError(PersyError),
86    IoError(io::Error),
87    SerdeError(String),
88}
89
90impl<T: Into<PersyError>> From<persy::PE<T>> for Error {
91    fn from(err: persy::PE<T>) -> Error {
92        Error::PersyError(err.error().into())
93    }
94}
95
96impl From<io::Error> for Error {
97    fn from(err: io::Error) -> Error {
98        Error::IoError(err)
99    }
100}
101
102#[cfg(feature = "json")]
103impl From<serde_json::error::Error> for Error {
104    fn from(err: serde_json::error::Error) -> Error {
105        Error::SerdeError(format!("{}", err))
106    }
107}
108
109#[cfg(feature = "bincode")]
110impl From<bincode::Error> for Error {
111    fn from(err: bincode::Error) -> Error {
112        Error::SerdeError(format!("{}", err))
113    }
114}
115
116#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
117pub struct SegmentMetadata {
118    pub version: u32,
119    pub name: String,
120    #[cfg_attr(
121        feature = "serde",
122        serde(serialize_with = "segment_id_serialize", deserialize_with = "segment_id_deserialize")
123    )]
124    pub id: SegmentId,
125}
126
127#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
128pub struct Record {
129    pub version: u32,
130    pub segment: String,
131    #[cfg_attr(
132        feature = "serde",
133        serde(serialize_with = "persy_id_serialize", deserialize_with = "persy_id_deserialize")
134    )]
135    pub id: PersyId,
136    pub content: Vec<u8>,
137}
138
139#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
140pub struct IndexMetadata {
141    pub version: u32,
142    pub name: String,
143    #[cfg_attr(
144        feature = "serde",
145        serde(serialize_with = "index_id_serialize", deserialize_with = "index_id_deserialize")
146    )]
147    pub id: IndexId,
148    #[cfg_attr(
149        feature = "serde",
150        serde(
151            serialize_with = "index_type_id_serialize",
152            deserialize_with = "index_type_id_deserialize"
153        )
154    )]
155    pub key_type: IndexTypeId,
156    #[cfg_attr(
157        feature = "serde",
158        serde(
159            serialize_with = "index_type_id_serialize",
160            deserialize_with = "index_type_id_deserialize"
161        )
162    )]
163    pub value_type: IndexTypeId,
164    #[cfg_attr(
165        feature = "serde",
166        serde(serialize_with = "value_mode_serialize", deserialize_with = "value_mode_deserialize")
167    )]
168    pub value_mode: ValueMode,
169}
170
171#[derive(Clone)]
172#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
173pub enum IndexKey {
174    U8(u8),
175    U16(u16),
176    U32(u32),
177    U64(u64),
178    U128(u128),
179    I8(i8),
180    I16(i16),
181    I32(i32),
182    I64(i64),
183    I128(i128),
184    F32(f32),
185    F64(f64),
186    String(String),
187    #[cfg_attr(
188        feature = "serde",
189        serde(serialize_with = "persy_id_serialize", deserialize_with = "persy_id_deserialize")
190    )]
191    PersyId(PersyId),
192    #[cfg_attr(
193        feature = "serde",
194        serde(serialize_with = "bytevec_serialize", deserialize_with = "bytevec_deserialize")
195    )]
196    ByteVec(ByteVec),
197}
198
199#[derive(Clone)]
200#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
201pub enum IndexValue {
202    U8(Vec<u8>),
203    U16(Vec<u16>),
204    U32(Vec<u32>),
205    U64(Vec<u64>),
206    U128(Vec<u128>),
207    I8(Vec<i8>),
208    I16(Vec<i16>),
209    I32(Vec<i32>),
210    I64(Vec<i64>),
211    I128(Vec<i128>),
212    F32(Vec<f32>),
213    F64(Vec<f64>),
214    String(Vec<String>),
215    #[cfg_attr(
216        feature = "serde",
217        serde(
218            serialize_with = "vec_persy_id_serialize",
219            deserialize_with = "vec_persy_id_deserialize"
220        )
221    )]
222    PersyId(Vec<PersyId>),
223    #[cfg_attr(
224        feature = "serde",
225        serde(
226            serialize_with = "vec_bytevec_serialize",
227            deserialize_with = "vec_bytevec_deserialize"
228        )
229    )]
230    ByteVec(Vec<ByteVec>),
231}
232
233fn range<K: IndexType + 'static, V: IndexType + 'static, T: PersyReader>(
234    persy: T,
235    name: &str,
236) -> EIRes<impl Iterator<Item = (K, ValueIter<V>)>> {
237    persy.range::<K, V, _>(name, ..)
238}
239
240fn resolve_value_type<K: IndexType + 'static, T: PersyReader + 'static>(
241    persy: T,
242    name: &str,
243    info: IndexInfo,
244) -> EIRes<Box<dyn Iterator<Item = (K, IndexValue)>>> {
245    Ok(match info.value_type {
246        IndexTypeId::U8 => {
247            Box::new(range::<K, u8, T>(persy, name)?.map(|(k, v)| (k, IndexValue::U8(v.into_iter().collect()))))
248        }
249        IndexTypeId::U16 => {
250            Box::new(range::<K, u16, T>(persy, name)?.map(|(k, v)| (k, IndexValue::U16(v.into_iter().collect()))))
251        }
252        IndexTypeId::U32 => {
253            Box::new(range::<K, u32, T>(persy, name)?.map(|(k, v)| (k, IndexValue::U32(v.into_iter().collect()))))
254        }
255        IndexTypeId::U64 => {
256            Box::new(range::<K, u64, T>(persy, name)?.map(|(k, v)| (k, IndexValue::U64(v.into_iter().collect()))))
257        }
258        IndexTypeId::U128 => {
259            Box::new(range::<K, u128, T>(persy, name)?.map(|(k, v)| (k, IndexValue::U128(v.into_iter().collect()))))
260        }
261        IndexTypeId::I8 => {
262            Box::new(range::<K, i8, T>(persy, name)?.map(|(k, v)| (k, IndexValue::I8(v.into_iter().collect()))))
263        }
264        IndexTypeId::I16 => {
265            Box::new(range::<K, i16, T>(persy, name)?.map(|(k, v)| (k, IndexValue::I16(v.into_iter().collect()))))
266        }
267        IndexTypeId::I32 => {
268            Box::new(range::<K, i32, T>(persy, name)?.map(|(k, v)| (k, IndexValue::I32(v.into_iter().collect()))))
269        }
270        IndexTypeId::I64 => {
271            Box::new(range::<K, i64, T>(persy, name)?.map(|(k, v)| (k, IndexValue::I64(v.into_iter().collect()))))
272        }
273        IndexTypeId::I128 => {
274            Box::new(range::<K, i128, T>(persy, name)?.map(|(k, v)| (k, IndexValue::I128(v.into_iter().collect()))))
275        }
276        IndexTypeId::F32W => {
277            Box::new(range::<K, f32, T>(persy, name)?.map(|(k, v)| (k, IndexValue::F32(v.into_iter().collect()))))
278        }
279        IndexTypeId::F64W => {
280            Box::new(range::<K, f64, T>(persy, name)?.map(|(k, v)| (k, IndexValue::F64(v.into_iter().collect()))))
281        }
282        IndexTypeId::String => {
283            Box::new(range::<K, String, T>(persy, name)?.map(|(k, v)| (k, IndexValue::String(v.into_iter().collect()))))
284        }
285        IndexTypeId::PersyId => Box::new(
286            range::<K, PersyId, T>(persy, name)?.map(|(k, v)| (k, IndexValue::PersyId(v.into_iter().collect()))),
287        ),
288        IndexTypeId::ByteVec => Box::new(
289            range::<K, ByteVec, T>(persy, name)?.map(|(k, v)| (k, IndexValue::ByteVec(v.into_iter().collect()))),
290        ),
291    })
292}
293fn browse<T: PersyReader + 'static>(
294    persy: T,
295    name: &str,
296    info: IndexInfo,
297) -> EIRes<Box<dyn Iterator<Item = (IndexKey, IndexValue)>>> {
298    Ok(match info.key_type {
299        IndexTypeId::U8 => Box::new(resolve_value_type::<u8, T>(persy, name, info)?.map(|(k, v)| (IndexKey::U8(k), v))),
300        IndexTypeId::U16 => {
301            Box::new(resolve_value_type::<u16, T>(persy, name, info)?.map(|(k, v)| (IndexKey::U16(k), v)))
302        }
303        IndexTypeId::U32 => {
304            Box::new(resolve_value_type::<u32, T>(persy, name, info)?.map(|(k, v)| (IndexKey::U32(k), v)))
305        }
306        IndexTypeId::U64 => {
307            Box::new(resolve_value_type::<u64, T>(persy, name, info)?.map(|(k, v)| (IndexKey::U64(k), v)))
308        }
309        IndexTypeId::U128 => {
310            Box::new(resolve_value_type::<u128, T>(persy, name, info)?.map(|(k, v)| (IndexKey::U128(k), v)))
311        }
312        IndexTypeId::I8 => Box::new(resolve_value_type::<i8, T>(persy, name, info)?.map(|(k, v)| (IndexKey::I8(k), v))),
313        IndexTypeId::I16 => {
314            Box::new(resolve_value_type::<i16, T>(persy, name, info)?.map(|(k, v)| (IndexKey::I16(k), v)))
315        }
316        IndexTypeId::I32 => {
317            Box::new(resolve_value_type::<i32, T>(persy, name, info)?.map(|(k, v)| (IndexKey::I32(k), v)))
318        }
319        IndexTypeId::I64 => {
320            Box::new(resolve_value_type::<i64, T>(persy, name, info)?.map(|(k, v)| (IndexKey::I64(k), v)))
321        }
322        IndexTypeId::I128 => {
323            Box::new(resolve_value_type::<i128, T>(persy, name, info)?.map(|(k, v)| (IndexKey::I128(k), v)))
324        }
325        IndexTypeId::F32W => {
326            Box::new(resolve_value_type::<f32, T>(persy, name, info)?.map(|(k, v)| (IndexKey::F32(k), v)))
327        }
328        IndexTypeId::F64W => {
329            Box::new(resolve_value_type::<f64, T>(persy, name, info)?.map(|(k, v)| (IndexKey::F64(k), v)))
330        }
331        IndexTypeId::String => {
332            Box::new(resolve_value_type::<String, T>(persy, name, info)?.map(|(k, v)| (IndexKey::String(k), v)))
333        }
334        IndexTypeId::PersyId => {
335            Box::new(resolve_value_type::<PersyId, T>(persy, name, info)?.map(|(k, v)| (IndexKey::PersyId(k), v)))
336        }
337        IndexTypeId::ByteVec => {
338            Box::new(resolve_value_type::<ByteVec, T>(persy, name, info)?.map(|(k, v)| (IndexKey::ByteVec(k), v)))
339        }
340    })
341}
342
343#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
344pub struct Entry {
345    pub version: u32,
346    pub index: String,
347    pub key: IndexKey,
348    pub value: IndexValue,
349}
350
351#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
352pub enum Info {
353    Segment(SegmentMetadata),
354    Record(Record),
355    Index(IndexMetadata),
356    Entry(Entry),
357}
358
359fn iter_keys<T: PersyReader + 'static>(
360    persy: T,
361    (name, infos): (String, IndexInfo),
362) -> EIRes<Box<impl Iterator<Item = Info>>> {
363    let entries = browse(persy, &name, infos)?;
364    Ok(Box::new(entries.map(move |(k, v)| {
365        Info::Entry(Entry {
366            version: 0,
367            index: name.clone(),
368            key: k,
369            value: v,
370        })
371    })))
372}
373
374fn create_index_k<K: IndexType + 'static>(tx: &mut Transaction, info: IndexMetadata) -> EIRes<()> {
375    Ok(match info.value_type {
376        IndexTypeId::U8 => tx.create_index::<K, u8>(&info.name, info.value_mode)?,
377        IndexTypeId::U16 => tx.create_index::<K, u16>(&info.name, info.value_mode)?,
378        IndexTypeId::U32 => tx.create_index::<K, u32>(&info.name, info.value_mode)?,
379        IndexTypeId::U64 => tx.create_index::<K, u64>(&info.name, info.value_mode)?,
380        IndexTypeId::U128 => tx.create_index::<K, u128>(&info.name, info.value_mode)?,
381        IndexTypeId::I8 => tx.create_index::<K, i8>(&info.name, info.value_mode)?,
382        IndexTypeId::I16 => tx.create_index::<K, i16>(&info.name, info.value_mode)?,
383        IndexTypeId::I32 => tx.create_index::<K, i32>(&info.name, info.value_mode)?,
384        IndexTypeId::I64 => tx.create_index::<K, i64>(&info.name, info.value_mode)?,
385        IndexTypeId::I128 => tx.create_index::<K, i128>(&info.name, info.value_mode)?,
386        IndexTypeId::F32W => tx.create_index::<K, f32>(&info.name, info.value_mode)?,
387        IndexTypeId::F64W => tx.create_index::<K, f64>(&info.name, info.value_mode)?,
388        IndexTypeId::String => tx.create_index::<K, String>(&info.name, info.value_mode)?,
389        IndexTypeId::PersyId => tx.create_index::<K, PersyId>(&info.name, info.value_mode)?,
390        IndexTypeId::ByteVec => tx.create_index::<K, ByteVec>(&info.name, info.value_mode)?,
391    })
392}
393fn create_index(tx: &mut Transaction, info: IndexMetadata) -> EIRes<()> {
394    match info.key_type {
395        IndexTypeId::U8 => create_index_k::<u8>(tx, info),
396        IndexTypeId::U16 => create_index_k::<u16>(tx, info),
397        IndexTypeId::U32 => create_index_k::<u32>(tx, info),
398        IndexTypeId::U64 => create_index_k::<u64>(tx, info),
399        IndexTypeId::U128 => create_index_k::<u128>(tx, info),
400        IndexTypeId::I8 => create_index_k::<i8>(tx, info),
401        IndexTypeId::I16 => create_index_k::<i16>(tx, info),
402        IndexTypeId::I32 => create_index_k::<i32>(tx, info),
403        IndexTypeId::I64 => create_index_k::<i64>(tx, info),
404        IndexTypeId::I128 => create_index_k::<i128>(tx, info),
405        IndexTypeId::F32W => create_index_k::<f32>(tx, info),
406        IndexTypeId::F64W => create_index_k::<f64>(tx, info),
407        IndexTypeId::String => create_index_k::<String>(tx, info),
408        IndexTypeId::PersyId => create_index_k::<PersyId>(tx, info),
409        IndexTypeId::ByteVec => create_index_k::<ByteVec>(tx, info),
410    }
411}
412
413fn remap_persy_id(tx: &mut Transaction, orig: PersyId, new: PersyId) -> EIRes<()> {
414    Ok(tx.put("xx__persy__id__mapper", orig, new)?)
415}
416
417fn create_map_persy_id_index(tx: &mut Transaction) -> EIRes<()> {
418    Ok(tx.create_index::<PersyId, PersyId>("xx__persy__id__mapper", ValueMode::Replace)?)
419}
420
421fn drop_map_persy_id_index(tx: &mut Transaction) -> EIRes<()> {
422    Ok(tx.drop_index("xx__persy__id__mapper")?)
423}
424
425fn map_persy_id(tx: &mut Transaction, id: PersyId) -> EIRes<PersyId> {
426    Ok(tx.get("xx__persy__id__mapper", &id)?.into_iter().next().unwrap_or(id))
427}
428
429fn map_persy_id_out(persy: &Persy, id: PersyId) -> EIRes<PersyId> {
430    Ok(persy
431        .get("xx__persy__id__mapper", &id)?
432        .into_iter()
433        .next()
434        .unwrap_or(id))
435}
436
437fn put_all_id<K: IndexType>(tx: &mut Transaction, index: &str, k: K, v: Vec<PersyId>) -> EIRes<()> {
438    for val in v {
439        let mapped = map_persy_id(tx, val)?;
440        tx.put(index, k.clone(), mapped)?;
441    }
442    Ok(())
443}
444
445fn put_all<K: IndexType, V: IndexType>(tx: &mut Transaction, index: &str, k: K, v: Vec<V>) -> EIRes<()> {
446    for val in v {
447        tx.put(index, k.clone(), val)?;
448    }
449    Ok(())
450}
451
452fn put_entry_k<K: IndexType + 'static>(tx: &mut Transaction, k: K, entry: Entry) -> EIRes<()> {
453    match entry.value {
454        IndexValue::U8(v) => put_all(tx, &entry.index, k, v),
455        IndexValue::U16(v) => put_all(tx, &entry.index, k, v),
456        IndexValue::U32(v) => put_all(tx, &entry.index, k, v),
457        IndexValue::U64(v) => put_all(tx, &entry.index, k, v),
458        IndexValue::U128(v) => put_all(tx, &entry.index, k, v),
459        IndexValue::I8(v) => put_all(tx, &entry.index, k, v),
460        IndexValue::I16(v) => put_all(tx, &entry.index, k, v),
461        IndexValue::I32(v) => put_all(tx, &entry.index, k, v),
462        IndexValue::I64(v) => put_all(tx, &entry.index, k, v),
463        IndexValue::I128(v) => put_all(tx, &entry.index, k, v),
464        IndexValue::F32(v) => put_all(tx, &entry.index, k, v),
465        IndexValue::F64(v) => put_all(tx, &entry.index, k, v),
466        IndexValue::String(v) => put_all(tx, &entry.index, k, v),
467        IndexValue::PersyId(v) => put_all_id(tx, &entry.index, k, v),
468        IndexValue::ByteVec(v) => put_all(tx, &entry.index, k, v),
469    }
470}
471fn put_entry(tx: &mut Transaction, entry: Entry) -> EIRes<()> {
472    match entry.key.clone() {
473        IndexKey::U8(k) => put_entry_k(tx, k, entry),
474        IndexKey::U16(k) => put_entry_k(tx, k, entry),
475        IndexKey::U32(k) => put_entry_k(tx, k, entry),
476        IndexKey::U64(k) => put_entry_k(tx, k, entry),
477        IndexKey::U128(k) => put_entry_k(tx, k, entry),
478        IndexKey::I8(k) => put_entry_k(tx, k, entry),
479        IndexKey::I16(k) => put_entry_k(tx, k, entry),
480        IndexKey::I32(k) => put_entry_k(tx, k, entry),
481        IndexKey::I64(k) => put_entry_k(tx, k, entry),
482        IndexKey::I128(k) => put_entry_k(tx, k, entry),
483        IndexKey::F32(k) => put_entry_k(tx, k, entry),
484        IndexKey::F64(k) => put_entry_k(tx, k, entry),
485        IndexKey::String(k) => put_entry_k(tx, k, entry),
486        IndexKey::PersyId(k) => {
487            let mapped_key = map_persy_id(tx, k)?;
488            put_entry_k(tx, mapped_key, entry)
489        }
490        IndexKey::ByteVec(k) => put_entry_k(tx, k, entry),
491    }
492}
493
494pub trait PersyReader: Clone + Sized {
495    fn list_segments(&self) -> EIRes<Vec<(String, SegmentId)>>;
496
497    fn list_indexes(&self) -> EIRes<Vec<(String, IndexInfo)>>;
498
499    fn scan(&self, segment: &str) -> EIRes<Box<dyn Iterator<Item = (PersyId, Vec<u8>)>>>;
500
501    fn range<K, V, R>(&self, index_name: &str, range: R) -> EIRes<Box<dyn Iterator<Item = (K, ValueIter<V>)>>>
502    where
503        K: IndexType + 'static,
504        V: IndexType + 'static,
505        R: RangeBounds<K>;
506}
507
508impl PersyReader for Persy {
509    fn list_segments(&self) -> EIRes<Vec<(String, SegmentId)>> {
510        Ok(self.list_segments()?)
511    }
512    fn list_indexes(&self) -> EIRes<Vec<(String, IndexInfo)>> {
513        Ok(self.list_indexes()?)
514    }
515    fn scan(&self, segment: &str) -> EIRes<Box<dyn Iterator<Item = (PersyId, Vec<u8>)>>> {
516        Ok(Box::new(self.scan(segment)?))
517    }
518    fn range<K, V, R>(&self, index_name: &str, range: R) -> EIRes<Box<dyn Iterator<Item = (K, ValueIter<V>)>>>
519    where
520        K: IndexType + 'static,
521        V: IndexType + 'static,
522        R: RangeBounds<K>,
523    {
524        Ok(Box::new(self.range::<K, V, R>(index_name, range)?))
525    }
526}
527impl PersyReader for Snapshot {
528    fn list_segments(&self) -> EIRes<Vec<(String, SegmentId)>> {
529        Ok(self.list_segments()?)
530    }
531
532    fn list_indexes(&self) -> EIRes<Vec<(String, IndexInfo)>> {
533        Ok(self.list_indexes()?)
534    }
535
536    fn scan(&self, segment: &str) -> EIRes<Box<dyn Iterator<Item = (PersyId, Vec<u8>)>>> {
537        Ok(Box::new(self.scan(segment)?))
538    }
539    fn range<K, V, R>(&self, index_name: &str, range: R) -> EIRes<Box<dyn Iterator<Item = (K, ValueIter<V>)>>>
540    where
541        K: IndexType + 'static,
542        V: IndexType + 'static,
543        R: RangeBounds<K>,
544    {
545        Ok(Box::new(self.range::<K, V, R>(index_name, range)?))
546    }
547}
548
549///
550/// Export the data from a persy storage with a custom format
551///
552/// # Example
553/// ```
554/// use persy::{Persy, Config};
555/// use persy_expimp::export;
556/// use std::vec::Vec;
557/// # use persy_expimp::EIRes;
558/// # fn foo() -> EIRes<()> {
559/// let persy = Persy::open("file.persy", Config::new())?;
560/// for info in export(&persy)? {
561///     // Custom logic
562/// }
563/// # Ok(())
564/// # }
565/// ```
566pub fn export(persy_p: &Persy) -> EIRes<Box<impl Iterator<Item = Info>>> {
567    export_from_reader(persy_p)
568}
569fn export_from_reader<T: PersyReader + 'static>(persy_p: &T) -> EIRes<Box<impl Iterator<Item = Info>>> {
570    let persy = persy_p.clone();
571    let segs = persy.list_segments()?.into_iter();
572    let indexes = persy.list_indexes()?.into_iter();
573    let p_keys = persy.clone();
574    let all_keys = indexes
575        .clone()
576        .map(move |i| iter_keys(p_keys.clone(), i))
577        .flatten()
578        .flatten();
579    let indexes_info = indexes.map(|(name, infos)| {
580        Info::Index(IndexMetadata {
581            version: 0,
582            name,
583            id: infos.id,
584            key_type: infos.key_type,
585            value_type: infos.value_type,
586            value_mode: infos.value_mode,
587        })
588    });
589    let all_records = segs
590        .clone()
591        .map(move |(name, _)| -> EIRes<_> {
592            Ok(persy.clone().scan(&name)?.map(move |(id, content)| {
593                Info::Record(Record {
594                    version: 0,
595                    segment: name.clone(),
596                    id,
597                    content,
598                })
599            }))
600        })
601        .flatten()
602        .flatten();
603    let segs_info = segs.map(|(name, id)| Info::Segment(SegmentMetadata { version: 0, name, id }));
604    Ok(Box::new(
605        segs_info.chain(indexes_info).chain(all_records).chain(all_keys),
606    ))
607}
608
609///
610/// Export the data from a snapshot of persy storage with a custom format
611///
612/// # Example
613/// ```
614/// use persy::{Persy, Config};
615/// use persy_expimp::export_from_snapshot;
616/// use std::vec::Vec;
617/// # use persy_expimp::EIRes;
618/// # fn foo() -> EIRes<()> {
619/// let persy = Persy::open("file.persy", Config::new())?;
620/// let snapshot = persy.snapshot()?;
621/// for info in export_from_snapshot(&snapshot)? {
622///     // Custom logic
623/// }
624/// # Ok(())
625/// # }
626/// ```
627pub fn export_from_snapshot(persy_p: &Snapshot) -> EIRes<Box<impl Iterator<Item = Info>>> {
628    export_from_reader(persy_p)
629}
630
631/// Import the data to a persy storage from a custom format
632///
633/// # Example
634/// ```
635/// use persy::{Persy, Config};
636/// use persy_expimp::{import,Info};
637/// # use persy_expimp::EIRes;
638/// # fn foo() -> EIRes<()> {
639/// Persy::create("imported.persy")?;
640/// let persy = Persy::open("imported.persy", Config::new())?;
641/// // Source informations from a custom source
642/// let source = Vec::<Info>::new();
643/// import(&persy,source.into_iter())?;
644/// # Ok(())
645/// # }
646/// ```
647pub fn import<I>(persy: &Persy, importer: I) -> EIRes<()>
648where
649    I: Iterator<Item = Info>,
650{
651    import_with_handler(persy, importer, NothingHandler())
652}
653
654/// Import the data to a persy storage from a custom format
655///
656/// # Example
657/// ```
658/// use persy::{Persy, Config};
659/// use persy_expimp::{import_with_handler,Info, Handler, Mapper};
660/// # use persy_expimp::EIRes;
661/// # fn foo() -> EIRes<()> {
662///
663/// struct HandlerImpl{ //...
664/// };
665///
666/// impl Handler for  HandlerImpl {
667///    fn pre(&self, _persy: &Persy, _mapper: &Mapper) -> EIRes<()> {
668///        //....
669///        Ok(())
670///    }
671///    fn post(&self, _persy: &Persy, _mapper: &Mapper) -> EIRes<()> {
672///        //....
673///        Ok(())
674///    }
675/// }
676/// Persy::create("imported.persy")?;
677/// let persy = Persy::open("imported.persy", Config::new())?;
678/// // Source informations from a custom source
679/// let source = Vec::<Info>::new();
680/// import_with_handler(&persy,source.into_iter(), HandlerImpl{})?;
681/// # Ok(())
682/// # }
683/// ```
684pub fn import_with_handler<I, H>(persy: &Persy, importer: I, handler: H) -> EIRes<()>
685where
686    I: Iterator<Item = Info>,
687    H: Handler,
688{
689    let mut tx = persy.begin()?;
690    create_map_persy_id_index(&mut tx)?;
691    tx.prepare()?.commit()?;
692    let mapper = Mapper::new(persy);
693    handler.pre(persy, &mapper)?;
694    for val in importer {
695        let mut tx = persy.begin()?;
696        match val {
697            Info::Segment(segment) => {
698                tx.create_segment(&segment.name)?;
699            }
700            Info::Record(record) => {
701                let inserted_id = tx.insert(&record.segment, &record.content)?;
702                remap_persy_id(&mut tx, record.id, inserted_id)?;
703            }
704            Info::Index(index) => {
705                create_index(&mut tx, index)?;
706            }
707            Info::Entry(entry) => {
708                put_entry(&mut tx, entry)?;
709            }
710        }
711        let prep = tx.prepare()?;
712        prep.commit()?;
713    }
714    handler.post(persy, &mapper)?;
715    let mut tx = persy.begin()?;
716    drop_map_persy_id_index(&mut tx)?;
717    tx.prepare()?.commit()?;
718    Ok(())
719}
720
721pub trait Handler {
722    fn pre(&self, persy: &Persy, mapper: &Mapper) -> EIRes<()>;
723    fn post(&self, persy: &Persy, mapper: &Mapper) -> EIRes<()>;
724}
725struct NothingHandler();
726
727impl Handler for NothingHandler {
728    fn pre(&self, _persy: &Persy, _mapper: &Mapper) -> EIRes<()> {
729        Ok(())
730    }
731    fn post(&self, _persy: &Persy, _mapper: &Mapper) -> EIRes<()> {
732        Ok(())
733    }
734}
735
736pub struct Mapper {
737    persy: Persy,
738}
739impl Mapper {
740    fn new(persy: &Persy) -> Self {
741        Self { persy: persy.clone() }
742    }
743    pub fn map(&self, id: PersyId) -> EIRes<PersyId> {
744        map_persy_id_out(&self.persy, id)
745    }
746}
747
748#[cfg(test)]
749mod tests {
750    use super::{export, export_from_snapshot, import, Info};
751    use persy::{ByteVec, Config, IndexType, Persy, PersyId, Transaction, ValueMode};
752    use std::fs;
753
754    fn util<C, V>(name: &str, create: C, verify: V)
755    where
756        C: FnOnce(&mut Transaction),
757        V: FnOnce(&Persy),
758    {
759        let c_name = format!("target/{}.pei", name);
760        let rec_name = format!("target/{}_fill.pei", name);
761        Persy::create(c_name.to_string()).expect("creation works fine");
762        let p = Persy::open(c_name.to_string(), Config::new()).expect("open fine");
763        let mut tx = p.begin().unwrap();
764        create(&mut tx);
765        let prep = tx.prepare().unwrap();
766        prep.commit().unwrap();
767        let data: Vec<Info> = export(&p).unwrap().collect();
768
769        Persy::create(rec_name.to_string()).expect("creation works fine");
770        let p1 = Persy::open(rec_name.to_string(), Config::new()).expect("open fine");
771        import(&p1, data.into_iter()).unwrap();
772        verify(&p1);
773        fs::remove_file(c_name).unwrap();
774        fs::remove_file(rec_name).unwrap();
775    }
776
777    #[test]
778    fn base_snapshot_export_import() {
779        let name = "snapshot";
780        let c_name = format!("target/{}.pei", name);
781        let rec_name = format!("target/{}_fill.pei", name);
782        Persy::create(c_name.to_string()).expect("creation works fine");
783        let p = Persy::open(c_name.to_string(), Config::new()).expect("open fine");
784        let mut tx = p.begin().unwrap();
785        tx.create_segment("test").unwrap();
786        tx.insert("test", &"test".to_string().as_bytes()).unwrap();
787        tx.create_index::<u8, u8>("test_u8", ValueMode::Replace).unwrap();
788        tx.put::<u8, u8>("test_u8", 10, 10).unwrap();
789        let prep = tx.prepare().unwrap();
790        prep.commit().unwrap();
791        let data: Vec<Info> = export_from_snapshot(&p.snapshot().unwrap()).unwrap().collect();
792
793        Persy::create(rec_name.to_string()).expect("creation works fine");
794        let p1 = Persy::open(rec_name.to_string(), Config::new()).expect("open fine");
795        import(&p1, data.into_iter()).unwrap();
796
797        for (_, content) in p.scan("test").unwrap() {
798            assert_eq!("test".to_string().as_bytes().to_vec(), content);
799        }
800        check_key_value(&p1, "test_u8", 10 as u8, 10 as u8);
801        fs::remove_file(c_name).unwrap();
802        fs::remove_file(rec_name).unwrap();
803    }
804
805    #[test]
806    fn segment_metadata_export_import() {
807        util(
808            "segment",
809            |tx| {
810                tx.create_segment("test").unwrap();
811            },
812            |p| {
813                assert!(p.exists_segment("test").unwrap());
814            },
815        );
816    }
817    #[test]
818    fn index_metadata_export_import() {
819        util(
820            "index",
821            |tx| {
822                tx.create_index::<u8, u8>("test", ValueMode::Replace).unwrap();
823            },
824            |p| {
825                assert!(p.exists_index("test").unwrap());
826            },
827        );
828    }
829
830    #[test]
831    fn segment_data_export_import() {
832        util(
833            "segment_data",
834            |tx| {
835                tx.create_segment("test").unwrap();
836                tx.insert("test", &"test".to_string().as_bytes()).unwrap();
837            },
838            |p| {
839                for (_, content) in p.scan("test").unwrap() {
840                    assert_eq!("test".to_string().as_bytes().to_vec(), content);
841                }
842            },
843        );
844    }
845    #[test]
846    fn index_data_export_import() {
847        util(
848            "index_data",
849            |tx| {
850                tx.create_index::<u8, u8>("test", ValueMode::Replace).unwrap();
851                tx.put::<u8, u8>("test", 10, 10).unwrap();
852            },
853            |p| assert_eq!(10, p.get::<u8, u8>("test", &10).unwrap().into_iter().next().unwrap()),
854        );
855    }
856
857    #[test]
858    fn all_data_export_import() {
859        util(
860            "all_data",
861            |tx| {
862                tx.create_segment("test").unwrap();
863                let persy_id = tx.insert("test", &"test".to_string().as_bytes()).unwrap();
864                tx.create_index::<u8, u8>("test_u8", ValueMode::Replace).unwrap();
865                tx.put::<u8, u8>("test_u8", 10, 10).unwrap();
866                tx.create_index::<u16, u16>("test_u16", ValueMode::Replace).unwrap();
867                tx.put::<u16, u16>("test_u16", 10, 10).unwrap();
868                tx.create_index::<u32, u32>("test_u32", ValueMode::Replace).unwrap();
869                tx.put::<u32, u32>("test_u32", 10, 10).unwrap();
870                tx.create_index::<u64, u64>("test_u64", ValueMode::Replace).unwrap();
871                tx.put::<u64, u64>("test_u64", 10, 10).unwrap();
872                tx.create_index::<u128, u128>("test_u128", ValueMode::Replace).unwrap();
873                tx.put::<u128, u128>("test_u128", 10, 10).unwrap();
874                tx.create_index::<i8, i8>("test_i8", ValueMode::Replace).unwrap();
875                tx.put::<i8, i8>("test_i8", 10, 10).unwrap();
876                tx.create_index::<i16, i16>("test_i16", ValueMode::Replace).unwrap();
877                tx.put::<i16, i16>("test_i16", 10, 10).unwrap();
878                tx.create_index::<i32, i32>("test_i32", ValueMode::Replace).unwrap();
879                tx.put::<i32, i32>("test_i32", 10, 10).unwrap();
880                tx.create_index::<i64, i64>("test_i64", ValueMode::Replace).unwrap();
881                tx.put::<i64, i64>("test_i64", 10, 10).unwrap();
882                tx.create_index::<i128, i128>("test_i128", ValueMode::Replace).unwrap();
883                tx.put::<i128, i128>("test_i128", 10, 10).unwrap();
884                tx.create_index::<f32, f32>("test_f32", ValueMode::Replace).unwrap();
885                tx.put::<f32, f32>("test_f32", 10.0, 10.0).unwrap();
886                tx.create_index::<f64, f64>("test_f64", ValueMode::Replace).unwrap();
887                tx.put::<f64, f64>("test_f64", 10.0, 10.0).unwrap();
888                tx.create_index::<String, String>("test_string", ValueMode::Replace)
889                    .unwrap();
890                tx.put::<String, String>("test_string", "one".to_string(), "two".to_string())
891                    .unwrap();
892                tx.create_index::<ByteVec, ByteVec>("test_bytevec", ValueMode::Replace)
893                    .unwrap();
894                let bv = ByteVec::new(vec![20, 10]);
895                let bv1 = ByteVec::new(vec![10, 20]);
896                tx.put::<ByteVec, ByteVec>("test_bytevec", bv, bv1).unwrap();
897                tx.create_index::<PersyId, PersyId>("test_p", ValueMode::Replace)
898                    .unwrap();
899                tx.put::<PersyId, PersyId>("test_p", persy_id.clone(), persy_id)
900                    .unwrap();
901            },
902            |p| {
903                for (_, content) in p.scan("test").unwrap() {
904                    assert_eq!("test".to_string().as_bytes().to_vec(), content);
905                }
906                check_key_value(p, "test_u8", 10 as u8, 10 as u8);
907                check_key_value(p, "test_u16", 10 as u16, 10 as u16);
908                check_key_value(p, "test_u32", 10 as u32, 10 as u32);
909                check_key_value(p, "test_u64", 10 as u64, 10 as u64);
910                check_key_value(p, "test_u128", 10 as u128, 10 as u128);
911                check_key_value(p, "test_i8", 10 as i8, 10 as i8);
912                check_key_value(p, "test_i16", 10 as i16, 10 as i16);
913                check_key_value(p, "test_i32", 10 as i32, 10 as i32);
914                check_key_value(p, "test_i64", 10 as i64, 10 as i64);
915                check_key_value(p, "test_i128", 10 as i128, 10 as i128);
916                check_key_value(p, "test_f32", 10 as f32, 10 as f32);
917                check_key_value(p, "test_f64", 10 as f64, 10 as f64);
918                check_key_value(p, "test_string", "one".to_string(), "two".to_string());
919                let bv = ByteVec::new(vec![20, 10]);
920                let bv1 = ByteVec::new(vec![10, 20]);
921                check_key_value(p, "test_bytevec", bv, bv1);
922                assert_eq!(
923                    1,
924                    p.range::<PersyId, PersyId, _>("test_p", ..)
925                        .unwrap()
926                        .into_iter()
927                        .count()
928                );
929            },
930        );
931    }
932
933    pub fn check_key_value<K: IndexType + PartialEq, V: IndexType + PartialEq + std::fmt::Debug>(
934        p: &Persy,
935        index: &str,
936        k: K,
937        v: V,
938    ) {
939        assert_eq!(v, p.get::<K, V>(index, &k).unwrap().into_iter().next().unwrap());
940    }
941
942    #[test]
943    fn index_id_mapping() {
944        util(
945            "id_mapping",
946            |tx| {
947                tx.create_segment("test").unwrap();
948                let id = tx.insert("test", "xxx".as_bytes()).unwrap();
949                tx.create_index::<u8, PersyId>("test", ValueMode::Replace).unwrap();
950                tx.put::<u8, PersyId>("test", 10, id).unwrap();
951            },
952            |p| {
953                let id = p.get::<u8, PersyId>("test", &10).unwrap().next().unwrap();
954                assert_eq!(Some("xxx".as_bytes().into()), p.read("test", &id).unwrap());
955            },
956        );
957    }
958}