use std::net::SocketAddr;
use std::path::PathBuf;
use clap::{Parser, Subcommand, ValueEnum};
#[derive(Parser, Debug)]
#[command(version, about = "sbol-db CLI", long_about = None)]
pub struct Cli {
#[arg(
long,
env = "DATABASE_URL",
default_value = "postgres://sbol:sbol@localhost:5432/sbol"
)]
pub database_url: String,
#[arg(long, value_enum, env = "SBOL_DB_BACKEND")]
pub backend: Option<BackendKind>,
#[command(subcommand)]
pub command: Command,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, ValueEnum)]
pub enum BackendKind {
Postgres,
Sqlite,
Rocksdb,
}
impl BackendKind {
pub fn scheme(self) -> &'static str {
match self {
BackendKind::Postgres => "postgres",
BackendKind::Sqlite => "sqlite",
BackendKind::Rocksdb => "rocksdb",
}
}
pub fn accepts_scheme(self, scheme: &str) -> bool {
match self {
BackendKind::Postgres => scheme == "postgres" || scheme == "postgresql",
BackendKind::Sqlite => scheme == "sqlite",
BackendKind::Rocksdb => scheme == "rocksdb",
}
}
}
#[derive(Subcommand, Debug)]
pub enum Command {
Server {
#[arg(long, env = "SBOL_DB_BIND", default_value = "127.0.0.1:8888")]
bind: SocketAddr,
#[arg(long, env = "SBOL_DB_WORKER_DISABLED")]
no_worker: bool,
#[arg(long, env = "SBOL_DB_WORKER_CONCURRENCY")]
worker_concurrency: Option<usize>,
#[arg(long, env = "SBOL_DB_WORKER_QUEUES")]
worker_queues: Option<String>,
#[arg(long, env = "SBOL_DB_WORKER_ID")]
worker_id: Option<String>,
},
Worker {
#[arg(long, env = "SBOL_DB_WORKER_CONCURRENCY")]
concurrency: Option<usize>,
#[arg(long, env = "SBOL_DB_WORKER_QUEUES")]
queues: Option<String>,
#[arg(long, env = "SBOL_DB_WORKER_ID")]
worker_id: Option<String>,
},
Graph {
#[command(subcommand)]
action: GraphAction,
},
Object {
#[command(subcommand)]
action: ObjectAction,
},
Query {
#[command(subcommand)]
action: QueryAction,
},
Ontology {
#[command(subcommand)]
action: OntologyAction,
},
Jobs {
#[command(subcommand)]
action: JobsAction,
},
Db {
#[command(subcommand)]
action: DbAction,
},
Inspect {
#[command(subcommand)]
action: InspectAction,
},
Util {
#[command(subcommand)]
action: UtilAction,
},
}
#[derive(Subcommand, Debug)]
pub enum GraphAction {
Import {
path: PathBuf,
#[arg(long)]
format: Option<String>,
#[arg(long)]
namespace: Option<String>,
#[arg(long)]
document_iri: Option<String>,
#[arg(long)]
name: Option<String>,
#[arg(long)]
continue_on_error: bool,
#[arg(long, default_value_t = 1)]
parallel: usize,
#[arg(long)]
skip_existing: bool,
},
List {
#[arg(long, default_value_t = 50)]
limit: u32,
#[arg(long)]
name: Option<String>,
#[arg(long)]
format: Option<String>,
},
Show { id: uuid::Uuid },
Delete {
id: uuid::Uuid,
#[arg(long)]
yes: bool,
},
Validate { graph_id: uuid::Uuid },
}
#[derive(Subcommand, Debug)]
pub enum ObjectAction {
Get {
iri: String,
#[arg(long)]
json: bool,
},
Export {
iri: String,
#[arg(long, default_value = "turtle")]
format: String,
},
ExportAll {
#[arg(long)]
sbol_class: Option<String>,
#[arg(long)]
role: Option<String>,
#[arg(long)]
graph_id: Option<uuid::Uuid>,
#[arg(long, default_value_t = 1000)]
page_size: u32,
},
}
#[derive(Subcommand, Debug)]
pub enum QueryAction {
Sparql {
source: String,
#[arg(long)]
format: Option<String>,
#[arg(long, default_value_t = 30)]
timeout_secs: u64,
#[arg(long, default_value_t = 100_000)]
max_rows: usize,
#[arg(long, default_value_t = 64 * 1024)]
max_query_size: usize,
},
Explain {
source: String,
},
Neighborhood {
iri: String,
#[arg(long, default_value_t = 2)]
depth: u32,
#[arg(long, default_value = "forward")]
direction: String,
#[arg(long = "predicate")]
predicates: Vec<String>,
#[arg(long, default_value_t = 2048)]
max_nodes: u32,
#[arg(long)]
literals: bool,
#[arg(long)]
rdf: Option<String>,
},
SequenceSearch {
pattern: String,
#[arg(long, default_value_t = 1024)]
max_hits: u32,
#[arg(long)]
forward_only: bool,
},
SequenceBatch {
source: String,
#[arg(long, default_value_t = 1024)]
max_hits: u32,
#[arg(long)]
forward_only: bool,
},
}
#[derive(Subcommand, Debug)]
pub enum OntologyAction {
Fetch {
prefix: String,
#[arg(long)]
url: Option<String>,
#[arg(long)]
name: Option<String>,
},
List,
Term { iri_or_curie: String },
Descendants { iri_or_curie: String },
LoadFile {
path: PathBuf,
#[arg(long)]
prefix: String,
#[arg(long)]
name: Option<String>,
},
}
#[derive(Subcommand, Debug)]
pub enum JobsAction {
Enqueue {
kind: String,
payload: String,
#[arg(long)]
queue: Option<String>,
#[arg(long)]
priority: Option<i16>,
#[arg(long)]
max_attempts: Option<i32>,
#[arg(long)]
idempotency_key: Option<String>,
},
Status { id: uuid::Uuid },
List {
#[arg(long)]
kind: Option<String>,
#[arg(long)]
status: Option<String>,
#[arg(long)]
queue: Option<String>,
#[arg(long, default_value_t = 50)]
limit: u32,
},
Cancel { id: uuid::Uuid },
Attempts { id: uuid::Uuid },
Replay {
id: uuid::Uuid,
#[arg(long)]
keep_idempotency_key: bool,
},
QueueDepth,
QueueAge,
Handlers,
}
#[derive(Subcommand, Debug)]
pub enum DbAction {
Migrate,
MigrateStatus,
Doctor {
#[arg(long)]
json: bool,
#[arg(long, default_value = "SO")]
require_ontologies: String,
#[arg(long, default_value_t = 3600)]
max_queued_age_secs: i64,
},
}
#[derive(Subcommand, Debug)]
pub enum InspectAction {
Size,
Tables {
#[arg(long, default_value_t = 100)]
limit: i64,
#[arg(long, default_value_t = 0)]
offset: i64,
},
Table { name: String },
Activity {
#[arg(long, default_value_t = 50)]
limit: i64,
#[arg(long)]
include_idle: bool,
},
Locks,
Indexes {
#[arg(long, default_value_t = 50)]
limit: i64,
},
SlowQueries {
#[arg(long, default_value_t = 20)]
limit: i64,
},
Config,
}
#[derive(Subcommand, Debug)]
pub enum UtilAction {
Hash {
path: PathBuf,
#[arg(long)]
bytes: bool,
#[arg(long)]
format: Option<String>,
},
KmerEncode { sequence: String },
KmerCanonical { sequence: String },
KmerRevcomp { sequence: String },
}