fraiseql_cli/commands/
serve.rs1use std::{path::Path, sync::mpsc::channel, time::Duration};
6
7use anyhow::{Context, Result};
8use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
9use tracing::{error, info};
10
11pub async fn run(schema: &str, port: u16) -> Result<()> {
29 info!("Starting development server");
30 println!("🚀 FraiseQL Dev Server");
31 println!(" Schema: {schema}");
32 println!(" Port: {port} (GraphQL server integration coming soon)");
33 println!(" Watching for changes...\n");
34
35 let schema_path = Path::new(schema);
37 if !schema_path.exists() {
38 anyhow::bail!("Schema file not found: {schema}");
39 }
40
41 println!("📦 Initial compilation:");
43 match compile_schema(schema).await {
44 Ok(()) => println!(" ✓ Schema compiled successfully\n"),
45 Err(e) => {
46 error!("Initial compilation failed: {e}");
47 println!(" ❌ Compilation failed: {e}\n");
48 println!(" Fix errors and save to retry...\n");
49 },
50 }
51
52 let (tx, rx) = channel();
54
55 let mut watcher = RecommendedWatcher::new(
56 move |res: Result<Event, notify::Error>| {
57 if let Ok(event) = res {
58 let _ = tx.send(event);
59 }
60 },
61 Config::default(),
62 )
63 .context("Failed to create file watcher")?;
64
65 watcher
67 .watch(schema_path, RecursiveMode::NonRecursive)
68 .context("Failed to watch schema file")?;
69
70 loop {
72 match rx.recv() {
73 Ok(event) => {
74 if matches!(event.kind, EventKind::Modify(_)) {
76 info!("Schema file modified, recompiling...");
77 println!("🔄 Schema changed, recompiling...");
78
79 tokio::time::sleep(Duration::from_millis(100)).await;
81
82 match compile_schema(schema).await {
83 Ok(()) => {
84 info!("Recompilation successful");
85 println!(" ✓ Recompiled successfully\n");
86 },
87 Err(e) => {
88 error!("Recompilation failed: {e}");
89 println!(" ❌ Compilation failed: {e}\n");
90 },
91 }
92 }
93 },
94 Err(e) => {
95 error!("Watch error: {e}");
96 anyhow::bail!("File watch error: {e}");
97 },
98 }
99 }
100}
101
102async fn compile_schema(input: &str) -> Result<()> {
104 let output = input.replace(".json", ".compiled.json");
105
106 super::compile::run(input, None, None, Vec::new(), Vec::new(), Vec::new(), &output, false, None)
108 .await
109}