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
#[allow(type_alias_bounds)] // False positive, required for associated types
48
pub type ViewMapResult<V: View> = Result<Mappings<V::Key, V::Value>, crate::Error>;
49

            
50
/// A type alias for the result of `ViewSchema::reduce()`.
51
#[allow(type_alias_bounds)] // False positive, required for associated types
52
pub type ReduceResult<V: View> = Result<V::Value, crate::Error>;
53

            
54
/// A mechanism for accessing mapped and/or reduced data from a [`Collection`].
55
#[doc = "\n"]
56
#[doc = include_str!("./view-overview.md")]
57
pub trait View: Send + Sync + Debug + 'static {
58
    /// The collection this view belongs to
59
    type Collection: Collection;
60
    /// The key for this view.
61
    type Key: for<'a> Key<'a> + 'static;
62
    /// An associated type that can be stored with each entry in the view.
63
    type Value: Send + Sync;
64

            
65
    /// The name of the view. Must be unique per collection.
66
    fn name(&self) -> Name;
67

            
68
    /// The namespaced name of the view.
69
8936909
    fn view_name(&self) -> ViewName {
70
8936909
        ViewName {
71
8936909
            collection: Self::Collection::collection_name(),
72
8936909
            name: self.name(),
73
8936909
        }
74
8936909
    }
75
}
76

            
77
/// The implementation of Map/Reduce for a [`View`].
78
#[doc = "\n"]
79
#[doc = include_str!("./view-overview.md")]
80
pub trait ViewSchema: Send + Sync + Debug + 'static {
81
    /// The view this schema is defined for.
82
    type View: SerializedView;
83

            
84
    /// If true, no two documents may emit the same key. Unique views are
85
    /// updated when the document is saved, allowing for this check to be done
86
    /// atomically. When a document is updated, all unique views will be
87
    /// updated, and if any of them fail, the document will not be allowed to
88
    /// update and an
89
    /// [`Error::UniqueKeyViolation`](crate::Error::UniqueKeyViolation) will be
90
    /// returned.
91
8485614
    fn unique(&self) -> bool {
92
8485614
        false
93
8485614
    }
94

            
95
    /// The version of the view. Changing this value will cause indexes to be rebuilt.
96
2110
    fn version(&self) -> u64 {
97
2110
        0
98
2110
    }
99

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

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

            
124
/// A [`View`] with additional tyes and logic to handle serializing view values.
125
pub trait SerializedView: View {
126
    /// The serialization format for this view.
127
    type Format: OwnedDeserializer<Self::Value>;
128

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

            
133
    /// Deserialize `data` as `Self::Value` using this views's format.
134
84090
    fn deserialize(data: &[u8]) -> Result<Self::Value, crate::Error> {
135
84090
        Self::format()
136
84090
            .deserialize_owned(data)
137
84090
            .map_err(|err| crate::Error::Serialization(err.to_string()))
138
84090
    }
139

            
140
    /// Serialize `item` using this views's format.
141
45595
    fn serialize(item: &Self::Value) -> Result<Vec<u8>, crate::Error> {
142
45595
        Self::format()
143
45595
            .serialize(item)
144
45595
            .map_err(|err| crate::Error::Serialization(err.to_string()))
145
45595
    }
146
}
147

            
148
/// A default serialization strategy for views. Uses equivalent settings as
149
/// [`DefaultSerialization`](crate::schema::DefaultSerialization).
150
pub trait DefaultViewSerialization: View {}
151

            
152
impl<T> SerializedView for T
153
where
154
    T: DefaultViewSerialization,
155
    T::Value: Serialize + DeserializeOwned,
156
{
157
    type Format = Pot;
158

            
159
129252
    fn format() -> Self::Format {
160
129252
        Pot::default()
161
129252
    }
162
}
163

            
164
/// A [`View`] for a [`Collection`] that stores Serde-compatible documents. The
165
/// only difference between implmementing this and [`View`] is that the `map`
166
/// function receives a [`CollectionDocument`] instead of a [`BorrowedDocument`].
167
pub trait CollectionViewSchema: Send + Sync + Debug + 'static
168
where
169
    <Self::View as View>::Collection: SerializedCollection,
170
{
171
    /// The view this schema is an implementation of.
172
    type View: SerializedView;
173

            
174
    /// If true, no two documents may emit the same key. Unique views are
175
    /// updated when the document is saved, allowing for this check to be done
176
    /// atomically. When a document is updated, all unique views will be
177
    /// updated, and if any of them fail, the document will not be allowed to
178
    /// update and an
179
    /// [`Error::UniqueKeyViolation`](crate::Error::UniqueKeyViolation) will be
180
    /// returned.
181
47540
    fn unique(&self) -> bool {
182
47540
        false
183
47540
    }
184

            
185
    /// The version of the view. Changing this value will cause indexes to be rebuilt.
186
968
    fn version(&self) -> u64 {
187
968
        0
188
968
    }
189

            
190
    /// The map function for this view. This function is responsible for
191
    /// emitting entries for any documents that should be contained in this
192
    /// View. If None is returned, the View will not include the document.
193
    fn map(
194
        &self,
195
        document: CollectionDocument<<Self::View as View>::Collection>,
196
    ) -> ViewMapResult<Self::View>;
197

            
198
    /// The reduce function for this view. If `Err(Error::ReduceUnimplemented)`
199
    /// is returned, queries that ask for a reduce operation will return an
200
    /// error. See [`CouchDB`'s Reduce/Rereduce
201
    /// documentation](https://docs.couchdb.org/en/stable/ddocs/views/intro.html#reduce-rereduce)
202
    /// for the design this implementation will be inspired by
203
    #[allow(unused_variables)]
204
29454
    fn reduce(
205
29454
        &self,
206
29454
        mappings: &[ViewMappedValue<Self::View>],
207
29454
        rereduce: bool,
208
29454
    ) -> ReduceResult<Self::View> {
209
29454
        Err(crate::Error::ReduceUnimplemented)
210
29454
    }
211
}
212

            
213
impl<T> ViewSchema for T
214
where
215
    T: CollectionViewSchema,
