use clap::Subcommand;
use colored::Colorize;
use mockforge_core::intelligent_behavior::session::{SessionManager, SessionTracking};
use mockforge_data::{FieldDefinition, SchemaDefinition};
use mockforge_vbr::{
config::{StorageBackend, VbrConfig},
entities::Entity,
schema::VbrSchemaDefinition,
session::SessionDataManager,
VbrEngine,
};
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
#[derive(Subcommand)]
pub enum VbrCommands {
#[command(verbatim_doc_comment)]
Create {
#[command(subcommand)]
create_command: CreateCommands,
},
#[command(verbatim_doc_comment)]
Serve {
#[arg(short, long, default_value = "3000")]
port: u16,
#[arg(short, long, default_value = "memory")]
storage: String,
#[arg(long)]
db_path: Option<PathBuf>,
#[arg(long, default_value = "/vbr-api")]
api_prefix: String,
#[arg(long)]
session_scoped: bool,
},
#[command(verbatim_doc_comment)]
Manage {
#[command(subcommand)]
manage_command: ManageCommands,
},
#[command(verbatim_doc_comment)]
Import {
#[command(subcommand)]
import_command: ImportCommands,
},
#[command(verbatim_doc_comment)]
Seed {
file: PathBuf,
#[arg(short, long)]
entity: Option<String>,
#[arg(long)]
db_path: Option<PathBuf>,
#[arg(short, long, default_value = "memory")]
storage: String,
},
#[command(verbatim_doc_comment)]
Snapshot {
#[command(subcommand)]
snapshot_command: SnapshotCommands,
},
#[command(verbatim_doc_comment)]
Reset {
#[arg(short, long)]
entity: Option<String>,
#[arg(long)]
db_path: Option<PathBuf>,
#[arg(short, long, default_value = "memory")]
storage: String,
},
}
#[derive(Subcommand)]
pub enum CreateCommands {
Entity {
name: String,
#[arg(short, long)]
fields: Option<String>,
#[arg(short, long)]
schema: Option<PathBuf>,
#[arg(short, long)]
output: Option<PathBuf>,
},
}
#[derive(Subcommand)]
pub enum ManageCommands {
Entities {
#[command(subcommand)]
entities_command: EntitiesCommands,
},
Data {
query: String,
#[arg(long)]
db_path: Option<PathBuf>,
#[arg(short, long, default_value = "memory")]
storage: String,
},
}
#[derive(Subcommand)]
pub enum EntitiesCommands {
List {
#[arg(long)]
db_path: Option<PathBuf>,
#[arg(short, long, default_value = "memory")]
storage: String,
},
Show {
name: String,
#[arg(long)]
db_path: Option<PathBuf>,
#[arg(short, long, default_value = "memory")]
storage: String,
},
}
#[derive(Subcommand)]
pub enum ImportCommands {
Openapi {
file: PathBuf,
#[arg(short, long)]
output: Option<PathBuf>,
#[arg(long)]
db_path: Option<PathBuf>,
#[arg(short, long, default_value = "memory")]
storage: String,
},
}
#[derive(Subcommand)]
pub enum SnapshotCommands {
Create {
name: String,
#[arg(short, long)]
description: Option<String>,
#[arg(long, default_value = "./snapshots")]
snapshots_dir: PathBuf,
#[arg(long)]
db_path: Option<PathBuf>,
#[arg(short, long, default_value = "memory")]
storage: String,
},
List {
#[arg(long, default_value = "./snapshots")]
snapshots_dir: PathBuf,
},
Restore {
name: String,
#[arg(long, default_value = "./snapshots")]
snapshots_dir: PathBuf,
#[arg(long)]
db_path: Option<PathBuf>,
#[arg(short, long, default_value = "memory")]
storage: String,
},
Delete {
name: String,
#[arg(long, default_value = "./snapshots")]
snapshots_dir: PathBuf,
},
}
pub async fn execute_vbr_command(command: VbrCommands) -> Result<(), Box<dyn std::error::Error>> {
match command {
VbrCommands::Create { create_command } => execute_create_command(create_command).await,
VbrCommands::Serve {
port,
storage,
db_path,
api_prefix,
session_scoped,
} => execute_serve_command(port, storage, db_path, api_prefix, session_scoped).await,
VbrCommands::Manage { manage_command } => execute_manage_command(manage_command).await,
VbrCommands::Import { import_command } => execute_import_command(import_command).await,
VbrCommands::Seed {
file,
entity,
db_path,
storage,
} => execute_seed_command(file, entity, db_path, storage).await,
VbrCommands::Snapshot { snapshot_command } => {
execute_snapshot_command(snapshot_command).await
}
VbrCommands::Reset {
entity,
db_path,
storage,
} => execute_reset_command(entity, db_path, storage).await,
}
}
async fn execute_create_command(command: CreateCommands) -> Result<(), Box<dyn std::error::Error>> {
match command {
CreateCommands::Entity {
name,
fields,
schema,
output,
} => {
println!("{}", "Creating VBR entity...".bright_cyan());
let entity_schema = if let Some(schema_path) = schema {
let content = std::fs::read_to_string(&schema_path)?;
if schema_path.extension().and_then(|s| s.to_str()) == Some("yaml")
|| schema_path.extension().and_then(|s| s.to_str()) == Some("yml")
{
serde_yaml::from_str(&content)?
} else {
serde_json::from_str(&content)?
}
} else if let Some(fields_str) = fields {
create_schema_from_fields(&name, &fields_str)?
} else {
return Err("Either --fields or --schema must be provided".into());
};
let entity = Entity::new(name.clone(), entity_schema);
let schema_json = serde_json::to_string_pretty(&entity.schema)?;
if let Some(output_path) = output {
std::fs::write(&output_path, schema_json)?;
println!(
"{} Entity '{}' created and saved to {}",
"✓".green(),
name,
output_path.display()
);
} else {
println!("{} Entity '{}' definition:", "✓".green(), name);
println!("{}", schema_json);
}
Ok(())
}
}
}
fn create_schema_from_fields(
entity_name: &str,
fields_str: &str,
) -> Result<VbrSchemaDefinition, Box<dyn std::error::Error>> {
let mut field_defs = Vec::new();
let mut primary_key = vec!["id".to_string()];
for field_spec in fields_str.split(',') {
let parts: Vec<&str> = field_spec.split(':').collect();
if parts.len() != 2 {
return Err(format!("Invalid field specification: {}", field_spec).into());
}
let field_name = parts[0].trim();
let field_type = parts[1].trim();
if field_name == "id" {
primary_key = vec![field_name.to_string()];
}
field_defs.push(FieldDefinition {
name: field_name.to_string(),
field_type: field_type.to_string(),
required: field_name == "id", description: None,
default: None,
constraints: HashMap::new(),
faker_template: None,
});
}
let base_schema = SchemaDefinition {
name: entity_name.to_string(),
fields: field_defs,
description: Some(format!("{} entity", entity_name)),
metadata: HashMap::new(),
relationships: HashMap::new(),
};
Ok(VbrSchemaDefinition {
base: base_schema,
primary_key,
foreign_keys: Vec::new(),
unique_constraints: Vec::new(),
indexes: Vec::new(),
auto_generation: HashMap::new(),
many_to_many: Vec::new(),
})
}
async fn execute_serve_command(
port: u16,
storage: String,
db_path: Option<PathBuf>,
api_prefix: String,
session_scoped: bool,
) -> Result<(), Box<dyn std::error::Error>> {
println!("{} Starting VBR server on port {}...", "🚀".bright_cyan(), port);
let storage_backend = match storage.as_str() {
"sqlite" => {
let path = db_path.unwrap_or_else(|| PathBuf::from("./data/vbr.db"));
StorageBackend::Sqlite { path }
}
"json" => {
let path = db_path.unwrap_or_else(|| PathBuf::from("./data/vbr.json"));
StorageBackend::Json { path }
}
"memory" => StorageBackend::Memory,
_ => {
return Err(format!("Invalid storage backend: {}", storage).into());
}
};
let mut config = VbrConfig {
storage: storage_backend,
..VbrConfig::default()
};
config.sessions.scoped_data = session_scoped;
let session_timeout_secs = config.sessions.timeout;
let session_storage_backend = config.storage.clone();
let engine = VbrEngine::new(config).await?;
let database = engine.database_arc();
let registry = engine.registry().clone();
let session_manager = if session_scoped {
let session_tracking = SessionTracking::default();
let core_session_manager =
Arc::new(SessionManager::new(session_tracking, session_timeout_secs));
Some(Arc::new(SessionDataManager::new(core_session_manager, session_storage_backend)))
} else {
None
};
let context = mockforge_vbr::handlers::HandlerContext {
database,
registry,
session_manager,
snapshots_dir: None,
};
let router = mockforge_vbr::integration::create_vbr_router_with_context(&api_prefix, context)?;
use std::net::SocketAddr;
let addr: SocketAddr = format!("0.0.0.0:{}", port).parse()?;
let listener = tokio::net::TcpListener::bind(addr).await?;
println!("{} VBR server running at http://localhost:{}{}", "✓".green(), port, api_prefix);
println!("{} Press Ctrl+C to stop", "ℹ".bright_blue());
axum::serve(listener, router).await?;
Ok(())
}
async fn execute_manage_command(command: ManageCommands) -> Result<(), Box<dyn std::error::Error>> {
match command {
ManageCommands::Entities { entities_command } => match entities_command {
EntitiesCommands::List { db_path, storage } => {
let config = create_config_from_storage(&storage, db_path)?;
let engine = VbrEngine::new(config).await?;
let entities = engine.registry().list();
if entities.is_empty() {
println!("{} No entities registered", "ℹ".bright_blue());
} else {
println!("{} Registered entities:", "📋".bright_cyan());
for entity in entities {
println!(" - {}", entity);
}
}
Ok(())
}
EntitiesCommands::Show {
name,
db_path,
storage,
} => {
let config = create_config_from_storage(&storage, db_path)?;
let engine = VbrEngine::new(config).await?;
if let Some(entity) = engine.registry().get(&name) {
let schema = serde_json::to_string_pretty(&entity.schema)?;
println!("{} Entity '{}':", "ℹ".bright_blue(), name.bright_cyan());
println!("{}", schema);
Ok(())
} else {
Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("Entity '{}' not found", name),
)
.into())
}
}
},
ManageCommands::Data {
query,
db_path,
storage,
} => {
let config = create_config_from_storage(&storage, db_path)?;
let engine = VbrEngine::new(config).await?;
let database = engine.database_arc();
let normalized = query.trim().to_lowercase();
if normalized.starts_with("select")
|| normalized.starts_with("with")
|| normalized.starts_with("pragma")
{
let rows = database.query(&query, &[]).await?;
println!("{}", serde_json::to_string_pretty(&rows)?);
} else {
let affected = database.execute(&query, &[]).await?;
println!(
"{} Query executed successfully ({} row(s) affected)",
"✓".green(),
affected
);
}
Ok(())
}
}
}
async fn execute_import_command(command: ImportCommands) -> Result<(), Box<dyn std::error::Error>> {
match command {
ImportCommands::Openapi {
file,
output,
db_path,
storage,
} => {
println!("{} Importing entities from OpenAPI specification...", "📥".bright_cyan());
let content = std::fs::read_to_string(&file)?;
let is_yaml = file
.extension()
.and_then(|s| s.to_str())
.map(|s| s == "yaml" || s == "yml")
.unwrap_or(false);
let config = create_config_from_storage(&storage, db_path)?;
let (engine, result) = if is_yaml {
VbrEngine::from_openapi_file(config, &file).await?
} else {
VbrEngine::from_openapi(config, &content).await?
};
println!("{} Created {} entities:", "✓".green(), result.entities.len());
for (name, _) in &result.entities {
println!(" - {}", name.bright_cyan());
}
if !result.warnings.is_empty() {
println!("{} Warnings:", "⚠".yellow());
for warning in &result.warnings {
println!(" - {}", warning);
}
}
if let Some(output_dir) = output {
std::fs::create_dir_all(&output_dir)?;
for (name, _schema) in &result.entities {
if let Some(entity) = engine.registry().get(name) {
let schema_json = serde_json::to_string_pretty(&entity.schema)?;
let output_file = output_dir.join(format!("{}.json", name));
std::fs::write(&output_file, schema_json)?;
println!(" {} Saved to {}", "✓".green(), output_file.display());
}
}
}
Ok(())
}
}
}
async fn execute_seed_command(
file: PathBuf,
entity: Option<String>,
db_path: Option<PathBuf>,
storage: String,
) -> Result<(), Box<dyn std::error::Error>> {
println!("{} Seeding data from {}...", "🌱".bright_cyan(), file.display());
let config = create_config_from_storage(&storage, db_path)?;
let engine = VbrEngine::new(config).await?;
let results = if let Some(entity_name) = entity {
let seed_data = mockforge_vbr::seeding::load_seed_file(&file).await?;
if let Some(records) = seed_data.get(&entity_name) {
let count = engine.seed_entity(&entity_name, records).await?;
let mut results = HashMap::new();
results.insert(entity_name, count);
results
} else {
return Err(format!("Entity '{}' not found in seed file", entity_name).into());
}
} else {
let seed_data = mockforge_vbr::seeding::load_seed_file(&file).await?;
engine.seed_all(&seed_data).await?
};
println!("{} Seeded data:", "✓".green());
for (entity_name, count) in results {
println!(" - {}: {} records", entity_name.bright_cyan(), count);
}
Ok(())
}
async fn execute_snapshot_command(
command: SnapshotCommands,
) -> Result<(), Box<dyn std::error::Error>> {
match command {
SnapshotCommands::Create {
name,
description,
snapshots_dir,
db_path,
storage,
} => {
println!("{} Creating snapshot '{}'...", "📸".bright_cyan(), name);
let config = create_config_from_storage(&storage, db_path)?;
let engine = VbrEngine::new(config).await?;
let metadata = engine.create_snapshot(&name, description, &snapshots_dir).await?;
println!("{} Snapshot created:", "✓".green());
println!(" Name: {}", metadata.name.bright_cyan());
println!(" Created: {}", metadata.created_at);
println!(" Entity counts:");
for (entity, count) in &metadata.entity_counts {
println!(" - {}: {}", entity, count);
}
Ok(())
}
SnapshotCommands::List { snapshots_dir } => {
println!("{} Listing snapshots...", "📋".bright_cyan());
let snapshots = VbrEngine::list_snapshots(&snapshots_dir).await?;
if snapshots.is_empty() {
println!(" No snapshots found");
} else {
println!("{} Found {} snapshots:", "✓".green(), snapshots.len());
for snapshot in snapshots {
println!(" - {} ({})", snapshot.name.bright_cyan(), snapshot.created_at);
if let Some(desc) = &snapshot.description {
println!(" Description: {}", desc);
}
println!(" Entity counts:");
for (entity, count) in &snapshot.entity_counts {
println!(" - {}: {}", entity, count);
}
}
}
Ok(())
}
SnapshotCommands::Restore {
name,
snapshots_dir,
db_path,
storage,
} => {
println!("{} Restoring snapshot '{}'...", "🔄".bright_cyan(), name);
let config = create_config_from_storage(&storage, db_path)?;
let engine = VbrEngine::new(config).await?;
engine.restore_snapshot(&name, &snapshots_dir).await?;
println!("{} Snapshot '{}' restored successfully", "✓".green(), name);
Ok(())
}
SnapshotCommands::Delete {
name,
snapshots_dir,
} => {
println!("{} Deleting snapshot '{}'...", "🗑️".bright_cyan(), name);
VbrEngine::delete_snapshot(&name, &snapshots_dir).await?;
println!("{} Snapshot '{}' deleted successfully", "✓".green(), name);
Ok(())
}
}
}
async fn execute_reset_command(
entity: Option<String>,
db_path: Option<PathBuf>,
storage: String,
) -> Result<(), Box<dyn std::error::Error>> {
println!("{} Resetting database...", "🔄".bright_cyan());
let config = create_config_from_storage(&storage, db_path)?;
let engine = VbrEngine::new(config).await?;
if let Some(entity_name) = entity {
println!(" Resetting entity: {}", entity_name.bright_cyan());
engine.clear_entity(&entity_name).await?;
println!("{} Entity '{}' reset successfully", "✓".green(), entity_name);
} else {
println!(" Resetting all entities...");
engine.reset().await?;
println!("{} Database reset successfully", "✓".green());
}
Ok(())
}
fn create_config_from_storage(
storage: &str,
db_path: Option<PathBuf>,
) -> Result<VbrConfig, Box<dyn std::error::Error>> {
let storage_backend = match storage {
"sqlite" => {
let path = db_path.unwrap_or_else(|| PathBuf::from("./data/vbr.db"));
StorageBackend::Sqlite { path }
}
"json" => {
let path = db_path.unwrap_or_else(|| PathBuf::from("./data/vbr.json"));
StorageBackend::Json { path }
}
"memory" => StorageBackend::Memory,
_ => {
return Err(format!("Invalid storage backend: {}", storage).into());
}
};
let config = VbrConfig {
storage: storage_backend,
..VbrConfig::default()
};
Ok(config)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_schema_from_fields_basic() {
let schema = create_schema_from_fields("User", "id:string,name:string,email:string")
.expect("Failed to create schema");
assert_eq!(schema.base.name, "User");
assert_eq!(schema.base.fields.len(), 3);
assert_eq!(schema.primary_key, vec!["id".to_string()]);
}
#[test]
fn test_create_schema_from_fields_with_types() {
let schema = create_schema_from_fields("Product", "id:string,price:number,quantity:number")
.expect("Failed to create schema");
assert_eq!(schema.base.fields.len(), 3);
let id_field = schema.base.fields.iter().find(|f| f.name == "id").unwrap();
assert_eq!(id_field.field_type, "string");
assert!(id_field.required);
let price_field = schema.base.fields.iter().find(|f| f.name == "price").unwrap();
assert_eq!(price_field.field_type, "number");
assert!(!price_field.required);
}
#[test]
fn test_create_schema_from_fields_invalid_format() {
let result = create_schema_from_fields("Invalid", "field1:type1,field2");
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Invalid field specification"));
}
#[test]
fn test_create_schema_from_fields_single_field() {
let schema =
create_schema_from_fields("Simple", "id:string").expect("Failed to create schema");
assert_eq!(schema.base.fields.len(), 1);
assert_eq!(schema.primary_key, vec!["id".to_string()]);
}
#[test]
fn test_create_schema_from_fields_whitespace() {
let schema = create_schema_from_fields("Test", " id : string , name : string ")
.expect("Failed to create schema");
assert_eq!(schema.base.fields.len(), 2);
let field_names: Vec<String> = schema.base.fields.iter().map(|f| f.name.clone()).collect();
assert!(field_names.contains(&"id".to_string()));
assert!(field_names.contains(&"name".to_string()));
}
#[test]
fn test_create_config_from_storage_memory() {
let config = create_config_from_storage("memory", None).expect("Failed to create config");
match config.storage {
StorageBackend::Memory => {}
_ => panic!("Expected Memory storage backend"),
}
}
#[test]
fn test_create_config_from_storage_sqlite() {
let db_path = PathBuf::from("./test.db");
let config = create_config_from_storage("sqlite", Some(db_path.clone()))
.expect("Failed to create config");
match config.storage {
StorageBackend::Sqlite { path } => {
assert_eq!(path, db_path);
}
_ => panic!("Expected Sqlite storage backend"),
}
}
#[test]
fn test_create_config_from_storage_sqlite_default_path() {
let config = create_config_from_storage("sqlite", None).expect("Failed to create config");
match config.storage {
StorageBackend::Sqlite { path } => {
assert_eq!(path, PathBuf::from("./data/vbr.db"));
}
_ => panic!("Expected Sqlite storage backend"),
}
}
#[test]
fn test_create_config_from_storage_json() {
let db_path = PathBuf::from("./test.json");
let config = create_config_from_storage("json", Some(db_path.clone()))
.expect("Failed to create config");
match config.storage {
StorageBackend::Json { path } => {
assert_eq!(path, db_path);
}
_ => panic!("Expected Json storage backend"),
}
}
#[test]
fn test_create_config_from_storage_json_default_path() {
let config = create_config_from_storage("json", None).expect("Failed to create config");
match config.storage {
StorageBackend::Json { path } => {
assert_eq!(path, PathBuf::from("./data/vbr.json"));
}
_ => panic!("Expected Json storage backend"),
}
}
#[test]
fn test_create_config_from_storage_invalid() {
let result = create_config_from_storage("invalid", None);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Invalid storage backend"));
}
#[test]
fn test_vbr_commands_create_entity() {
let cmd = VbrCommands::Create {
create_command: CreateCommands::Entity {
name: "User".to_string(),
fields: Some("id:string,name:string".to_string()),
schema: None,
output: None,
},
};
match cmd {
VbrCommands::Create { create_command } => match create_command {
CreateCommands::Entity { name, fields, .. } => {
assert_eq!(name, "User");
assert!(fields.is_some());
}
},
_ => panic!("Expected Create command"),
}
}
#[test]
fn test_vbr_commands_serve() {
let cmd = VbrCommands::Serve {
port: 8080,
storage: "memory".to_string(),
db_path: None,
api_prefix: "/api".to_string(),
session_scoped: true,
};
match cmd {
VbrCommands::Serve {
port,
storage,
session_scoped,
..
} => {
assert_eq!(port, 8080);
assert_eq!(storage, "memory");
assert!(session_scoped);
}
_ => panic!("Expected Serve command"),
}
}
#[test]
fn test_vbr_commands_import_openapi() {
let cmd = VbrCommands::Import {
import_command: ImportCommands::Openapi {
file: PathBuf::from("api.yaml"),
output: Some(PathBuf::from("./entities")),
db_path: None,
storage: "memory".to_string(),
},
};
match cmd {
VbrCommands::Import { import_command } => match import_command {
ImportCommands::Openapi { file, output, .. } => {
assert_eq!(file, PathBuf::from("api.yaml"));
assert!(output.is_some());
}
},
_ => panic!("Expected Import command"),
}
}
#[test]
fn test_vbr_commands_seed() {
let cmd = VbrCommands::Seed {
file: PathBuf::from("seed.json"),
entity: Some("User".to_string()),
db_path: None,
storage: "sqlite".to_string(),
};
match cmd {
VbrCommands::Seed {
file,
entity,
storage,
..
} => {
assert_eq!(file, PathBuf::from("seed.json"));
assert_eq!(entity, Some("User".to_string()));
assert_eq!(storage, "sqlite");
}
_ => panic!("Expected Seed command"),
}
}
#[test]
fn test_vbr_commands_snapshot_create() {
let cmd = VbrCommands::Snapshot {
snapshot_command: SnapshotCommands::Create {
name: "initial".to_string(),
description: Some("Initial state".to_string()),
snapshots_dir: PathBuf::from("./snapshots"),
db_path: None,
storage: "memory".to_string(),
},
};
match cmd {
VbrCommands::Snapshot { snapshot_command } => match snapshot_command {
SnapshotCommands::Create {
name, description, ..
} => {
assert_eq!(name, "initial");
assert_eq!(description, Some("Initial state".to_string()));
}
_ => panic!("Expected Create snapshot command"),
},
_ => panic!("Expected Snapshot command"),
}
}
#[test]
fn test_vbr_commands_snapshot_list() {
let cmd = VbrCommands::Snapshot {
snapshot_command: SnapshotCommands::List {
snapshots_dir: PathBuf::from("./snapshots"),
},
};
match cmd {
VbrCommands::Snapshot { snapshot_command } => match snapshot_command {
SnapshotCommands::List { snapshots_dir } => {
assert_eq!(snapshots_dir, PathBuf::from("./snapshots"));
}
_ => panic!("Expected List snapshot command"),
},
_ => panic!("Expected Snapshot command"),
}
}
#[test]
fn test_vbr_commands_snapshot_restore() {
let cmd = VbrCommands::Snapshot {
snapshot_command: SnapshotCommands::Restore {
name: "backup1".to_string(),
snapshots_dir: PathBuf::from("./snapshots"),
db_path: None,
storage: "sqlite".to_string(),
},
};
match cmd {
VbrCommands::Snapshot { snapshot_command } => match snapshot_command {
SnapshotCommands::Restore { name, .. } => {
assert_eq!(name, "backup1");
}
_ => panic!("Expected Restore snapshot command"),
},
_ => panic!("Expected Snapshot command"),
}
}
#[test]
fn test_vbr_commands_snapshot_delete() {
let cmd = VbrCommands::Snapshot {
snapshot_command: SnapshotCommands::Delete {
name: "old_snapshot".to_string(),
snapshots_dir: PathBuf::from("./snapshots"),
},
};
match cmd {
VbrCommands::Snapshot { snapshot_command } => match snapshot_command {
SnapshotCommands::Delete { name, .. } => {
assert_eq!(name, "old_snapshot");
}
_ => panic!("Expected Delete snapshot command"),
},
_ => panic!("Expected Snapshot command"),
}
}
#[test]
fn test_vbr_commands_reset() {
let cmd = VbrCommands::Reset {
entity: Some("User".to_string()),
db_path: Some(PathBuf::from("./data.db")),
storage: "sqlite".to_string(),
};
match cmd {
VbrCommands::Reset {
entity,
db_path,
storage,
} => {
assert_eq!(entity, Some("User".to_string()));
assert!(db_path.is_some());
assert_eq!(storage, "sqlite");
}
_ => panic!("Expected Reset command"),
}
}
#[test]
fn test_vbr_commands_reset_all() {
let cmd = VbrCommands::Reset {
entity: None,
db_path: None,
storage: "memory".to_string(),
};
match cmd {
VbrCommands::Reset { entity, .. } => {
assert!(entity.is_none());
}
_ => panic!("Expected Reset command"),
}
}
#[test]
fn test_vbr_commands_manage_entities_list() {
let cmd = VbrCommands::Manage {
manage_command: ManageCommands::Entities {
entities_command: EntitiesCommands::List {
db_path: None,
storage: "memory".to_string(),
},
},
};
match cmd {
VbrCommands::Manage { manage_command } => match manage_command {
ManageCommands::Entities { entities_command } => match entities_command {
EntitiesCommands::List { .. } => {}
_ => panic!("Expected List entities command"),
},
_ => panic!("Expected Entities command"),
},
_ => panic!("Expected Manage command"),
}
}
#[test]
fn test_vbr_commands_manage_entities_show() {
let cmd = VbrCommands::Manage {
manage_command: ManageCommands::Entities {
entities_command: EntitiesCommands::Show {
name: "User".to_string(),
db_path: None,
storage: "memory".to_string(),
},
},
};
match cmd {
VbrCommands::Manage { manage_command } => match manage_command {
ManageCommands::Entities { entities_command } => match entities_command {
EntitiesCommands::Show { name, .. } => {
assert_eq!(name, "User");
}
_ => panic!("Expected Show entities command"),
},
_ => panic!("Expected Entities command"),
},
_ => panic!("Expected Manage command"),
}
}
#[test]
fn test_vbr_commands_manage_data() {
let cmd = VbrCommands::Manage {
manage_command: ManageCommands::Data {
query: "SELECT * FROM users".to_string(),
db_path: None,
storage: "memory".to_string(),
},
};
match cmd {
VbrCommands::Manage { manage_command } => match manage_command {
ManageCommands::Data { query, .. } => {
assert_eq!(query, "SELECT * FROM users");
}
_ => panic!("Expected Data command"),
},
_ => panic!("Expected Manage command"),
}
}
#[test]
fn test_create_schema_empty_fields() {
let result = create_schema_from_fields("Test", "");
assert!(result.is_ok() || result.is_err());
}
#[test]
fn test_create_schema_complex_types() {
let schema = create_schema_from_fields(
"Complex",
"id:string,count:number,active:boolean,data:object",
)
.expect("Failed to create schema");
assert_eq!(schema.base.fields.len(), 4);
let types: Vec<String> = schema.base.fields.iter().map(|f| f.field_type.clone()).collect();
assert!(types.contains(&"string".to_string()));
assert!(types.contains(&"number".to_string()));
assert!(types.contains(&"boolean".to_string()));
assert!(types.contains(&"object".to_string()));
}
}