1use serde::{Deserialize, Serialize};
2use tito::{
3 types::{
4 DBUuid, TitoEngine, TitoIndexBlockType,
5 TitoIndexConfig, TitoIndexField, TitoModelTrait,
6 },
7 TiKV, TitoError, TitoModelOptions,
8};
9
10#[derive(Default, Debug, Clone, Serialize, Deserialize)]
11struct Tag {
12 id: String,
13 name: String,
14 description: String,
15}
16
17#[derive(Default, Debug, Clone, Serialize, Deserialize)]
18struct Post {
19 id: String,
20 title: String,
21 content: String,
22 author: String,
23 tag_ids: Vec<String>,
24 #[serde(default)]
25 tags: Vec<Tag>,
26}
27
28impl TitoModelTrait for Tag {
29 fn indexes(&self) -> Vec<TitoIndexConfig> {
30 vec![TitoIndexConfig {
31 condition: true,
32 name: "tag-by-name".to_string(),
33 fields: vec![TitoIndexField {
34 name: "name".to_string(),
35 r#type: TitoIndexBlockType::String,
36 }],
37 }]
38 }
39
40 fn table(&self) -> String {
41 "tag".to_string()
42 }
43
44 fn id(&self) -> String {
45 self.id.clone()
46 }
47}
48
49impl TitoModelTrait for Post {
50 fn relationships(&self) -> Vec<tito::types::TitoRelationshipConfig> {
51 vec![tito::types::TitoRelationshipConfig {
52 source_field_name: "tag_ids".to_string(),
53 destination_field_name: "tags".to_string(),
54 model: "tag".to_string(),
55 }]
56 }
57
58 fn indexes(&self) -> Vec<TitoIndexConfig> {
59 vec![
60 TitoIndexConfig {
61 condition: true,
62 name: "post-by-author".to_string(),
63 fields: vec![TitoIndexField {
64 name: "author".to_string(),
65 r#type: TitoIndexBlockType::String,
66 }],
67 },
68 TitoIndexConfig {
69 condition: true,
70 name: "post-by-tag".to_string(),
71 fields: vec![TitoIndexField {
72 name: "tag_ids".to_string(),
73 r#type: TitoIndexBlockType::String,
74 }],
75 },
76 ]
77 }
78
79 fn table(&self) -> String {
80 "post".to_string()
81 }
82
83 fn id(&self) -> String {
84 self.id.clone()
85 }
86}
87
88#[tokio::main]
89async fn main() -> Result<(), TitoError> {
90 let tito_db = TiKV::connect(vec!["127.0.0.1:2379"]).await?;
91
92 let post_model = tito_db.clone().model::<Post>(TitoModelOptions::default());
93 let tag_model = tito_db.clone().model::<Tag>(TitoModelOptions::default());
94
95 let tech_tag = tito_db
96 .transaction(|tx| {
97 let tag_model = tag_model.clone();
98 let tag = Tag {
99 id: DBUuid::new_v4().to_string(),
100 name: "Technology".to_string(),
101 description: "All about tech".to_string(),
102 };
103 let tag_clone = tag.clone();
104 async move {
105 tag_model.set(tag_clone).execute(&tx).await?;
106 Ok::<_, TitoError>(tag)
107 }
108 })
109 .await?;
110
111 let rust_tag = tito_db
112 .transaction(|tx| {
113 let tag_model = tag_model.clone();
114 let tag = Tag {
115 id: DBUuid::new_v4().to_string(),
116 name: "Rust".to_string(),
117 description: "Rust programming".to_string(),
118 };
119 let tag_clone = tag.clone();
120 async move {
121 tag_model.set(tag_clone).execute(&tx).await?;
122 Ok::<_, TitoError>(tag)
123 }
124 })
125 .await?;
126
127 println!("Created tags: {}, {}", tech_tag.name, rust_tag.name);
128
129 let post = tito_db
130 .transaction(|tx| {
131 let post_model = post_model.clone();
132 let post = Post {
133 id: DBUuid::new_v4().to_string(),
134 title: "Using Rust with TiKV".to_string(),
135 content: "Examples of using Rust with TiKV...".to_string(),
136 author: "Alice".to_string(),
137 tag_ids: vec![tech_tag.id.clone(), rust_tag.id.clone()],
138 tags: Vec::new(),
139 };
140 let post_clone = post.clone();
141 async move {
142 post_model.set(post_clone).execute(&tx).await?;
143 Ok::<_, TitoError>(post)
144 }
145 })
146 .await?;
147
148 println!("Created post: {}", post.title);
149
150 let post_with_tags = post_model
151 .get(&post.id)
152 .relationship("tags")
153 .execute(None)
154 .await?;
155
156 println!("Post: {}", post_with_tags.title);
157 println!("Tags:");
158 for tag in &post_with_tags.tags {
159 println!("- {}", tag.name);
160 }
161
162 let mut query = post_model.query_by_index("post-by-author");
163 let results = query
164 .value("Alice".to_string())
165 .relationship("tags")
166 .execute(None)
167 .await?;
168
169 println!("\nAlice's posts:");
170 for p in &results.items {
171 println!("- {} (tags: {})", p.title, p.tags.iter().map(|t| t.name.clone()).collect::<Vec<_>>().join(", "));
172 }
173
174 Ok(())
175}