Skip to main content

coven_database/
write_batch.rs

1//! The app bytes one staging writes to coven's copies of them, each file
2//! given its new id (§17.2).
3
4use coven_foundation::id_source::{FileId, IdSource};
5use std::pin::Pin;
6use tokio::io::AsyncRead;
7
8/// App bytes to stage, before the write that puts them in rows; a failure
9/// discards all of them. Each staged file gets a new id from the store's id
10/// source, which the batch borrows while the app stages; the write's SQL
11/// puts the id in the rows that reference the file.
12pub struct WriteBatch<'a> {
13    ids: &'a dyn IdSource,
14    files: Vec<BatchFile>,
15}
16
17/// A new file over an existing file's bytes: its new id, and the file whose
18/// bytes, namespace, place and key it takes (§17.2).
19#[derive(Clone, Copy, Debug)]
20pub(crate) struct ExistingFile {
21    pub(crate) id: FileId,
22    pub(crate) from: FileId,
23}
24
25/// One staged file: its id, its namespace, its bytes, and where it is to be.
26pub(crate) struct BatchFile {
27    pub(crate) id: FileId,
28    pub(crate) namespace: String,
29    pub(crate) source: FileSource,
30    pub(crate) place: Place,
31}
32
33/// Where a staged file is to be: on this device only, or uploaded to the
34/// cloud (§17.3).
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub enum Place {
37    /// On this device only, with no upload.
38    DeviceOnly,
39    /// Uploaded; on this device only until its upload is stored.
40    Cloud,
41    /// Uploaded, as `Cloud`, and kept whole here too once stored: the write
42    /// switching it to the cloud pins it on this device, which makes its
43    /// cache copy from coven's copy of app bytes, and downloads a user's
44    /// original's from storage, never reading the original (§17.8).
45    CloudKeptHere,
46}
47
48impl<'a> WriteBatch<'a> {
49    pub(crate) fn new(ids: &'a dyn IdSource) -> Self {
50        Self { ids, files: Vec::new() }
51    }
52
53    /// The files staged, for the staging that copies them in.
54    pub(crate) fn into_files(self) -> Vec<BatchFile> {
55        self.files
56    }
57
58    /// Stage app bytes as a new file in an app namespace, kept in coven's
59    /// own copy: on this device only, or for the cloud. A stream is consumed
60    /// once and never buffered whole. Returns the file's id for a row to
61    /// reference.
62    pub fn put_file(
63        &mut self,
64        namespace: &str,
65        bytes: impl Into<FileSource>,
66        place: Place,
67    ) -> FileId {
68        let id = FileId(self.ids.new_id());
69        self.files.push(BatchFile {
70            id,
71            namespace: namespace.to_owned(),
72            source: bytes.into(),
73            place,
74        });
75        id
76    }
77}
78
79/// An owned buffer or a reader whose stream coven consumes exactly once.
80pub enum FileSource {
81    /// Bytes already held by the app.
82    Bytes(Vec<u8>),
83    /// A stream read in bounded chunks.
84    Stream(Pin<Box<dyn AsyncRead + Send>>),
85}
86
87impl From<Vec<u8>> for FileSource {
88    fn from(bytes: Vec<u8>) -> Self {
89        Self::Bytes(bytes)
90    }
91}