1use crate::engine::ForgeEngine;
4use crate::types::blueprint::*;
5use crate::types::ids::*;
6use crate::types::intent::*;
7use crate::types::{ForgeError, ForgeResult, MAX_DEPENDENCIES, MAX_ENTITIES, MAX_FILES};
8
9pub struct WriteEngine<'a> {
10 engine: &'a mut ForgeEngine,
11}
12
13impl<'a> WriteEngine<'a> {
14 pub fn new(engine: &'a mut ForgeEngine) -> Self {
15 Self { engine }
16 }
17
18 pub fn rename_blueprint(
21 &mut self,
22 id: &BlueprintId,
23 name: impl Into<String>,
24 ) -> ForgeResult<()> {
25 let bp = self.engine.store.load_mut(id)?;
26 bp.name = name.into();
27 bp.touch();
28 self.engine.dirty = true;
29 Ok(())
30 }
31
32 pub fn set_description(
33 &mut self,
34 id: &BlueprintId,
35 desc: impl Into<String>,
36 ) -> ForgeResult<()> {
37 let bp = self.engine.store.load_mut(id)?;
38 bp.description = desc.into();
39 bp.touch();
40 self.engine.dirty = true;
41 Ok(())
42 }
43
44 pub fn set_status(&mut self, id: &BlueprintId, status: BlueprintStatus) -> ForgeResult<()> {
45 let bp = self.engine.store.load_mut(id)?;
46 bp.status = status;
47 bp.touch();
48 self.engine.dirty = true;
49 Ok(())
50 }
51
52 pub fn set_version(&mut self, id: &BlueprintId, version: impl Into<String>) -> ForgeResult<()> {
53 let bp = self.engine.store.load_mut(id)?;
54 bp.version = version.into();
55 bp.touch();
56 self.engine.dirty = true;
57 Ok(())
58 }
59
60 pub fn set_metadata(
61 &mut self,
62 id: &BlueprintId,
63 key: impl Into<String>,
64 value: impl Into<String>,
65 ) -> ForgeResult<()> {
66 let bp = self.engine.store.load_mut(id)?;
67 bp.metadata.insert(key.into(), value.into());
68 bp.touch();
69 self.engine.dirty = true;
70 Ok(())
71 }
72
73 pub fn delete_blueprint(&mut self, id: &BlueprintId) -> ForgeResult<Blueprint> {
74 let bp = self.engine.store.delete(id)?;
75 self.engine.indexes.remove_blueprint(id);
76 self.engine.dirty = true;
77 Ok(bp)
78 }
79
80 pub fn add_entity(&mut self, bp_id: &BlueprintId, entity: Entity) -> ForgeResult<EntityId> {
83 let bp = self.engine.store.load_mut(bp_id)?;
84 if bp.entities.len() >= MAX_ENTITIES {
85 return Err(ForgeError::capacity("entities", MAX_ENTITIES));
86 }
87 if bp.entities.iter().any(|e| e.name == entity.name) {
88 return Err(ForgeError::DuplicateEntity(entity.name.clone()));
89 }
90 let id = entity.id;
91 bp.entities.push(entity);
92 bp.touch();
93 self.engine.dirty = true;
94 Ok(id)
95 }
96
97 pub fn add_entity_from_spec(
98 &mut self,
99 bp_id: &BlueprintId,
100 spec: &EntitySpec,
101 ) -> ForgeResult<EntityId> {
102 let mut entity = Entity::new(&spec.name, &spec.description);
103 entity.is_aggregate_root = spec.is_aggregate_root;
104 for field in &spec.fields {
105 entity.fields.push(EntityField {
106 name: field.name.clone(),
107 field_type: field.field_type.clone(),
108 required: field.required,
109 default_value: field.default_value.clone(),
110 description: String::new(),
111 });
112 }
113 for op in &spec.operations {
114 let mut eop = EntityOperation::new(&op.name, op.operation_type);
115 eop.description = op.description.clone();
116 eop.is_async = op.is_async;
117 eop.return_type = op.return_type.clone();
118 eop.error_types = op.error_cases.clone();
119 for p in &op.parameters {
120 eop.parameters.push(OperationParameter {
121 name: p.name.clone(),
122 param_type: p.param_type.clone(),
123 required: p.required,
124 });
125 }
126 entity.operations.push(eop);
127 }
128 self.add_entity(bp_id, entity)
129 }
130
131 pub fn remove_entity(
132 &mut self,
133 bp_id: &BlueprintId,
134 entity_id: &EntityId,
135 ) -> ForgeResult<Entity> {
136 let bp = self.engine.store.load_mut(bp_id)?;
137 let pos = bp
138 .entities
139 .iter()
140 .position(|e| e.id == *entity_id)
141 .ok_or_else(|| ForgeError::EntityNotFound(entity_id.to_string()))?;
142 let entity = bp.entities.remove(pos);
143 bp.touch();
144 self.engine.dirty = true;
145 Ok(entity)
146 }
147
148 pub fn update_entity_name(
149 &mut self,
150 bp_id: &BlueprintId,
151 entity_id: &EntityId,
152 name: impl Into<String>,
153 ) -> ForgeResult<()> {
154 let bp = self.engine.store.load_mut(bp_id)?;
155 let entity = bp
156 .entities
157 .iter_mut()
158 .find(|e| e.id == *entity_id)
159 .ok_or_else(|| ForgeError::EntityNotFound(entity_id.to_string()))?;
160 entity.name = name.into();
161 bp.touch();
162 self.engine.dirty = true;
163 Ok(())
164 }
165
166 pub fn add_field_to_entity(
167 &mut self,
168 bp_id: &BlueprintId,
169 entity_id: &EntityId,
170 field: EntityField,
171 ) -> ForgeResult<()> {
172 let bp = self.engine.store.load_mut(bp_id)?;
173 let entity = bp
174 .entities
175 .iter_mut()
176 .find(|e| e.id == *entity_id)
177 .ok_or_else(|| ForgeError::EntityNotFound(entity_id.to_string()))?;
178 entity.fields.push(field);
179 bp.touch();
180 self.engine.dirty = true;
181 Ok(())
182 }
183
184 pub fn remove_field_from_entity(
185 &mut self,
186 bp_id: &BlueprintId,
187 entity_id: &EntityId,
188 field_name: &str,
189 ) -> ForgeResult<()> {
190 let bp = self.engine.store.load_mut(bp_id)?;
191 let entity = bp
192 .entities
193 .iter_mut()
194 .find(|e| e.id == *entity_id)
195 .ok_or_else(|| ForgeError::EntityNotFound(entity_id.to_string()))?;
196 let pos = entity
197 .fields
198 .iter()
199 .position(|f| f.name == field_name)
200 .ok_or_else(|| ForgeError::MissingField(field_name.to_string()))?;
201 entity.fields.remove(pos);
202 bp.touch();
203 self.engine.dirty = true;
204 Ok(())
205 }
206
207 pub fn add_operation_to_entity(
208 &mut self,
209 bp_id: &BlueprintId,
210 entity_id: &EntityId,
211 op: EntityOperation,
212 ) -> ForgeResult<OperationId> {
213 let bp = self.engine.store.load_mut(bp_id)?;
214 let entity = bp
215 .entities
216 .iter_mut()
217 .find(|e| e.id == *entity_id)
218 .ok_or_else(|| ForgeError::EntityNotFound(entity_id.to_string()))?;
219 let id = op.id;
220 entity.operations.push(op);
221 bp.touch();
222 self.engine.dirty = true;
223 Ok(id)
224 }
225
226 pub fn remove_operation_from_entity(
227 &mut self,
228 bp_id: &BlueprintId,
229 entity_id: &EntityId,
230 op_id: &OperationId,
231 ) -> ForgeResult<()> {
232 let bp = self.engine.store.load_mut(bp_id)?;
233 let entity = bp
234 .entities
235 .iter_mut()
236 .find(|e| e.id == *entity_id)
237 .ok_or_else(|| ForgeError::EntityNotFound(entity_id.to_string()))?;
238 let pos = entity
239 .operations
240 .iter()
241 .position(|o| o.id == *op_id)
242 .ok_or_else(|| ForgeError::OperationNotFound(op_id.to_string()))?;
243 entity.operations.remove(pos);
244 bp.touch();
245 self.engine.dirty = true;
246 Ok(())
247 }
248
249 pub fn add_relationship(
250 &mut self,
251 bp_id: &BlueprintId,
252 entity_id: &EntityId,
253 rel: Relationship,
254 ) -> ForgeResult<()> {
255 let bp = self.engine.store.load_mut(bp_id)?;
256 let entity = bp
257 .entities
258 .iter_mut()
259 .find(|e| e.id == *entity_id)
260 .ok_or_else(|| ForgeError::EntityNotFound(entity_id.to_string()))?;
261 entity.relationships.push(rel);
262 bp.touch();
263 self.engine.dirty = true;
264 Ok(())
265 }
266
267 pub fn add_validation_rule(
268 &mut self,
269 bp_id: &BlueprintId,
270 entity_id: &EntityId,
271 rule: ValidationRule,
272 ) -> ForgeResult<()> {
273 let bp = self.engine.store.load_mut(bp_id)?;
274 let entity = bp
275 .entities
276 .iter_mut()
277 .find(|e| e.id == *entity_id)
278 .ok_or_else(|| ForgeError::EntityNotFound(entity_id.to_string()))?;
279 entity.validation_rules.push(rule);
280 bp.touch();
281 self.engine.dirty = true;
282 Ok(())
283 }
284
285 pub fn add_file(&mut self, bp_id: &BlueprintId, file: FileBlueprint) -> ForgeResult<FileId> {
288 let bp = self.engine.store.load_mut(bp_id)?;
289 if bp.files.len() >= MAX_FILES {
290 return Err(ForgeError::capacity("files", MAX_FILES));
291 }
292 let id = file.id;
293 bp.files.push(file);
294 bp.touch();
295 self.engine.dirty = true;
296 Ok(id)
297 }
298
299 pub fn remove_file(
300 &mut self,
301 bp_id: &BlueprintId,
302 file_id: &FileId,
303 ) -> ForgeResult<FileBlueprint> {
304 let bp = self.engine.store.load_mut(bp_id)?;
305 let pos = bp
306 .files
307 .iter()
308 .position(|f| f.id == *file_id)
309 .ok_or_else(|| ForgeError::FileNotFound(file_id.to_string()))?;
310 let file = bp.files.remove(pos);
311 bp.touch();
312 self.engine.dirty = true;
313 Ok(file)
314 }
315
316 pub fn update_file_imports(
317 &mut self,
318 bp_id: &BlueprintId,
319 file_id: &FileId,
320 imports: Vec<String>,
321 ) -> ForgeResult<()> {
322 let bp = self.engine.store.load_mut(bp_id)?;
323 let file = bp
324 .files
325 .iter_mut()
326 .find(|f| f.id == *file_id)
327 .ok_or_else(|| ForgeError::FileNotFound(file_id.to_string()))?;
328 file.imports = imports;
329 bp.touch();
330 self.engine.dirty = true;
331 Ok(())
332 }
333
334 pub fn update_file_exports(
335 &mut self,
336 bp_id: &BlueprintId,
337 file_id: &FileId,
338 exports: Vec<String>,
339 ) -> ForgeResult<()> {
340 let bp = self.engine.store.load_mut(bp_id)?;
341 let file = bp
342 .files
343 .iter_mut()
344 .find(|f| f.id == *file_id)
345 .ok_or_else(|| ForgeError::FileNotFound(file_id.to_string()))?;
346 file.exports = exports;
347 bp.touch();
348 self.engine.dirty = true;
349 Ok(())
350 }
351
352 pub fn add_dependency(
355 &mut self,
356 bp_id: &BlueprintId,
357 dep: Dependency,
358 ) -> ForgeResult<DependencyId> {
359 let bp = self.engine.store.load_mut(bp_id)?;
360 if bp.dependencies.len() >= MAX_DEPENDENCIES {
361 return Err(ForgeError::capacity("dependencies", MAX_DEPENDENCIES));
362 }
363 if bp.dependencies.iter().any(|d| d.name == dep.name) {
364 return Err(ForgeError::DuplicateDependency(dep.name.clone()));
365 }
366 let id = dep.id;
367 bp.dependencies.push(dep);
368 bp.touch();
369 self.engine.dirty = true;
370 Ok(id)
371 }
372
373 pub fn remove_dependency(
374 &mut self,
375 bp_id: &BlueprintId,
376 dep_id: &DependencyId,
377 ) -> ForgeResult<Dependency> {
378 let bp = self.engine.store.load_mut(bp_id)?;
379 let pos = bp
380 .dependencies
381 .iter()
382 .position(|d| d.id == *dep_id)
383 .ok_or_else(|| ForgeError::DependencyNotFound(dep_id.to_string()))?;
384 let dep = bp.dependencies.remove(pos);
385 bp.touch();
386 self.engine.dirty = true;
387 Ok(dep)
388 }
389
390 pub fn update_dependency_version(
391 &mut self,
392 bp_id: &BlueprintId,
393 dep_id: &DependencyId,
394 version: impl Into<String>,
395 ) -> ForgeResult<()> {
396 let bp = self.engine.store.load_mut(bp_id)?;
397 let dep = bp
398 .dependencies
399 .iter_mut()
400 .find(|d| d.id == *dep_id)
401 .ok_or_else(|| ForgeError::DependencyNotFound(dep_id.to_string()))?;
402 dep.version = version.into();
403 bp.touch();
404 self.engine.dirty = true;
405 Ok(())
406 }
407
408 pub fn add_test_case(&mut self, bp_id: &BlueprintId, tc: TestCase) -> ForgeResult<TestCaseId> {
411 let bp = self.engine.store.load_mut(bp_id)?;
412 let id = tc.id;
413 bp.test_cases.push(tc);
414 bp.touch();
415 self.engine.dirty = true;
416 Ok(id)
417 }
418
419 pub fn remove_test_case(
420 &mut self,
421 bp_id: &BlueprintId,
422 tc_id: &TestCaseId,
423 ) -> ForgeResult<TestCase> {
424 let bp = self.engine.store.load_mut(bp_id)?;
425 let pos = bp
426 .test_cases
427 .iter()
428 .position(|t| t.id == *tc_id)
429 .ok_or_else(|| ForgeError::TestCaseNotFound(tc_id.to_string()))?;
430 let tc = bp.test_cases.remove(pos);
431 bp.touch();
432 self.engine.dirty = true;
433 Ok(tc)
434 }
435
436 pub fn add_type_definition(
439 &mut self,
440 bp_id: &BlueprintId,
441 td: TypeDefinition,
442 ) -> ForgeResult<()> {
443 let bp = self.engine.store.load_mut(bp_id)?;
444 bp.type_definitions.push(td);
445 bp.touch();
446 self.engine.dirty = true;
447 Ok(())
448 }
449
450 pub fn remove_type_definition(&mut self, bp_id: &BlueprintId, name: &str) -> ForgeResult<()> {
451 let bp = self.engine.store.load_mut(bp_id)?;
452 let pos = bp
453 .type_definitions
454 .iter()
455 .position(|t| t.name == name)
456 .ok_or_else(|| ForgeError::MissingField(name.to_string()))?;
457 bp.type_definitions.remove(pos);
458 bp.touch();
459 self.engine.dirty = true;
460 Ok(())
461 }
462
463 pub fn add_function_blueprint(
466 &mut self,
467 bp_id: &BlueprintId,
468 fb: FunctionBlueprint,
469 ) -> ForgeResult<()> {
470 let bp = self.engine.store.load_mut(bp_id)?;
471 bp.function_blueprints.push(fb);
472 bp.touch();
473 self.engine.dirty = true;
474 Ok(())
475 }
476
477 pub fn add_layer(&mut self, bp_id: &BlueprintId, layer: ArchitectureLayer) -> ForgeResult<()> {
480 let bp = self.engine.store.load_mut(bp_id)?;
481 bp.layers.push(layer);
482 bp.touch();
483 self.engine.dirty = true;
484 Ok(())
485 }
486
487 pub fn add_concern(
488 &mut self,
489 bp_id: &BlueprintId,
490 concern: CrossCuttingConcern,
491 ) -> ForgeResult<()> {
492 let bp = self.engine.store.load_mut(bp_id)?;
493 bp.concerns.push(concern);
494 bp.touch();
495 self.engine.dirty = true;
496 Ok(())
497 }
498
499 pub fn add_wiring(&mut self, bp_id: &BlueprintId, wiring: ComponentWiring) -> ForgeResult<()> {
502 let bp = self.engine.store.load_mut(bp_id)?;
503 bp.wiring.push(wiring);
504 bp.touch();
505 self.engine.dirty = true;
506 Ok(())
507 }
508
509 pub fn add_data_flow(&mut self, bp_id: &BlueprintId, flow: DataFlow) -> ForgeResult<()> {
510 let bp = self.engine.store.load_mut(bp_id)?;
511 bp.data_flows.push(flow);
512 bp.touch();
513 self.engine.dirty = true;
514 Ok(())
515 }
516
517 pub fn add_import_edge(&mut self, bp_id: &BlueprintId, edge: ImportEdge) -> ForgeResult<()> {
518 let bp = self.engine.store.load_mut(bp_id)?;
519 bp.import_graph.push(edge);
520 bp.touch();
521 self.engine.dirty = true;
522 Ok(())
523 }
524
525 pub fn set_generation_order(
526 &mut self,
527 bp_id: &BlueprintId,
528 order: Vec<String>,
529 ) -> ForgeResult<()> {
530 let bp = self.engine.store.load_mut(bp_id)?;
531 bp.generation_order = order;
532 bp.touch();
533 self.engine.dirty = true;
534 Ok(())
535 }
536}
537
538#[cfg(test)]
539mod tests {
540 use super::*;
541 use crate::engine::ForgeEngine;
542
543 fn setup() -> (ForgeEngine, BlueprintId) {
544 let mut engine = ForgeEngine::new();
545 let id = engine
546 .create_blueprint("Test", "Test blueprint", Domain::Api)
547 .unwrap();
548 (engine, id)
549 }
550
551 #[test]
552 fn test_rename_blueprint() {
553 let (mut engine, id) = setup();
554 engine.writer().rename_blueprint(&id, "Renamed").unwrap();
555 assert_eq!(engine.store.load(&id).unwrap().name, "Renamed");
556 }
557
558 #[test]
559 fn test_set_description() {
560 let (mut engine, id) = setup();
561 engine.writer().set_description(&id, "New desc").unwrap();
562 assert_eq!(engine.store.load(&id).unwrap().description, "New desc");
563 }
564
565 #[test]
566 fn test_set_status() {
567 let (mut engine, id) = setup();
568 engine
569 .writer()
570 .set_status(&id, BlueprintStatus::Complete)
571 .unwrap();
572 assert_eq!(
573 engine.store.load(&id).unwrap().status,
574 BlueprintStatus::Complete
575 );
576 }
577
578 #[test]
579 fn test_set_version() {
580 let (mut engine, id) = setup();
581 engine.writer().set_version(&id, "1.0.0").unwrap();
582 assert_eq!(engine.store.load(&id).unwrap().version, "1.0.0");
583 }
584
585 #[test]
586 fn test_set_metadata() {
587 let (mut engine, id) = setup();
588 engine.writer().set_metadata(&id, "key", "value").unwrap();
589 assert_eq!(
590 engine.store.load(&id).unwrap().metadata.get("key").unwrap(),
591 "value"
592 );
593 }
594
595 #[test]
596 fn test_add_entity() {
597 let (mut engine, id) = setup();
598 let entity = Entity::new("User", "A user");
599 let eid = engine.writer().add_entity(&id, entity).unwrap();
600 let bp = engine.store.load(&id).unwrap();
601 assert_eq!(bp.entity_count(), 1);
602 assert!(bp.find_entity_by_id(&eid).is_some());
603 }
604
605 #[test]
606 fn test_add_duplicate_entity() {
607 let (mut engine, id) = setup();
608 engine
609 .writer()
610 .add_entity(&id, Entity::new("User", "A"))
611 .unwrap();
612 let result = engine.writer().add_entity(&id, Entity::new("User", "B"));
613 assert!(result.is_err());
614 }
615
616 #[test]
617 fn test_remove_entity() {
618 let (mut engine, id) = setup();
619 let eid = engine
620 .writer()
621 .add_entity(&id, Entity::new("User", "A"))
622 .unwrap();
623 engine.writer().remove_entity(&id, &eid).unwrap();
624 assert_eq!(engine.store.load(&id).unwrap().entity_count(), 0);
625 }
626
627 #[test]
628 fn test_update_entity_name() {
629 let (mut engine, id) = setup();
630 let eid = engine
631 .writer()
632 .add_entity(&id, Entity::new("User", "A"))
633 .unwrap();
634 engine
635 .writer()
636 .update_entity_name(&id, &eid, "Account")
637 .unwrap();
638 assert_eq!(
639 engine
640 .store
641 .load(&id)
642 .unwrap()
643 .find_entity_by_id(&eid)
644 .unwrap()
645 .name,
646 "Account"
647 );
648 }
649
650 #[test]
651 fn test_add_field_to_entity() {
652 let (mut engine, id) = setup();
653 let eid = engine
654 .writer()
655 .add_entity(&id, Entity::new("User", "A"))
656 .unwrap();
657 let field = EntityField::new("name", FieldType::String);
658 engine
659 .writer()
660 .add_field_to_entity(&id, &eid, field)
661 .unwrap();
662 let bp = engine.store.load(&id).unwrap();
663 assert_eq!(bp.find_entity_by_id(&eid).unwrap().fields.len(), 1);
664 }
665
666 #[test]
667 fn test_remove_field_from_entity() {
668 let (mut engine, id) = setup();
669 let eid = engine
670 .writer()
671 .add_entity(&id, Entity::new("User", "A"))
672 .unwrap();
673 let field = EntityField::new("name", FieldType::String);
674 engine
675 .writer()
676 .add_field_to_entity(&id, &eid, field)
677 .unwrap();
678 engine
679 .writer()
680 .remove_field_from_entity(&id, &eid, "name")
681 .unwrap();
682 assert_eq!(
683 engine
684 .store
685 .load(&id)
686 .unwrap()
687 .find_entity_by_id(&eid)
688 .unwrap()
689 .fields
690 .len(),
691 0
692 );
693 }
694
695 #[test]
696 fn test_add_operation_to_entity() {
697 let (mut engine, id) = setup();
698 let eid = engine
699 .writer()
700 .add_entity(&id, Entity::new("User", "A"))
701 .unwrap();
702 let op = EntityOperation::new("create", OperationType::Create);
703 engine
704 .writer()
705 .add_operation_to_entity(&id, &eid, op)
706 .unwrap();
707 assert_eq!(
708 engine
709 .store
710 .load(&id)
711 .unwrap()
712 .find_entity_by_id(&eid)
713 .unwrap()
714 .operations
715 .len(),
716 1
717 );
718 }
719
720 #[test]
721 fn test_add_file() {
722 let (mut engine, id) = setup();
723 let file = FileBlueprint::new("src/main.rs", FileType::Source);
724 engine.writer().add_file(&id, file).unwrap();
725 assert_eq!(engine.store.load(&id).unwrap().file_count(), 1);
726 }
727
728 #[test]
729 fn test_remove_file() {
730 let (mut engine, id) = setup();
731 let file = FileBlueprint::new("src/main.rs", FileType::Source);
732 let fid = engine.writer().add_file(&id, file).unwrap();
733 engine.writer().remove_file(&id, &fid).unwrap();
734 assert_eq!(engine.store.load(&id).unwrap().file_count(), 0);
735 }
736
737 #[test]
738 fn test_add_dependency() {
739 let (mut engine, id) = setup();
740 let dep = Dependency::new("serde", "1.0");
741 engine.writer().add_dependency(&id, dep).unwrap();
742 assert_eq!(engine.store.load(&id).unwrap().dependency_count(), 1);
743 }
744
745 #[test]
746 fn test_add_duplicate_dependency() {
747 let (mut engine, id) = setup();
748 engine
749 .writer()
750 .add_dependency(&id, Dependency::new("serde", "1.0"))
751 .unwrap();
752 let result = engine
753 .writer()
754 .add_dependency(&id, Dependency::new("serde", "2.0"));
755 assert!(result.is_err());
756 }
757
758 #[test]
759 fn test_remove_dependency() {
760 let (mut engine, id) = setup();
761 let did = engine
762 .writer()
763 .add_dependency(&id, Dependency::new("serde", "1.0"))
764 .unwrap();
765 engine.writer().remove_dependency(&id, &did).unwrap();
766 assert_eq!(engine.store.load(&id).unwrap().dependency_count(), 0);
767 }
768
769 #[test]
770 fn test_update_dependency_version() {
771 let (mut engine, id) = setup();
772 let did = engine
773 .writer()
774 .add_dependency(&id, Dependency::new("serde", "1.0"))
775 .unwrap();
776 engine
777 .writer()
778 .update_dependency_version(&id, &did, "2.0")
779 .unwrap();
780 assert_eq!(
781 engine
782 .store
783 .load(&id)
784 .unwrap()
785 .find_dependency("serde")
786 .unwrap()
787 .version,
788 "2.0"
789 );
790 }
791
792 #[test]
793 fn test_add_test_case() {
794 let (mut engine, id) = setup();
795 let tc = TestCase::new("test_create", TestType::Unit, "User::create");
796 engine.writer().add_test_case(&id, tc).unwrap();
797 assert_eq!(engine.store.load(&id).unwrap().test_count(), 1);
798 }
799
800 #[test]
801 fn test_add_type_definition() {
802 let (mut engine, id) = setup();
803 let td = TypeDefinition::new("User", TypeKind::Struct);
804 engine.writer().add_type_definition(&id, td).unwrap();
805 assert_eq!(engine.store.load(&id).unwrap().type_definitions.len(), 1);
806 }
807
808 #[test]
809 fn test_add_function_blueprint() {
810 let (mut engine, id) = setup();
811 let fb = FunctionBlueprint::new("create_user");
812 engine.writer().add_function_blueprint(&id, fb).unwrap();
813 assert_eq!(engine.store.load(&id).unwrap().function_blueprints.len(), 1);
814 }
815
816 #[test]
817 fn test_add_layer() {
818 let (mut engine, id) = setup();
819 let layer = ArchitectureLayer {
820 name: "domain".into(),
821 description: "Domain layer".into(),
822 modules: vec!["models".into()],
823 allowed_dependencies: vec![],
824 };
825 engine.writer().add_layer(&id, layer).unwrap();
826 assert_eq!(engine.store.load(&id).unwrap().layers.len(), 1);
827 }
828
829 #[test]
830 fn test_add_concern() {
831 let (mut engine, id) = setup();
832 let concern = CrossCuttingConcern {
833 name: "logging".into(),
834 concern_type: ConcernType::Logging,
835 affected_layers: vec!["all".into()],
836 implementation_strategy: "tracing".into(),
837 };
838 engine.writer().add_concern(&id, concern).unwrap();
839 assert_eq!(engine.store.load(&id).unwrap().concerns.len(), 1);
840 }
841
842 #[test]
843 fn test_add_wiring() {
844 let (mut engine, id) = setup();
845 let wiring = ComponentWiring {
846 source: "UserService".into(),
847 target: "UserRepository".into(),
848 wiring_type: WiringType::DependencyInjection,
849 description: "Service depends on repo".into(),
850 };
851 engine.writer().add_wiring(&id, wiring).unwrap();
852 assert_eq!(engine.store.load(&id).unwrap().wiring.len(), 1);
853 }
854
855 #[test]
856 fn test_add_data_flow() {
857 let (mut engine, id) = setup();
858 let flow = DataFlow {
859 source: "API".into(),
860 target: "Database".into(),
861 data_type: "User".into(),
862 direction: FlowDirection::Unidirectional,
863 is_async: true,
864 };
865 engine.writer().add_data_flow(&id, flow).unwrap();
866 assert_eq!(engine.store.load(&id).unwrap().data_flows.len(), 1);
867 }
868
869 #[test]
870 fn test_add_import_edge() {
871 let (mut engine, id) = setup();
872 let edge = ImportEdge {
873 from_file: "src/main.rs".into(),
874 to_file: "src/lib.rs".into(),
875 imported_symbols: vec!["App".into()],
876 };
877 engine.writer().add_import_edge(&id, edge).unwrap();
878 assert_eq!(engine.store.load(&id).unwrap().import_graph.len(), 1);
879 }
880
881 #[test]
882 fn test_set_generation_order() {
883 let (mut engine, id) = setup();
884 let order = vec!["types.rs".into(), "models.rs".into(), "main.rs".into()];
885 engine.writer().set_generation_order(&id, order).unwrap();
886 assert_eq!(engine.store.load(&id).unwrap().generation_order.len(), 3);
887 }
888
889 #[test]
890 fn test_delete_blueprint() {
891 let (mut engine, id) = setup();
892 engine.writer().delete_blueprint(&id).unwrap();
893 assert_eq!(engine.blueprint_count(), 0);
894 }
895
896 #[test]
897 fn test_add_entity_from_spec() {
898 let (mut engine, id) = setup();
899 let spec = EntitySpec::new("User", "A user")
900 .with_field(FieldSpec::new("name", FieldType::String))
901 .with_operation(OperationSpec::new("create", OperationType::Create).async_op());
902 engine.writer().add_entity_from_spec(&id, &spec).unwrap();
903 let bp = engine.store.load(&id).unwrap();
904 let entity = bp.find_entity("User").unwrap();
905 assert_eq!(entity.fields.len(), 1);
906 assert_eq!(entity.operations.len(), 1);
907 assert!(entity.operations[0].is_async);
908 }
909
910 #[test]
911 fn test_add_relationship() {
912 let (mut engine, id) = setup();
913 let eid = engine
914 .writer()
915 .add_entity(&id, Entity::new("User", "A"))
916 .unwrap();
917 let rel = Relationship {
918 target_entity: "Post".into(),
919 relationship_type: RelationshipType::HasMany,
920 cardinality: Cardinality::OneToMany,
921 description: "User has many posts".into(),
922 };
923 engine.writer().add_relationship(&id, &eid, rel).unwrap();
924 let entity = engine
925 .store
926 .load(&id)
927 .unwrap()
928 .find_entity_by_id(&eid)
929 .unwrap();
930 assert_eq!(entity.relationships.len(), 1);
931 }
932
933 #[test]
934 fn test_add_validation_rule() {
935 let (mut engine, id) = setup();
936 let eid = engine
937 .writer()
938 .add_entity(&id, Entity::new("User", "A"))
939 .unwrap();
940 let rule = ValidationRule {
941 field: "email".into(),
942 rule_type: "format".into(),
943 parameters: std::collections::HashMap::new(),
944 message: "Invalid email".into(),
945 };
946 engine
947 .writer()
948 .add_validation_rule(&id, &eid, rule)
949 .unwrap();
950 }
951
952 #[test]
953 fn test_update_file_imports() {
954 let (mut engine, id) = setup();
955 let fid = engine
956 .writer()
957 .add_file(&id, FileBlueprint::new("src/main.rs", FileType::Source))
958 .unwrap();
959 engine
960 .writer()
961 .update_file_imports(&id, &fid, vec!["std::io".into()])
962 .unwrap();
963 let file = engine
964 .store
965 .load(&id)
966 .unwrap()
967 .files
968 .iter()
969 .find(|f| f.id == fid)
970 .unwrap();
971 assert_eq!(file.imports.len(), 1);
972 }
973
974 #[test]
975 fn test_update_file_exports() {
976 let (mut engine, id) = setup();
977 let fid = engine
978 .writer()
979 .add_file(&id, FileBlueprint::new("src/lib.rs", FileType::Source))
980 .unwrap();
981 engine
982 .writer()
983 .update_file_exports(&id, &fid, vec!["App".into()])
984 .unwrap();
985 let file = engine
986 .store
987 .load(&id)
988 .unwrap()
989 .files
990 .iter()
991 .find(|f| f.id == fid)
992 .unwrap();
993 assert_eq!(file.exports.len(), 1);
994 }
995
996 #[test]
997 fn test_remove_operation_from_entity() {
998 let (mut engine, id) = setup();
999 let eid = engine
1000 .writer()
1001 .add_entity(&id, Entity::new("User", "A"))
1002 .unwrap();
1003 let op = EntityOperation::new("create", OperationType::Create);
1004 let oid = engine
1005 .writer()
1006 .add_operation_to_entity(&id, &eid, op)
1007 .unwrap();
1008 engine
1009 .writer()
1010 .remove_operation_from_entity(&id, &eid, &oid)
1011 .unwrap();
1012 assert_eq!(
1013 engine
1014 .store
1015 .load(&id)
1016 .unwrap()
1017 .find_entity_by_id(&eid)
1018 .unwrap()
1019 .operations
1020 .len(),
1021 0
1022 );
1023 }
1024
1025 #[test]
1026 fn test_remove_type_definition() {
1027 let (mut engine, id) = setup();
1028 engine
1029 .writer()
1030 .add_type_definition(&id, TypeDefinition::new("User", TypeKind::Struct))
1031 .unwrap();
1032 engine.writer().remove_type_definition(&id, "User").unwrap();
1033 assert_eq!(engine.store.load(&id).unwrap().type_definitions.len(), 0);
1034 }
1035
1036 #[test]
1037 fn test_remove_test_case() {
1038 let (mut engine, id) = setup();
1039 let tcid = engine
1040 .writer()
1041 .add_test_case(&id, TestCase::new("test_a", TestType::Unit, "A"))
1042 .unwrap();
1043 engine.writer().remove_test_case(&id, &tcid).unwrap();
1044 assert_eq!(engine.store.load(&id).unwrap().test_count(), 0);
1045 }
1046}