1use graph_api_lib::Graph;
2use graph_api_test::{Edge, Language, Project, Refs, Vertex, populate_graph};
3use rand::prelude::*;
4use rand::rngs::StdRng;
5use rand::{Rng, SeedableRng};
6use std::collections::HashSet;
7use uuid::Uuid;
8
9#[derive(Clone, Copy)]
11pub enum GraphSize {
12 Small, Medium, Large, Huge, }
17
18impl GraphSize {
19 pub fn vertex_count(&self) -> usize {
20 match self {
21 GraphSize::Small => 100,
22 GraphSize::Medium => 1_000,
23 GraphSize::Large => 10_000,
24 GraphSize::Huge => 100_000,
25 }
26 }
27
28 pub fn edge_multiplier(&self) -> usize {
29 3 }
31}
32
33pub fn generate_test_graph<G>(graph: &mut G) -> Refs<G>
35where
36 G: Graph<Vertex = Vertex, Edge = Edge>,
37{
38 populate_graph(graph)
39}
40
41pub fn generate_random_graph<G>(graph: &mut G, size: GraphSize, seed: u64) -> Vec<G::VertexId>
43where
44 G: Graph<Vertex = Vertex, Edge = Edge>,
45{
46 let mut rng = StdRng::seed_from_u64(seed);
47 let vertex_count = size.vertex_count();
48 let edge_count = vertex_count * size.edge_multiplier();
49
50 let mut vertex_ids = Vec::with_capacity(vertex_count);
52 for i in 0..vertex_count {
53 let vertex = match rng.random_range(0..3) {
54 0 => Vertex::Person {
55 name: format!("Person-{}", i),
56 age: rng.random_range(18..80),
57 unique_id: Uuid::new_v4(),
58 username: format!("user_{}", i),
59 biography: format!("Bio for person {}: {}", i, random_biography(&mut rng)),
60 },
61 1 => Vertex::Project(Project {
62 name: format!("Project-{}", i),
63 }),
64 _ => Vertex::Rust,
65 };
66
67 vertex_ids.push(graph.add_vertex(vertex));
68 }
69
70 let mut added_edges = HashSet::new();
72 for _ in 0..edge_count {
73 let src_idx = rng.random_range(0..vertex_count);
75 let tgt_idx = rng.random_range(0..vertex_count);
76 let src = vertex_ids[src_idx];
77 let tgt = vertex_ids[tgt_idx];
78
79 if src == tgt || added_edges.contains(&(src, tgt)) {
81 continue;
82 }
83
84 let edge = match rng.random_range(0..3) {
86 0 => Edge::Knows {
87 since: rng.random_range(1980..2023),
88 },
89 1 => Edge::Created,
90 _ => Edge::Language(Language {
91 name: match rng.random_range(0..4) {
92 0 => "Rust".to_string(),
93 1 => "Java".to_string(),
94 2 => "Python".to_string(),
95 _ => "JavaScript".to_string(),
96 },
97 }),
98 };
99
100 graph.add_edge(src, tgt, edge);
101 added_edges.insert((src, tgt));
102 }
103
104 vertex_ids
105}
106
107pub fn generate_social_graph<G>(graph: &mut G, size: GraphSize, seed: u64) -> Vec<G::VertexId>
109where
110 G: Graph<Vertex = Vertex, Edge = Edge>,
111{
112 let mut rng = StdRng::seed_from_u64(seed);
113 let vertex_count = size.vertex_count();
114
115 let mut vertex_ids = Vec::with_capacity(vertex_count);
117 for i in 0..vertex_count {
118 let vertex = Vertex::Person {
119 name: format!("Person-{}", i),
120 age: rng.random_range(18..80),
121 unique_id: Uuid::new_v4(),
122 username: format!("user_{}", i),
123 biography: format!("Social network user {}", i),
124 };
125
126 vertex_ids.push(graph.add_vertex(vertex));
127 }
128
129 for i in 0..vertex_count {
132 let num_connections = rng.random_range(5..15).min(vertex_count - 1);
134 let mut connections = HashSet::new();
135
136 while connections.len() < num_connections {
137 let target_idx = if rng.random_bool(0.8) {
139 let range = 50; let start = i.saturating_sub(range / 2);
142 let end = (i + range / 2).min(vertex_count - 1);
143 rng.random_range(start..=end)
144 } else {
145 rng.random_range(0..vertex_count)
147 };
148
149 if target_idx != i {
151 connections.insert(target_idx);
152 }
153 }
154
155 for target_idx in connections {
157 let target = vertex_ids[target_idx];
158 let year = rng.random_range(1980..2023);
159 graph.add_edge(vertex_ids[i], target, Edge::Knows { since: year });
160 }
161 }
162
163 vertex_ids
164}
165
166pub fn generate_project_graph<G>(graph: &mut G, size: GraphSize, seed: u64) -> Vec<G::VertexId>
168where
169 G: Graph<Vertex = Vertex, Edge = Edge>,
170{
171 let mut rng = StdRng::seed_from_u64(seed);
172 let project_count = size.vertex_count() / 3; let person_count = size.vertex_count() / 3; let rust_count = size.vertex_count() - project_count - person_count; let mut project_ids = Vec::with_capacity(project_count);
178 for i in 0..project_count {
179 let vertex = Vertex::Project(Project {
180 name: format!("Project-{}", i),
181 });
182 project_ids.push(graph.add_vertex(vertex));
183 }
184
185 let mut person_ids = Vec::with_capacity(person_count);
187 for i in 0..person_count {
188 let vertex = Vertex::Person {
189 name: format!("Developer-{}", i),
190 age: rng.random_range(18..80),
191 unique_id: Uuid::new_v4(),
192 username: format!("dev_{}", i),
193 biography: format!("Developer working on project {}", i % project_count),
194 };
195 person_ids.push(graph.add_vertex(vertex));
196 }
197
198 let mut rust_ids = Vec::with_capacity(rust_count);
200 for _ in 0..rust_count {
201 rust_ids.push(graph.add_vertex(Vertex::Rust));
202 }
203
204 for (i, &project_id) in project_ids.iter().enumerate() {
206 let num_deps = rng.random_range(0..=5).min(project_count - 1);
208 let mut deps = HashSet::new();
209
210 while deps.len() < num_deps {
211 let target_idx = rng.random_range(0..project_count);
212 if target_idx != i {
213 deps.insert(target_idx);
215 }
216 }
217
218 for target_idx in deps {
220 let target = project_ids[target_idx];
221 graph.add_edge(project_id, target, Edge::Created);
222 }
223 }
224
225 for (i, &person_id) in person_ids.iter().enumerate() {
227 let num_projects = rng.random_range(1..=3).min(project_count);
229 let mut projects = HashSet::new();
230
231 projects.insert(i % project_count);
233
234 while projects.len() < num_projects {
236 projects.insert(rng.random_range(0..project_count));
237 }
238
239 for &project_idx in &projects {
241 let project_id = project_ids[project_idx];
242 graph.add_edge(person_id, project_id, Edge::Created);
243 }
244 }
245
246 for &project_id in &project_ids {
248 let num_langs = rng.random_range(1..=2).min(rust_count);
250
251 for _ in 0..num_langs {
252 let lang_idx = rng.random_range(0..rust_count);
253 let lang_id = rust_ids[lang_idx];
254
255 graph.add_edge(
256 project_id,
257 lang_id,
258 Edge::Language(Language {
259 name: "Rust".to_string(),
260 }),
261 );
262 }
263 }
264
265 let mut all_vertices = Vec::with_capacity(size.vertex_count());
267 all_vertices.extend(project_ids);
268 all_vertices.extend(person_ids);
269 all_vertices.extend(rust_ids);
270 all_vertices
271}
272
273fn random_biography(rng: &mut StdRng) -> String {
275 let adjectives = [
276 "creative",
277 "diligent",
278 "innovative",
279 "experienced",
280 "passionate",
281 ];
282 let roles = ["developer", "engineer", "architect", "programmer", "coder"];
283 let interests = [
284 "graph databases",
285 "distributed systems",
286 "machine learning",
287 "web development",
288 "mobile apps",
289 ];
290
291 format!(
292 "A {} {} interested in {}",
293 adjectives.choose(rng).unwrap(),
294 roles.choose(rng).unwrap(),
295 interests.choose(rng).unwrap()
296 )
297}