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}