1
use std::fmt::Debug;
2

            
3
use serde::{de::DeserializeOwned, Serialize};
4
use transmog::{Format, OwnedDeserializer};
5
use transmog_pot::Pot;
6

            
7
use crate::{
8
    document::{BorrowedDocument, CollectionDocument},
9
    key::Key,
10
    schema::{
11
        view::map::{Mappings, ViewMappedValue},
12
        Collection, CollectionName, Name, SerializedCollection, ViewName,
13
    },
14
    AnyError,
15
};
16

            
17
/// Types for defining a `Map` within a `View`.
18
pub mod map;
19

            
20
/// Errors that arise when interacting with views.
21
#[derive(thiserror::Error, Debug)]
22
// TODO add which view name and collection
23
pub enum Error {
24
    /// An error occurred while serializing or deserializing keys emitted in a view.
25
    #[error("error serializing view keys {0}")]
26
    KeySerialization(Box<dyn AnyError>),
27

            
28
    /// An error unrelated to views.
29
    #[error("core error: {0}")]
30
    Core(#[from] crate::Error),
31
}
32

            
33
impl Error {
34
    /// Returns a [`Self::KeySerialization`] instance after boxing the error.
35
    pub fn key_serialization<E: AnyError>(error: E) -> Self {
36
        Self::KeySerialization(Box::new(error))
37
    }
38
}
39

            
40
impl From<pot::Error> for Error {
41
    fn from(err: pot::Error) -> Self {
42
        Self::Core(crate::Error::from(err))
43
    }
44
}
45

            
46
/// A type alias for the result of `ViewSchema::map()`.
47
pub type ViewMapResult<V> = Result<Mappings<<V as View>::Key, <V as View>::Value>, crate::Error>;
48

            
49
/// A type alias for the result of `ViewSchema::reduce()`.
50
pub type ReduceResult<V> = Result<<V as View>::Value, crate::Error>;
51

            
52
/// An lazy index of mapped and/or reduced data from a [`Collection`].
53
///
54
/// A view provides an efficient way to query data within a collection. BonsaiDb
55
/// indexes the associated [`View::Collection`] by calling
56
/// [`CollectionViewSchema::map()`]/[`ViewSchema::map()`] every time a document
57
/// is created or updated. The result [`Mappings`] form a sorted index that can
58
/// be efficiently queried using the [`View::Key`] type.
59
///
60
/// A View behaves similarly to the standard library's BTreeMap with these
61
/// types: `BTreeMap<View::Key, Vec<(Header, View::Value)>>`
62
///
63
/// For a deeper dive on Views, see [the section in our user's
64
/// guide](https://dev.bonsaidb.io/main/guide/about/concepts/view.html).
65
#[doc = "\n"]
66
#[doc = include_str!("./view-overview.md")]
67
pub trait View: Send + Sync + Debug + 'static {
68
    /// The collection this view belongs to
69
    type Collection: Collection;
70
    /// The key for this view.
71
    type Key: for<'a> Key<'a> + 'static;
72
    /// An associated type that can be stored with each entry in the view.
73
    type Value: Send + Sync;
74

            
75
    /// The name of the view. Must be unique per collection.
76
    fn name(&self) -> Name;
77

            
78
    /// The namespaced name of the view.
79
14396263
    fn view_name(&self) -> ViewName {
80
14396263
        ViewName {
81
14396263
            collection: Self::Collection::collection_name(),
82
14396263
            name: self.name(),
83
14396263
        }
84
14396263
    }
85
}
86

            
87
/// The implementation of Map/Reduce for a [`View`].
88
#[doc = "\n"]
89
#[doc = include_str!("./view-overview.md")]
90
pub trait ViewSchema: Send + Sync + Debug + 'static {
91
    /// The view this schema is defined for.
92
    type View: SerializedView;
93

            
94
    /// If true, no two documents may emit the same key. Unique views are
95
    /// updated when the document is saved, allowing for this check to be done
96
    /// atomically. When a document is updated, all unique views will be
97
    /// updated, and if any of them fail, the document will not be allowed to
98
    /// update and an
99
    /// [`Error::UniqueKeyViolation`](crate::Error::UniqueKeyViolation) will be
100
    /// returned.
101
13773227
    fn unique(&self) -> bool {
102
13773227
        false
103
13773227
    }
104

            
105
    /// The version of the view. Changing this value will cause indexes to be rebuilt.
106
3910
    fn version(&self) -> u64 {
107
3910
        0
108
3910
    }
109

            
110
    /// The map function for this view. This function is responsible for
111
    /// emitting entries for any documents that should be contained in this
112
    /// View. If None is returned, the View will not include the document. See [the user guide's chapter on
113
    /// views for more information on how map
114
    /// works](https://dev.bonsaidb.io/main/guide/about/concepts/view.html#map).