216
    T::View: SerializedView,
217
    <T::View as View>::Collection: SerializedCollection,
218
{
219
    type View = T::View;
220

            
221
35634
    fn version(&self) -> u64 {
222
35634
        T::version(self)
223
35634
    }
224

            
225
31226
    fn map(&self, document: &BorrowedDocument<'_>) -> ViewMapResult<Self::View> {
226
31226
        T::map(self, CollectionDocument::try_from(document)?)
227
31226
    }
228

            
229
36924
    fn reduce(
230
36924
        &self,
231
36924
        mappings: &[ViewMappedValue<Self::View>],
232
36924
        rereduce: bool,
233
36924
    ) -> Result<<Self::View as View>::Value, crate::Error> {
234
36924
        T::reduce(self, mappings, rereduce)
235
36924
    }
236

            
237
435118
    fn unique(&self) -> bool {
238
435118
        T::unique(self)
239
435118
    }
240
}
241

            
242
/// Wraps a [`View`] with serialization to erase the associated types
243
pub trait Serialized: Send + Sync + Debug {
244
    /// Wraps returing [`<View::Collection as Collection>::collection_name()`](crate::schema::Collection::collection_name)
245
    fn collection(&self) -> CollectionName;
246
    /// Wraps [`ViewSchema::unique`]
247
    fn unique(&self) -> bool;
248
    /// Wraps [`ViewSchema::version`]
249
    fn version(&self) -> u64;
250
    /// Wraps [`View::view_name`]
251
    fn view_name(&self) -> ViewName;
252
    /// Wraps [`ViewSchema::map`]
253
    fn map(&self, document: &BorrowedDocument<'_>) -> Result<Vec<map::Serialized>, Error>;
254
    /// Wraps [`ViewSchema::reduce`]
255
    fn reduce(&self, mappings: &[(&[u8], &[u8])], rereduce: bool) -> Result<Vec<u8>, Error>;
256
}
257

            
258
/// Defines an unique view named `$view_name` for `$collection` with the
259
/// mapping provided.
260
#[macro_export(local_inner_macros)]
261
macro_rules! define_basic_unique_mapped_view {
262
    ($view_name:ident, $collection:ty, $version:literal, $name:literal, $key:ty, $mapping:expr $(,)?) => {
263
        define_mapped_view!(
264
            $view_name,
265
            $collection,
266
            $version,
267
            $name,
268
            $key,
269
            (),
270
            true,
271
            $mapping
272
        );
273
    };
274
    ($view_name:ident, $collection:ty, $version:literal, $name:literal, $key:ty, $value:ty, $mapping:expr $(,)?) => {
275
        define_mapped_view!(
276
            $view_name,
277
            $collection,
278
            $version,
279
            $name,
280
            $key,
281
            $value,
282
            true,
283
            $mapping
284
        );
285
    };
286
}
287

            
288
/// Defines a non-unique view named `$view_name` for `$collection` with the
289
/// mapping provided.
290
#[macro_export(local_inner_macros)]
291
macro_rules! define_basic_mapped_view {
292
    ($view_name:ident, $collection:ty, $version:literal, $name:literal, $key:ty, $mapping:expr $(,)?) => {
293
        define_mapped_view!(
294
            $view_name,
295
            $collection,
296
            $version,
297
            $name,
298
            $key,
299
            (),
300
            false,
301
            $mapping
302
        );
303
    };
304
    ($view_name:ident, $collection:ty, $version:literal, $name:literal, $key:ty, $value:ty, $mapping:expr $(,)?) => {
305
        define_mapped_view!(
306
            $view_name,
307
            $collection,
308
            $version,
309
            $name,
310
            $key,
311
            $value,
312
            false,
313
            $mapping
314
        );
315
    };
316
}
317

            
318
/// Defines a view using the mapping provided.
319
#[macro_export]
320
macro_rules! define_mapped_view {
321
    ($view_name:ident, $collection:ty, $version:literal, $name:literal, $key:ty, $value:ty, $unique:literal, $mapping:expr) => {
322
235575
        #[derive(Debug, Clone)]
323
        pub struct $view_name;
324

            
325
        impl $crate::schema::View for $view_name {
326
            type Collection = $collection;
327
            type Key = $key;
328
            type Value = $value;
329

            
330
573240
            fn name(&self) -> $crate::schema::Name {
331
573240
                $crate::schema::Name::new($name)
332
573240
            }
333
        }
334

            
335
        impl $crate::schema::CollectionViewSchema for $view_name {
336
            type View = Self;
337

            
338
387526
            fn unique(&self) -> bool {
339
387526
                $unique
340
387526
            }
341

            
342
34666
            fn version(&self) -> u64 {
343
34666
                $version
344
34666
            }
345

            
346
29506
            fn map(
347
29506
                &self,
348
29506
                document: $crate::document::CollectionDocument<$collection>,
349
29506
            ) -> $crate::schema::ViewMapResult<Self::View> {
350
29506
                $mapping(document)
351
29506
            }
352
        }
353

            
354
        impl $crate::schema::view::DefaultViewSerialization for $view_name {}
355
    };
356
}