use std::{
borrow::Cow,
env,
path::{Path, PathBuf},
str::FromStr,
time::Duration,
};
use async_trait::async_trait;
use atuin_common::utils;
use fs_err as fs;
use itertools::Itertools;
use rand::{distributions::Alphanumeric, Rng};
use sql_builder::{bind::Bind, esc, quote, SqlBuilder, SqlName};
use sqlx::{
sqlite::{
SqliteConnectOptions, SqliteJournalMode, SqlitePool, SqlitePoolOptions, SqliteRow,
SqliteSynchronous,
},
Result, Row,
};
use time::OffsetDateTime;
use crate::{
history::{HistoryId, HistoryStats},
utils::get_host_user,
};
use super::{
history::History,
ordering,
settings::{FilterMode, SearchMode, Settings},
};
pub struct Context {
pub session: String,
pub cwd: String,
pub hostname: String,
pub host_id: String,
pub git_root: Option<PathBuf>,
}
#[derive(Default, Clone)]
pub struct OptFilters {
pub exit: Option<i64>,
pub exclude_exit: Option<i64>,
pub cwd: Option<String>,
pub exclude_cwd: Option<String>,
pub before: Option<String>,
pub after: Option<String>,
pub limit: Option<i64>,
pub offset: Option<i64>,
pub reverse: bool,
}
pub fn current_context() -> Context {
let Ok(session) = env::var("ATUIN_SESSION") else {
eprintln!("ERROR: Failed to find $ATUIN_SESSION in the environment. Check that you have correctly set up your shell.");
std::process::exit(1);
};
let hostname = get_host_user();
let cwd = utils::get_current_dir();
let host_id = Settings::host_id().expect("failed to load host ID");
let git_root = utils::in_git_repo(cwd.as_str());
Context {
session,
hostname,
cwd,
git_root,
host_id: host_id.0.as_simple().to_string(),
}
}
#[async_trait]
pub trait Database: Send + Sync + 'static {
async fn save(&self, h: &History) -> Result<()>;
async fn save_bulk(&self, h: &[History]) -> Result<()>;
async fn load(&self, id: &str) -> Result<Option<History>>;
async fn list(
&self,
filters: &[FilterMode],
context: &Context,
max: Option<usize>,
unique: bool,
include_deleted: bool,
) -> Result<Vec<History>>;
async fn range(&self, from: OffsetDateTime, to: OffsetDateTime) -> Result<Vec<