115
    fn map(&self, document: &BorrowedDocument<'_>) -> ViewMapResult<Self::View>;
116

            
117
    /// Returns a value that is produced by reducing a list of `mappings` into a
118
    /// single value. If `rereduce` is true, the values contained in the
119
    /// mappings have already been reduced at least one time. If an error of
120
    /// [`ReduceUnimplemented`](crate::Error::ReduceUnimplemented) is returned,
121
    /// queries that ask for a reduce operation will return an error. See [the
122
    /// user guide's chapter on views for more information on how reduce
123
    /// works](https://dev.bonsaidb.io/main/guide/about/concepts/view.html#reduce).
124
    #[allow(unused_variables)]
125
1519
    fn reduce(
126
1519
        &self,
127
1519
        mappings: &[ViewMappedValue<Self::View>],
128
1519
        rereduce: bool,
129
1519
    ) -> Result<<Self::View as View>::Value, crate::Error> {
130
1519
        Err(crate::Error::ReduceUnimplemented)
131
1519
    }
132
}
133

            
134
/// A [`View`] with additional tyes and logic to handle serializing view values.
135
pub trait SerializedView: View {
136
    /// The serialization format for this view.
137
    type Format: OwnedDeserializer<Self::Value>;
138

            
139
    /// Returns the configured instance of [`Self::Format`].
140
    // TODO allow configuration to be passed here, such as max allocation bytes.
141
    fn format() -> Self::Format;
142

            
143
    /// Deserialize `data` as `Self::Value` using this views's format.
144
108260
    fn deserialize(data: &[u8]) -> Result<Self::Value, crate::Error> {
145
108260
        Self::format()
146
108260
            .deserialize_owned(data)
147
108260
            .map_err(|err| crate::Error::Serialization(err.to_string()))
148
108260
    }
149

            
150
    /// Serialize `item` using this views's format.
151
66182
    fn serialize(item: &Self::Value) -> Result<Vec<u8>, crate::Error> {
152
66182
        Self::format()
153
66182
            .serialize(item)
154
66182
            .map_err(|err| crate::Error::Serialization(err.to_string()))
155
66182
    }
156
}
157

            
158
/// A default serialization strategy for views. Uses equivalent settings as
159
/// [`DefaultSerialization`](crate::schema::DefaultSerialization).
160
pub trait DefaultViewSerialization: View {}
161

            
162
impl<T> SerializedView for T
163
where
164
    T: DefaultViewSerialization,
165
    T::Value: Serialize + DeserializeOwned,
166
{
167
    type Format = Pot;
168

            
169
174010
    fn format() -> Self::Format {
170
174010
        Pot::default()
171
174010
    }
172
}
173

            
174
/// A [`View`] for a [`Collection`] that stores Serde-compatible documents. The
175
/// only difference between implmementing this and [`View`] is that the `map`
176
/// function receives a [`CollectionDocument`] instead of a [`BorrowedDocument`].
177
pub trait CollectionViewSchema: Send + Sync + Debug + 'static
178
where
179
    <Self::View as View>::Collection: SerializedCollection,
180
{
181
    /// The view this schema is an implementation of.
182
    type View: SerializedView;
183

            
184
    /// If true, no two documents may emit the same key. Unique views are
185
    /// updated when the document is saved, allowing for this check to be done
186
    /// atomically. When a document is updated, all unique views will be
187
    /// updated, and if any of them fail, the document will not be allowed to
188
    /// update and an
189
    /// [`Error::UniqueKeyViolation`](crate::Error::UniqueKeyViolation) will be
190
    /// returned.
191
63861
    fn unique(&self) -> bool {
192
63861
        false
193
63861
    }
194

            
195
    /// The version of the view. Changing this value will cause indexes to be rebuilt.
196
1205
    fn version(&self) -> u64 {
197
1205
        0
198
1205
    }
199

            
200
    /// The map function for this view. This function is responsible for
201
    /// emitting entries for any documents that should be contained in this
202
    /// View. If None is returned, the View will not include the document.
203
    fn map(
204
        &self,
205
        document: CollectionDocument<<Self::View as View>::Collection>,
206
    ) -> ViewMapResult<Self::View>;
207

            
208
    /// The reduce function for this view. If `Err(Error::ReduceUnimplemented)`
209
    /// is returned, queries that ask for a reduce operation will return an
210
    /// error. See [`CouchDB`'s Reduce/Rereduce
211
    /// documentation](https://docs.couchdb.org/en/stable/ddocs/views/intro.html#reduce-rereduce)
212
    /// for the design this implementation will be inspired by
213
    #[allow(unused_variables)]
214
40245
    fn reduce(
215
40245
        &self,
216
40245
        mappings: &[ViewMappedValue<Self::View>],
217
40245
        rereduce: bool,
218
40245
    ) -> ReduceResult<Self::View> {
219
40245
        Err(crate::Error::ReduceUnimplemented)
220
40245
    }
221
}
222

            
223
impl<T> ViewSchema for T
224
where
225
    T: CollectionViewSchema,
226
    T::View: SerializedView,
227
    <T::View as View>::Collection: SerializedCollection,
