Skip to content

Commit 54e459f

Browse files
committed
feat: add default type option data from type
1 parent 699d6e3 commit 54e459f

File tree

9 files changed

+387
-2
lines changed

9 files changed

+387
-2
lines changed

collab-database/src/entity.rs

Lines changed: 152 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
#![allow(clippy::upper_case_acronyms)]
22
use crate::database::{gen_database_id, gen_database_view_id, gen_row_id, timestamp, DatabaseData};
33
use crate::error::DatabaseError;
4-
use crate::fields::Field;
4+
use crate::fields::checkbox_type_option::CheckboxTypeOption;
5+
use crate::fields::checklist_type_option::ChecklistTypeOption;
6+
use crate::fields::date_type_option::{DateTypeOption, TimeTypeOption};
7+
use crate::fields::media_type_option::MediaTypeOption;
8+
use crate::fields::number_type_option::NumberTypeOption;
9+
use crate::fields::relation_type_option::RelationTypeOption;
10+
use crate::fields::select_type_option::{MultiSelectTypeOption, SingleSelectTypeOption};
11+
use crate::fields::summary_type_option::SummarizationTypeOption;
12+
use crate::fields::text_type_option::RichTextTypeOption;
13+
use crate::fields::timestamp_type_option::TimestampTypeOption;
14+
use crate::fields::translate_type_option::TranslateTypeOption;
15+
use crate::fields::url_type_option::URLTypeOption;
16+
use crate::fields::{Field, TypeOptionData};
517
use crate::rows::CreateRowParams;
618
use crate::views::{
719
DatabaseLayout, FieldOrder, FieldSettingsByFieldIdMap, FieldSettingsMap, FilterMap,
@@ -13,6 +25,7 @@ use collab_entity::CollabType;
1325
use serde::{Deserialize, Serialize};
1426
use serde_repr::{Deserialize_repr, Serialize_repr};
1527
use std::collections::HashMap;
28+
use std::fmt::{Display, Formatter};
1629
use tracing::error;
1730
use yrs::{Any, Out};
1831

@@ -254,7 +267,7 @@ impl CreateDatabaseParams {
254267
}
255268
}
256269

257-
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize_repr, Deserialize_repr)]
270+
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Serialize_repr, Deserialize_repr)]
258271
#[repr(u8)]
259272
pub enum FieldType {
260273
RichText = 0,
@@ -297,6 +310,120 @@ impl TryFrom<yrs::Out> for FieldType {
297310
}
298311
}
299312

