use super::lines::{format_r_path, generate_schema_lines};
use nu_ansi_term::{Color, Style};
use std::path::Path;
struct SchemaStyles {
heading: Style,
code_fence: Style,
path: Style,
sql_keyword: Style,
sql_identifier: Style,
sql_comment: Style,
r_keyword: Style,
r_string: Style,
r_operator: Style,
}
impl Default for SchemaStyles {
fn default() -> Self {
Self {
heading: Style::new().bold(),
code_fence: Style::new().fg(Color::DarkGray),
path: Style::new().fg(Color::Green),
sql_keyword: Style::new().fg(Color::Blue).bold(),
sql_identifier: Style::new().fg(Color::Yellow),
sql_comment: Style::new().fg(Color::DarkGray).italic(),
r_keyword: Style::new().fg(Color::Cyan).bold(),
r_string: Style::new().fg(Color::Green),
r_operator: Style::new().fg(Color::Magenta),
}
}
}
pub(super) fn print_schema_colored(history_path: &Path) {
let s = SchemaStyles::default();
let r_path = history_path.join("r.db");
let shell_path = history_path.join("shell.db");
println!("{}", s.heading.paint("# History Database"));
println!();
println!("{}", s.heading.paint("## Location"));
println!();
println!("- R mode: {}", s.path.paint(r_path.display().to_string()));
println!(
"- Shell mode: {}",
s.path.paint(shell_path.display().to_string())
);
println!();
print_sql_schema(&s);
println!();
print_indexes(&s);
println!();
print_artifact_metadata(&s);
println!();
print_r_example_code(&s, &r_path);
}
pub(super) fn print_schema_plain(history_path: &Path) {
for line in generate_schema_lines(history_path) {
println!("{}", line);
}
}
fn print_sql_schema(s: &SchemaStyles) {
println!("{}", s.heading.paint("## SQLite Schema"));
println!();
println!("{}", s.code_fence.paint("```sql"));
println!(
"{} {} {} (",
s.sql_keyword.paint("CREATE"),
s.sql_keyword.paint("TABLE"),
s.sql_identifier.paint("history")
);
println!(
" {} {},",
s.sql_identifier.paint("id"),
s.sql_keyword.paint("INTEGER PRIMARY KEY AUTOINCREMENT")
);
println!(
" {} {} {},",
s.sql_identifier.paint("command_line"),
s.sql_keyword.paint("TEXT"),
s.sql_keyword.paint("NOT NULL")
);
println!(
" {} {}, {}",
s.sql_identifier.paint("start_timestamp"),
s.sql_keyword.paint("INTEGER"),
s.sql_comment.paint("-- Unix timestamp (nullable)")
);
println!(
" {} {},",
s.sql_identifier.paint("session_id"),
s.sql_keyword.paint("INTEGER")
);
println!(
" {} {},",
s.sql_identifier.paint("hostname"),
s.sql_keyword.paint("TEXT")
);
println!(
" {} {}, {}",
s.sql_identifier.paint("cwd"),
s.sql_keyword.paint("TEXT"),
s.sql_comment.paint("-- Current working directory")
);
println!(
" {} {},",
s.sql_identifier.paint("duration_ms"),
s.sql_keyword.paint("INTEGER")
);
println!(
" {} {},",
s.sql_identifier.paint("exit_status"),
s.sql_keyword.paint("INTEGER")
);
println!(
" {} {} {}",
s.sql_identifier.paint("more_info"),
s.sql_keyword.paint("TEXT"),
s.sql_comment.paint("-- Reserved for future use")
);
println!(");");
println!("{}", s.code_fence.paint("```"));
}
fn print_indexes(s: &SchemaStyles) {
println!("{}", s.heading.paint("## Indexes"));
println!();
println!(
"- {} {} {}({})",
s.sql_identifier.paint("idx_history_time"),
s.sql_keyword.paint("ON"),
s.sql_identifier.paint("history"),
s.sql_identifier.paint("start_timestamp")
);
println!(
"- {} {} {}({})",
s.sql_identifier.paint("idx_history_cwd"),
s.sql_keyword.paint("ON"),
s.sql_identifier.paint("history"),
s.sql_identifier.paint("cwd")
);
println!(
"- {} {} {}({})",
s.sql_identifier.paint("idx_history_exit_status"),
s.sql_keyword.paint("ON"),
s.sql_identifier.paint("history"),
s.sql_identifier.paint("exit_status")
);
println!(
"- {} {} {}({})",
s.sql_identifier.paint("idx_history_cmd"),
s.sql_keyword.paint("ON"),
s.sql_identifier.paint("history"),
s.sql_identifier.paint("command_line")
);
}
fn print_artifact_metadata(s: &SchemaStyles) {
println!("{}", s.heading.paint("## arf Artifact Metadata"));
println!();
println!("Newly created single-history databases also contain:");
println!("{}", s.code_fence.paint("```sql"));
println!(
"{} {} {} (",
s.sql_keyword.paint("CREATE"),
s.sql_keyword.paint("TABLE"),
s.sql_identifier.paint("arf_metadata")
);
println!(
" {} {} {},",
s.sql_identifier.paint("key"),
s.sql_keyword.paint("TEXT"),
s.sql_keyword.paint("PRIMARY KEY NOT NULL")
);
println!(
" {} {} {}",
s.sql_identifier.paint("value"),
s.sql_keyword.paint("TEXT"),
s.sql_keyword.paint("NOT NULL")
);
println!(");");
println!("{}", s.code_fence.paint("```"));
println!("- `artifact`: `history`");
println!("- `format_version`: `1`");
println!("- `history_kind`: `r` or `shell`");
println!("- `created_by_version`: the arf package version");
println!(
"- `legacy_migrated_from` (optional): the legacy directory whose history `arf history migrate` copied into this database; written only by that command"
);
println!(
"Unified exports use `artifact = history-export`, `format_version = 1`, and `created_by_version`; they omit `history_kind`."
);
}
fn print_r_example_code(s: &SchemaStyles, r_path: &Path) {
println!("{}", s.heading.paint("## Analyze or Export"));
println!();
println!("Please read the database directly.");
println!("Example in R:");
println!();
println!("{}", s.code_fence.paint("```r"));
println!(
"{}({})",
s.r_keyword.paint("library"),
s.r_keyword.paint("DBI")
);
println!(
"{}({})",
s.r_keyword.paint("library"),
s.r_keyword.paint("tibble")
);
println!();
println!(
"con {} {}(",
s.r_operator.paint("<-"),
s.r_keyword.paint("dbConnect")
);
println!(" RSQLite::{}(),", s.r_keyword.paint("SQLite"));
println!(" {}", s.r_string.paint(format_r_path(r_path)));
println!(")");
println!(
"history_data {} {}(",
s.r_operator.paint("<-"),
s.r_keyword.paint("dbGetQuery")
);
println!(" con,");
println!(
" {}",
s.r_string
.paint(r#""SELECT * FROM history ORDER BY id DESC LIMIT 10""#)
);
println!(") {}", s.r_operator.paint("|>"));
println!(" {}()", s.r_keyword.paint("as_tibble"));
println!("{}(con)", s.r_keyword.paint("dbDisconnect"));
println!("{}", s.code_fence.paint("```"));
}