228
{
229
    type View = T::View;
230

            
231
50353
    fn version(&self) -> u64 {
232
50353
        T::version(self)
233
50353
    }
234

            
235
42385
    fn map(&self, document: &BorrowedDocument<'_>) -> ViewMapResult<Self::View> {
236
42385
        T::map(self, CollectionDocument::try_from(document)?)
237
42385
    }
238

            
239
51469
    fn reduce(
240
51469
        &self,
241
51469
        mappings: &[ViewMappedValue<Self::View>],
242
51469
        rereduce: bool,
243
51469
    ) -> Result<<Self::View as View>::Value, crate::Error> {
244
51469
        T::reduce(self, mappings, rereduce)
245
51469
    }
246

            
247
629186
    fn unique(&self) -> bool {
248
629186
        T::unique(self)
249
629186
    }
250
}
251

            
252
/// Wraps a [`View`] with serialization to erase the associated types
253
pub trait Serialized: Send + Sync + Debug {
254
    /// Wraps returing [`<View::Collection as Collection>::collection_name()`](crate::schema::Collection::collection_name)
255
    fn collection(&self) -> CollectionName;
256
    /// Wraps [`ViewSchema::unique`]
257
    fn unique(&self) -> bool;
258
    /// Wraps [`ViewSchema::version`]
259
    fn version(&self) -> u64;
260
    /// Wraps [`View::view_name`]
261
    fn view_name(&self) -> ViewName;
262
    /// Wraps [`ViewSchema::map`]
263
    fn map(&self, document: &BorrowedDocument<'_>) -> Result<Vec<map::Serialized>, Error>;
264
    /// Wraps [`ViewSchema::reduce`]
265
    fn reduce(&self, mappings: &[(&[u8], &[u8])], rereduce: bool) -> Result<Vec<u8>, Error>;
266
}
267

            
268
/// Defines an unique view named `$view_name` for `$collection` with the
269
/// mapping provided.
270
#[macro_export(local_inner_macros)]
271
macro_rules! define_basic_unique_mapped_view {
272
    ($view_name:ident, $collection:ty, $version:literal, $name:literal, $key:ty, $mapping:expr $(,)?) => {
273
        define_mapped_view!(
274
            $view_name,
275
            $collection,
276
            $version,
277
            $name,
278
            $key,
279
            (),
280
            true,
281
            $mapping
282
        );
283
    };
284
    ($view_name:ident, $collection:ty, $version:literal, $name:literal, $key:ty, $value:ty, $mapping:expr $(,)?) => {
285
        define_mapped_view!(
286
            $view_name,
287
            $collection,
288
            $version,
289
            $name,
290
            $key,
291
            $value,
292
            true,
293
            $mapping
294
        );
295
    };
296
}
297

            
298
/// Defines a non-unique view named `$view_name` for `$collection` with the
299
/// mapping provided.
300
#[macro_export(local_inner_macros)]
301
macro_rules! define_basic_mapped_view {
302
    ($view_name:ident, $collection:ty, $version:literal, $name:literal, $key:ty, $mapping:expr $(,)?) => {
303
        define_mapped_view!(
304
            $view_name,
305
            $collection,
306
            $version,
307
            $name,
308
            $key,
309
            (),
310
            false,
311
            $mapping
312
        );
313
    };
314
    ($view_name:ident, $collection:ty, $version:literal, $name:literal, $key:ty, $value:ty, $mapping:expr $(,)?) => {
315
        define_mapped_view!(
316
            $view_name,
317
            $collection,
318
            $version,
319
            $name,
320
            $key,
321
            $value,
322
            false,
323
            $mapping
324
        );
325
    };
326
}
327

            
328
/// Defines a view using the mapping provided.
329
#[macro_export]
330
macro_rules! define_mapped_view {
331
    ($view_name:ident, $collection:ty, $version:literal, $name:literal, $key:ty, $value:ty, $unique:literal, $mapping:expr) => {
332
359428
        #[derive(Debug, Clone)]
333
        pub struct $view_name;
334

            
335
        impl $crate::schema::View for $view_name {
336
            type Collection = $collection;
337
            type Key = $key;
338
            type Value = $value;
339

            
340
742728
            fn name(&self) -> $crate::schema::Name {
341
742728
                $crate::schema::Name::new($name)
342
742728
            }
343
        }
344

            
345
        impl $crate::schema::CollectionViewSchema for $view_name {
346
            type View = Self;
347

            
348
565232
            fn unique(&self) -> bool {
349
565232
                $unique
350
565232
            }
351

            
352
49148
            fn version(&self) -> u64 {
353
49148
                $version
354
49148
            }
355

            
356
40639
            fn map(
357
40639
                &self,
358
40639
                document: $crate::document::CollectionDocument<$collection>,
359
40639
            ) -> $crate::schema::ViewMapResult<Self::View> {
360
40639
                $mapping(document)
361
40639
            }
362
        }
363

            
364
        impl $crate::schema::view::DefaultViewSerialization for $view_name {}
365
    };
366
}