313+
impl Display for FieldType {
314+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
315+
let value: i64 = (*self).into();
316+
f.write_fmt(format_args!("{}", value))
317+
}
318+
}
319+
320+
impl AsRef<FieldType> for FieldType {
321+
fn as_ref(&self) -> &FieldType {
322+
self
323+
}
324+
}
325+
326+
impl From<&FieldType> for FieldType {
327+
fn from(field_type: &FieldType) -> Self {
328+
*field_type
329+
}
330+
}
331+
332+
impl FieldType {
333+
pub fn value(&self) -> i64 {
334+
(*self).into()
335+
}
336+
337+
pub fn default_name(&self) -> String {
338+
let s = match self {
339+
FieldType::RichText => "Text",
340+
FieldType::Number => "Number",
341+
FieldType::DateTime => "Date",
342+
FieldType::SingleSelect => "Single Select",
343+
FieldType::MultiSelect => "Multi Select",
344+
FieldType::Checkbox => "Checkbox",
345+
FieldType::URL => "URL",
346+
FieldType::Checklist => "Checklist",
347+
FieldType::LastEditedTime => "Last modified",
348+
FieldType::CreatedTime => "Created time",
349+
FieldType::Relation => "Relation",
350+
FieldType::Summary => "Summarize",
351+
FieldType::Translate => "Translate",
352+
FieldType::Time => "Time",
353+
FieldType::Media => "Media",
354+
};
355+
s.to_string()
356+
}
357+
358+
pub fn is_ai_field(&self) -> bool {
359+
matches!(self, FieldType::Summary | FieldType::Translate)
360+
}
361+
362+
pub fn is_number(&self) -> bool {
363+
matches!(self, FieldType::Number)
364+
}
365+
366+
pub fn is_text(&self) -> bool {
367+
matches!(self, FieldType::RichText)
368+
}
369+
370+
pub fn is_checkbox(&self) -> bool {
371+
matches!(self, FieldType::Checkbox)
372+
}
373+
374+
pub fn is_date(&self) -> bool {
375+
matches!(self, FieldType::DateTime)
376+
}
377+
378+
pub fn is_single_select(&self) -> bool {
379+
matches!(self, FieldType::SingleSelect)
380+
}
381+
382+
pub fn is_multi_select(&self) -> bool {
383+
matches!(self, FieldType::MultiSelect)
384+
}
385+
386+
pub fn is_last_edited_time(&self) -> bool {
387+
matches!(self, FieldType::LastEditedTime)
388+
}
389+
390+
pub fn is_created_time(&self) -> bool {
391+
matches!(self, FieldType::CreatedTime)
392+
}
393+
394+
pub fn is_url(&self) -> bool {
395+
matches!(self, FieldType::URL)
396+
}
397+
398+
pub fn is_select_option(&self) -> bool {
399+
self.is_single_select() || self.is_multi_select()
400+
}
401+
402+
pub fn is_checklist(&self) -> bool {
403+
matches!(self, FieldType::Checklist)
404+
}
405+
406+
pub fn is_relation(&self) -> bool {
407+
matches!(self, FieldType::Relation)
408+
}
409+
410+
pub fn is_time(&self) -> bool {
411+
matches!(self, FieldType::Time)
412+
}
413+
414+
pub fn is_media(&self) -> bool {
415+
matches!(self, FieldType::Media)
416+
}
417+
418+
pub fn can_be_group(&self) -> bool {
419+
self.is_select_option() || self.is_checkbox() || self.is_url()
420+
}
421+
422+
pub fn is_auto_update(&self) -> bool {
423+
self.is_last_edited_time()
424+
}
425+
}
426+
300427
impl From<i64> for FieldType {
301428
fn from(index: i64) -> Self {
302429
match index {
@@ -323,6 +450,29 @@ impl From<i64> for FieldType {
323450
}
324451
}
325452

453+
pub fn default_type_option_data_from_type(field_type: FieldType) -> TypeOptionData {
454+
match field_type {
455+
FieldType::RichText => RichTextTypeOption.into(),
456+
FieldType::Number => NumberTypeOption::default().into(),
457+
FieldType::DateTime => DateTypeOption::default().into(),
458+
FieldType::LastEditedTime | FieldType::CreatedTime => TimestampTypeOption {
459+
field_type: field_type.into(),
460+
..Default::default()
461+
}
462+
.into(),
463+
FieldType::SingleSelect => SingleSelectTypeOption::default().into(),
464+
FieldType::MultiSelect => MultiSelectTypeOption::default().into(),
465+
FieldType::Checkbox => CheckboxTypeOption.into(),
466+
FieldType::URL => URLTypeOption::default().into(),
467+
FieldType::Time => TimeTypeOption.into(),
468+
FieldType::Media => MediaTypeOption::default().into(),
469+
FieldType::Checklist => ChecklistTypeOption.into(),
470+
FieldType::Relation => RelationTypeOption::default().into(),
471+
FieldType::Summary => SummarizationTypeOption::default().into(),
472+
FieldType::Translate => TranslateTypeOption::default().into(),
473+
}
474+
}
475+
326476
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
327477
#[repr(u8)]
328478
pub enum FileUploadType {

collab-database/src/fields/field.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use serde::{Deserialize, Serialize};
22

33
use collab::preclude::{Any, Map, MapExt, MapRef, ReadTxn, TransactionMut, YrsValue};
44

5+
use crate::database::gen_field_id;
6+
use crate::entity::{default_type_option_data_from_type, FieldType};
57
use crate::fields::{TypeOptionData, TypeOptions, TypeOptionsUpdate};
68
use crate::{impl_bool_update, impl_i64_update, impl_str_update};
79

@@ -37,6 +39,17 @@ impl Field {
3739
self
3840
}
3941

42+
pub fn from_field_type(name: &str, field_type: FieldType, is_primary: bool) -> Self {
43+
let new_field = Self {
44+
id: gen_field_id(),
45+
name: name.to_string(),
46+
field_type: field_type.into(),
47+
is_primary,
48+
..Default::default()
49+
};
50+
new_field.with_type_option_data(field_type, default_type_option_data_from_type(field_type))
51+
}
52+
4053
pub fn get_type_option<T: From<TypeOptionData>>(&self, type_id: impl ToString) -> Option<T> {
4154
let type_option_data = self.type_options.get(&type_id.to_string())?.clone();
4255
Some(T::from(type_option_data))
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use collab::util::AnyMapExt;
2+
use yrs::Any;
3+
4+
use crate::views::{DatabaseLayout, FieldSettingsMap, FieldSettingsMapBuilder};
5+
6+
#[repr(u8)]
7+
#[derive(Debug, Default, Clone, Eq, PartialEq)]
8+
pub enum FieldVisibility {
9+
#[default]
10+
AlwaysShown = 0,
11+
HideWhenEmpty = 1,
12+
AlwaysHidden = 2,
13+
}
14+
15+
macro_rules! impl_into_field_visibility {
16+
($target: ident) => {
17+
impl std::convert::From<$target> for FieldVisibility {
18+
fn from(ty: $target) -> Self {
19+
match ty {
20+
0 => FieldVisibility::AlwaysShown,
21+
1 => FieldVisibility::HideWhenEmpty,
22+
2 => FieldVisibility::AlwaysHidden,
23+
_ => {
24+
tracing::error!("🔴Can't parse FieldVisibility from value: {}", ty);
25+
FieldVisibility::AlwaysShown
26+
},
27+
}
28+
}
29+
}
30+
};
31+
}
32+
33+
impl_into_field_visibility!(i64);
34+
impl_into_field_visibility!(u8);
35+
36+
impl From<FieldVisibility> for i64 {
37+
fn from(value: FieldVisibility) -> Self {
38+
(value as u8) as i64
39+
}
40+
}
41+
42+
/// Stores the field settings for a single field
43+
#[derive(Debug, Clone)]
44+
pub struct FieldSettings {
45+
pub field_id: String,
46+
pub visibility: FieldVisibility,
47+
pub width: i32,
48+
pub wrap_cell_content: bool,
49+
}
50+
51+
pub const VISIBILITY: &str = "visibility";
52+
pub const WIDTH: &str = "width";
53+
pub const DEFAULT_WIDTH: i32 = 150;
54+
pub const WRAP_CELL_CONTENT: &str = "wrap";
55+
56+
pub fn default_field_visibility(layout_type: DatabaseLayout) -> FieldVisibility {
57+
match layout_type {
58+
DatabaseLayout::Grid => FieldVisibility::AlwaysShown,
59+
DatabaseLayout::Board => FieldVisibility::HideWhenEmpty,
60+
DatabaseLayout::Calendar => FieldVisibility::HideWhenEmpty,
61+
}
62+
}
63+
64+
impl FieldSettings {
65+
pub fn from_any_map(
66+
field_id: &str,
67+
layout_type: DatabaseLayout,
68+
field_settings: &FieldSettingsMap,
69+
) -> Self {
70+
let visibility = field_settings
71+
.get_as::<i64>(VISIBILITY)
72+
.map(Into::into)
73+
.unwrap_or_else(|| default_field_visibility(layout_type));
74+
let width = field_settings.get_as::<i32>(WIDTH).unwrap_or(DEFAULT_WIDTH);
75+
let wrap_cell_content: bool = field_settings.get_as(WRAP_CELL_CONTENT).unwrap_or(true);
76+
77+
Self {
78+
field_id: field_id.to_string(),
79+
visibility,
80+
width,
81+
wrap_cell_content,
82+
}
83+
}
84+
}
85+
86+
impl From<FieldSettings> for FieldSettingsMap {
87+
fn from(field_settings: FieldSettings) -> Self {
88+
FieldSettingsMapBuilder::from([
89+
(
90+
VISIBILITY.into(),
91+
Any::BigInt(i64::from(field_settings.visibility)),
92+
),
93+
(WIDTH.into(), Any::BigInt(field_settings.width as i64)),
94+
(
95+
WRAP_CELL_CONTENT.into(),
96+
Any::Bool(field_settings.wrap_cell_content),
97+
),
98+
])
99+
}
100+
}

collab-database/src/fields/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ mod field;
22
mod field_id;
33
mod field_map;
44
mod field_observer;
5+
mod field_settings;
56
mod type_option;
67

78
pub use field::*;
89
pub use field_id::*;
910
pub use field_map::*;
1011
pub use field_observer::*;
12+
pub use field_settings::*;
1113
pub use type_option::*;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
use super::{TypeOptionData, TypeOptionDataBuilder};
4+
5+
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6+
pub struct ChecklistTypeOption;
7+
8+
impl From<TypeOptionData> for ChecklistTypeOption {
9+
fn from(_data: TypeOptionData) -> Self {
10+
Self
11+
}
12+
}
13+
14+
impl From<ChecklistTypeOption> for TypeOptionData {
15+
fn from(_data: ChecklistTypeOption) -> Self {
16+
TypeOptionDataBuilder::default()
17+
}
18+
}

collab-database/src/fields/type_option/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
pub mod checkbox_type_option;
2+
pub mod checklist_type_option;
23
pub mod date_type_option;
34
pub mod media_type_option;
45
pub mod number_type_option;
6+
pub mod relation_type_option;
57
pub mod select_type_option;
8+
pub mod summary_type_option;
69
pub mod text_type_option;
710
pub mod timestamp_type_option;
11+
pub mod translate_type_option;
812
pub mod url_type_option;
913

1014
use std::collections::HashMap;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use collab::util::AnyMapExt;
2+
use serde::{Deserialize, Serialize};
3+
4+
use super::{TypeOptionData, TypeOptionDataBuilder};
5+
6+
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7+
pub struct RelationTypeOption {
8+
pub database_id: String,
9+
}
10+
11+
impl From<TypeOptionData> for RelationTypeOption {
12+
fn from(data: TypeOptionData) -> Self {
13+
let database_id: String = data.get_as("database_id").unwrap_or_default();
14+
Self { database_id }
15+
}
16+
}
17+
18+
impl From<RelationTypeOption> for TypeOptionData {
19+
fn from(data: RelationTypeOption) -> Self {
20+
TypeOptionDataBuilder::from([("database_id".into(), data.database_id.into())])
21+
}
22+
}

0 commit comments

Comments
 (0)