use crate::{args, parse, remember};
use clap_cryo::Parser;
use color_print::cstr;
use colored::Colorize;
use cryo_freeze::{err, CollectError, ExecutionEnv, FreezeSummary};
use std::{sync::Arc, time::SystemTime};
pub async fn run(args: args::Args) -> Result<Option<FreezeSummary>, CollectError> {
if args.datatype.first() == Some(&"help".to_string()) {
return handle_help_subcommands(args).await
}
let cryo_dir: std::path::PathBuf = args.output_dir.clone().into();
let cryo_dir = cryo_dir.join(".cryo");
let args = if args.datatype.is_empty() {
let remembered = remember::load_remembered_command(cryo_dir.clone())?;
if remembered.cryo_version != cryo_freeze::CRYO_VERSION {
eprintln!("remembered command comes from different cryo version, proceed with caution");
eprintln!();
};
println!(
"{} {} {}",
"remembering previous command:".truecolor(170, 170, 170),
"cryo".bold().white(),
remembered.command.into_iter().skip(1).collect::<Vec<_>>().join(" ").white().bold()
);
println!();
args.merge_with_precedence(remembered.args)
} else {
args
};
if args.remember {
println!("remembering this command for future use");
println!();
remember::save_remembered_command(cryo_dir, &args)?;
}
let t_start_parse = Some(SystemTime::now());
let (query, source, sink, env) = match parse::parse_args(&args).await {
Ok(opts) => opts,
Err(e) => return Err(e.into()),
};
let source = Arc::new(source);
let env = ExecutionEnv { t_start_parse, ..env };
let env = env.set_start_time();
cryo_freeze::freeze(&query, &source, &sink, &env).await
}
async fn handle_help_subcommands(args: args::Args) -> Result<Option<FreezeSummary>, CollectError> {
if args.datatype.len() == 1 {
args::Args::parse_from(vec!["cryo", "-h"]);
} else if args.datatype.len() == 2 && args.datatype[1] == "syntax" {
let content = cstr!(
r#"<white><bold>Block specification syntax</bold></white>
- can use numbers <white><bold>--blocks 5000 6000 7000</bold></white>
- can use ranges <white><bold>--blocks 12M:13M 15M:16M</bold></white>
- can use a parquet file <white><bold>--blocks ./path/to/file.parquet[:COLUMN_NAME]</bold></white>
- can use multiple parquet files <white><bold>--blocks ./path/to/files/*.parquet[:COLUMN_NAME]</bold></white>
- numbers can contain { _ . K M B } <white><bold>5_000 5K 15M 15.5M</bold></white>
- omitting range end means latest <white><bold>15.5M:</bold></white> == <white><bold>15.5M:latest</bold></white>
- omitting range start means 0 <white><bold>:700</bold></white> == <white><bold>0:700</bold></white>
- minus on start means minus end <white><bold>-1000:7000</bold></white> == <white><bold>6000:7000</bold></white>
- plus sign on end means plus start <white><bold>15M:+1000</bold></white> == <white><bold>15M:15.001K</bold></white>
- can use every nth value <white><bold>2000:5000:1000</bold></white> == <white><bold>2000 3000 4000</bold></white>
- can use n values total <white><bold>100:200/5</bold></white> == <white><bold>100 124 149 174 199</bold></white>
<white><bold>Transaction specification syntax</bold></white>
- can use transaction hashes <white><bold>--txs TX_HASH1 TX_HASH2 TX_HASH3</bold></white>
- can use a parquet file <white><bold>--txs ./path/to/file.parquet[:COLUMN_NAME]</bold></white>
(default column name is <white><bold>transaction_hash</bold></white>)
- can use multiple parquet files <white><bold>--txs ./path/to/ethereum__logs*.parquet</bold></white>"#
);
println!("{}", content);
} else if args.datatype.len() == 2 && args.datatype.contains(&"datasets".to_string()) {
cryo_freeze::print_all_datasets();
} else {
let args = args::Args { datatype: args.datatype[1..].to_vec(), ..args };
let (datatypes, schemas) = super::parse::schemas::parse_schemas(&args)?;
for datatype in datatypes.into_iter() {
if schemas.len() > 1 {
println!();
println!();
};
if let Some(schema) = schemas.get(&datatype) {
cryo_freeze::print_dataset_info(datatype, schema);
} else {
return Err(err("missing schema for datatype"))
}
}
}
Ok(None)
}