refactor: use derive_builder for boilerplate builders (#116)

* refactor: remove boilerplate builder code with derive_builder macro

* refactor: better build creation using Default::default()

* refactor: resolve api change issues in benchmark code

* refactor: address some review issues

* refactor: address clippy issues

* chore: doc and todo update

* refactor: add builder for RegionDescriptor
This commit is contained in:
Ning Sun
2022-07-29 14:31:12 +08:00
committed by GitHub
parent 45490b6293
commit 62cb649389
10 changed files with 250 additions and 261 deletions

View File

@@ -16,6 +16,7 @@ futures = "0.3"
object-store = { path = "../object-store" }
serde = { version = "1.0", features = ["derive"] }
snafu = { version = "0.7", features = ["backtraces"] }
derive_builder = "0.11"
[dev-dependencies]
async-stream = "0.3"

View File

@@ -1,5 +1,4 @@
//! Storage related APIs
pub mod logstore;
pub mod manifest;
pub mod storage;

View File

@@ -1,4 +1,5 @@
use datatypes::value::Value;
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use crate::manifest::MetadataId;
@@ -20,19 +21,35 @@ pub fn gen_region_name(id: RegionId) -> String {
// TODO(yingwen): Validate default value has same type with column, and name is a valid column name.
/// A [ColumnDescriptor] contains information to create a column.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Builder)]
#[builder(pattern = "owned")]
pub struct ColumnDescriptor {
pub id: ColumnId,
#[builder(setter(into))]
pub name: String,
pub data_type: ConcreteDataType,
/// Is column nullable, default is true.
#[builder(default = "true")]
pub is_nullable: bool,
/// Default value of column, default is None, which means no default value
/// for this column, and user must provide value for a not-null column.
#[builder(default)]
pub default_value: Option<Value>,
#[builder(default, setter(into))]
pub comment: String,
}
impl ColumnDescriptorBuilder {
pub fn new<S: Into<String>>(id: ColumnId, name: S, data_type: ConcreteDataType) -> Self {
Self {
id: Some(id),
name: Some(name.into()),
data_type: Some(data_type),
..Default::default()
}
}
}
impl From<&ColumnDescriptor> for ColumnSchema {
fn from(desc: &ColumnDescriptor) -> ColumnSchema {
ColumnSchema::new(&desc.name, desc.data_type.clone(), desc.is_nullable)
@@ -40,32 +57,39 @@ impl From<&ColumnDescriptor> for ColumnSchema {
}
/// A [RowKeyDescriptor] contains information about row key.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Builder)]
#[builder(pattern = "owned")]
pub struct RowKeyDescriptor {
#[builder(default)]
pub columns: Vec<ColumnDescriptor>,
/// Timestamp key column.
pub timestamp: ColumnDescriptor,
/// Enable version column in row key if this field is true.
///
/// The default value is true.
// FIXME(yingwen): Change default value to true (Disable version column by default).
/// The default value is false.
#[builder(default = "false")]
pub enable_version_column: bool,
}
/// A [ColumnFamilyDescriptor] contains information to create a column family.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Builder)]
pub struct ColumnFamilyDescriptor {
#[builder(default = "consts::DEFAULT_CF_ID")]
pub cf_id: ColumnFamilyId,
#[builder(default = "consts::DEFAULT_CF_NAME.to_string()", setter(into))]
pub name: String,
/// Descriptors of columns in this column family.
#[builder(default)]
pub columns: Vec<ColumnDescriptor>,
}
/// A [RegionDescriptor] contains information to create a region.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Builder)]
#[builder(pattern = "owned")]
pub struct RegionDescriptor {
pub id: RegionId,
/// Region name.
#[builder(setter(into))]
pub name: String,
/// Row key descriptor of this region.
pub row_key: RowKeyDescriptor,
@@ -75,154 +99,51 @@ pub struct RegionDescriptor {
pub extra_cfs: Vec<ColumnFamilyDescriptor>,
}
pub struct ColumnDescriptorBuilder {
id: ColumnId,
name: String,
data_type: ConcreteDataType,
is_nullable: bool,
default_value: Option<Value>,
comment: String,
}
impl ColumnDescriptorBuilder {
pub fn new<T: Into<String>>(id: ColumnId, name: T, data_type: ConcreteDataType) -> Self {
Self {
id,
name: name.into(),
data_type,
is_nullable: true,
default_value: None,
comment: "".to_string(),
}
}
pub fn is_nullable(mut self, is_nullable: bool) -> Self {
self.is_nullable = is_nullable;
self
}
pub fn default_value(mut self, value: Option<Value>) -> Self {
self.default_value = value;
self
}
pub fn comment<T: Into<String>>(mut self, comment: T) -> Self {
self.comment = comment.into();
self
}
pub fn build(self) -> ColumnDescriptor {
ColumnDescriptor {
id: self.id,
name: self.name,
data_type: self.data_type,
is_nullable: self.is_nullable,
default_value: self.default_value,
comment: self.comment,
}
}
}
pub struct RowKeyDescriptorBuilder {
columns: Vec<ColumnDescriptor>,
timestamp: ColumnDescriptor,
enable_version_column: bool,
}
impl RowKeyDescriptorBuilder {
pub fn new(timestamp: ColumnDescriptor) -> Self {
Self {
columns: Vec::new(),
timestamp,
enable_version_column: false,
timestamp: Some(timestamp),
..Default::default()
}
}
pub fn columns_capacity(mut self, capacity: usize) -> Self {
self.columns.reserve(capacity);
self.columns = Some(Vec::with_capacity(capacity));
self
}
pub fn push_column(mut self, column: ColumnDescriptor) -> Self {
self.columns.push(column);
let columns = self.columns.get_or_insert_with(Vec::new);
columns.push(column);
self
}
pub fn enable_version_column(mut self, enable: bool) -> Self {
self.enable_version_column = enable;
self
}
pub fn build(self) -> RowKeyDescriptor {
RowKeyDescriptor {
columns: self.columns,
timestamp: self.timestamp,
enable_version_column: self.enable_version_column,
}
}
}
pub struct ColumnFamilyDescriptorBuilder {
cf_id: ColumnFamilyId,
name: String,
columns: Vec<ColumnDescriptor>,
}
impl ColumnFamilyDescriptorBuilder {
pub fn new() -> Self {
Self {
cf_id: consts::DEFAULT_CF_ID,
name: consts::DEFAULT_CF_NAME.to_string(),
columns: Vec::new(),
}
}
pub fn cf_id(mut self, cf_id: ColumnFamilyId) -> Self {
self.cf_id = cf_id;
self
}
pub fn name<T: Into<String>>(mut self, name: T) -> Self {
self.name = name.into();
self
}
pub fn columns_capacity(mut self, capacity: usize) -> Self {
self.columns.reserve(capacity);
self.columns = Some(Vec::with_capacity(capacity));
self
}
pub fn push_column(mut self, column: ColumnDescriptor) -> Self {
self.columns.push(column);
let columns = self.columns.get_or_insert_with(Vec::new);
columns.push(column);
self
}
pub fn build(self) -> ColumnFamilyDescriptor {
ColumnFamilyDescriptor {
cf_id: self.cf_id,
name: self.name,
columns: self.columns,
}
}
}
impl Default for ColumnFamilyDescriptorBuilder {
fn default() -> ColumnFamilyDescriptorBuilder {
ColumnFamilyDescriptorBuilder::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[inline]
fn new_column_desc_builder() -> ColumnDescriptorBuilder {
ColumnDescriptorBuilder::new(3, "test", ConcreteDataType::int32_datatype())
}
#[test]
fn test_column_descriptor_builder() {
let desc = new_column_desc_builder().build();
let desc = new_column_desc_builder().build().unwrap();
assert_eq!(3, desc.id);
assert_eq!("test", desc.name);
assert_eq!(ConcreteDataType::int32_datatype(), desc.data_type);
@@ -230,73 +151,98 @@ mod tests {
assert!(desc.default_value.is_none());
assert!(desc.comment.is_empty());
let desc = new_column_desc_builder().is_nullable(false).build();
let desc = new_column_desc_builder()
.is_nullable(false)
.build()
.unwrap();
assert!(!desc.is_nullable);
let desc = new_column_desc_builder()
.default_value(Some(Value::Null))
.build();
.build()
.unwrap();
assert_eq!(Value::Null, desc.default_value.unwrap());
let desc = new_column_desc_builder()
.default_value(Some(Value::Int32(123)))
.build();
.build()
.unwrap();
assert_eq!(Value::Int32(123), desc.default_value.unwrap());
let desc = new_column_desc_builder().comment("A test column").build();
let desc = new_column_desc_builder()
.comment("A test column")
.build()
.unwrap();
assert_eq!("A test column", desc.comment);
}
fn new_timestamp_desc() -> ColumnDescriptor {
ColumnDescriptorBuilder::new(5, "timestamp", ConcreteDataType::int64_datatype()).build()
ColumnDescriptorBuilder::new(5, "timestamp", ConcreteDataType::int64_datatype())
.build()
.unwrap()
}
#[test]
fn test_row_key_descriptor_builder() {
let timestamp = new_timestamp_desc();
let desc = RowKeyDescriptorBuilder::new(timestamp.clone()).build();
let desc = RowKeyDescriptorBuilder::new(timestamp.clone())
.build()
.unwrap();
assert!(desc.columns.is_empty());
assert!(!desc.enable_version_column);
let desc = RowKeyDescriptorBuilder::new(timestamp.clone())
.columns_capacity(1)
.push_column(
ColumnDescriptorBuilder::new(6, "c1", ConcreteDataType::int32_datatype()).build(),
ColumnDescriptorBuilder::new(6, "c1", ConcreteDataType::int32_datatype())
.build()
.unwrap(),
)
.push_column(
ColumnDescriptorBuilder::new(7, "c2", ConcreteDataType::int32_datatype()).build(),
ColumnDescriptorBuilder::new(7, "c2", ConcreteDataType::int32_datatype())
.build()
.unwrap(),
)
.build();
.build()
.unwrap();
assert_eq!(2, desc.columns.len());
assert!(!desc.enable_version_column);
let desc = RowKeyDescriptorBuilder::new(timestamp)
.enable_version_column(false)
.build();
.build()
.unwrap();
assert!(desc.columns.is_empty());
assert!(!desc.enable_version_column);
}
#[test]
fn test_cf_descriptor_builder() {
let desc = ColumnFamilyDescriptorBuilder::default().build();
let desc = ColumnFamilyDescriptorBuilder::default().build().unwrap();
assert_eq!(consts::DEFAULT_CF_ID, desc.cf_id);
assert_eq!(consts::DEFAULT_CF_NAME, desc.name);
assert!(desc.columns.is_empty());
let desc = ColumnFamilyDescriptorBuilder::new()
let desc = ColumnFamilyDescriptorBuilder::default()
.cf_id(32)
.name("cf1")
.build();
.build()
.unwrap();
assert_eq!(32, desc.cf_id);
assert_eq!("cf1", desc.name);
let desc = ColumnFamilyDescriptorBuilder::new()
let desc = ColumnFamilyDescriptorBuilder::default()
.push_column(
ColumnDescriptorBuilder::new(6, "c1", ConcreteDataType::int32_datatype()).build(),
ColumnDescriptorBuilder::default()
.id(6)
.name("c1")
.data_type(ConcreteDataType::int32_datatype())
.build()
.unwrap(),
)
.build();
.build()
.unwrap();
assert_eq!(1, desc.columns.len());
}