schemadb/
schema.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4// Copyright 2021 Conflux Foundation. All rights reserved.
5// Conflux is free software and distributed under GNU General Public License.
6// See http://www.gnu.org/licenses/
7
8//! This module provides traits that define the behavior of a schema and its
9//! associated key and value types, along with helpers to define a new schema
10//! with ease.
11use crate::ColumnFamilyName;
12use anyhow::Result;
13use std::fmt::Debug;
14
15/// Macro for defining a SchemaDB schema.
16///
17/// `define_schema!` allows a schema to be defined in the following syntax:
18/// ```
19/// use anyhow::Result;
20/// use schemadb::{
21///     define_schema,
22///     schema::{KeyCodec, SeekKeyCodec, ValueCodec},
23/// };
24///
25/// // Define key type and value type for a schema with derived traits (Clone, Debug, Eq, PartialEq)
26/// #[derive(Clone, Debug, Eq, PartialEq)]
27/// pub struct Key;
28/// #[derive(Clone, Debug, Eq, PartialEq)]
29/// pub struct Value;
30///
31/// // Implement KeyCodec/ValueCodec traits for key and value types
32/// impl KeyCodec<ExampleSchema> for Key {
33///     fn encode_key(&self) -> Result<Vec<u8>> {
34///         Ok(vec![])
35///     }
36///
37///     fn decode_key(data: &[u8]) -> Result<Self> {
38///         Ok(Key)
39///     }
40/// }
41///
42/// impl ValueCodec<ExampleSchema> for Value {
43///     fn encode_value(&self) -> Result<Vec<u8>> {
44///         Ok(vec![])
45///     }
46///
47///     fn decode_value(data: &[u8]) -> Result<Self> {
48///         Ok(Value)
49///     }
50/// }
51///
52/// // And finally define a schema type and associate it with key and value types, as well as the
53/// // column family name, by generating code that implements the `Schema` trait for the type.
54/// define_schema!(ExampleSchema, Key, Value, "exmaple_cf_name");
55///
56/// // SeekKeyCodec is automatically implemented for KeyCodec,
57/// // so you can seek an iterator with the Key type:
58/// // iter.seek(&Key);
59///
60/// // Or if seek-by-prefix is desired, you can implement your own SeekKey
61/// #[derive(Clone, Eq, PartialEq, Debug)]
62/// pub struct PrefixSeekKey;
63///
64/// impl SeekKeyCodec<ExampleSchema> for PrefixSeekKey {
65///     fn encode_seek_key(&self) -> Result<Vec<u8>> {
66///         Ok(vec![])
67///     }
68/// }
69/// // and seek like this:
70/// // iter.seek(&PrefixSeekKey);
71/// ```
72#[macro_export]
73macro_rules! define_schema {
74    ($schema_type:ident, $key_type:ty, $value_type:ty, $cf_name:expr) => {
75        pub(crate) struct $schema_type;
76
77        impl $crate::schema::Schema for $schema_type {
78            type Key = $key_type;
79            type Value = $value_type;
80
81            const COLUMN_FAMILY_NAME: $crate::ColumnFamilyName = $cf_name;
82        }
83    };
84}
85
86/// This trait defines a type that can serve as a [`Schema::Key`].
87pub trait KeyCodec<S: Schema + ?Sized>: Sized + PartialEq + Debug {
88    /// Converts `self` to bytes to be stored in DB.
89    fn encode_key(&self) -> Result<Vec<u8>>;
90    /// Converts bytes fetched from DB to `Self`.
91    fn decode_key(data: &[u8]) -> Result<Self>;
92}
93
94/// This trait defines a type that can serve as a [`Schema::Value`].
95pub trait ValueCodec<S: Schema + ?Sized>: Sized + PartialEq + Debug {
96    /// Converts `self` to bytes to be stored in DB.
97    fn encode_value(&self) -> Result<Vec<u8>>;
98    /// Converts bytes fetched from DB to `Self`.
99    fn decode_value(data: &[u8]) -> Result<Self>;
100}
101
102/// This defines a type that can be used to seek a
103/// [`SchemaIterator`](crate::SchemaIterator), via interfaces like
104/// [`seek`](crate::SchemaIterator::seek).
105pub trait SeekKeyCodec<S: Schema + ?Sized>: Sized {
106    /// Converts `self` to bytes which is used to seek the underlying raw
107    /// iterator.
108    fn encode_seek_key(&self) -> Result<Vec<u8>>;
109}
110
111/// All keys can automatically be used as seek keys.
112impl<S, K> SeekKeyCodec<S> for K
113where
114    S: Schema,
115    K: KeyCodec<S>,
116{
117    /// Delegates to [`KeyCodec::encode_key`].
118    fn encode_seek_key(&self) -> Result<Vec<u8>> {
119        <K as KeyCodec<S>>::encode_key(&self)
120    }
121}
122
123/// This trait defines a schema: an association of a column family name, the key
124/// type and the value type.
125pub trait Schema {
126    /// The column family name associated with this struct.
127    /// Note: all schemas within the same SchemaDB must have distinct column
128    /// family names.
129    const COLUMN_FAMILY_NAME: ColumnFamilyName;
130
131    /// Type of the key.
132    type Key: KeyCodec<Self>;
133    /// Type of the value.
134    type Value: ValueCodec<Self>;
135}
136
137/// Helper used in tests to assert a (key, value) pair for a certain [`Schema`]
138/// is able to convert to bytes and convert back.
139pub fn assert_encode_decode<S: Schema>(key: &S::Key, value: &S::Value) {
140    {
141        let encoded = key.encode_key().expect("Encoding key should work.");
142        let decoded =
143            S::Key::decode_key(&encoded).expect("Decoding key should work.");
144        assert_eq!(*key, decoded);
145    }
146    {
147        let encoded =
148            value.encode_value().expect("Encoding value should work.");
149        let decoded = S::Value::decode_value(&encoded)
150            .expect("Decoding value should work.");
151        assert_eq!(*value, decoded);
152    }
153}