mirror of
https://github.com/atuinsh/atuin.git
synced 2025-08-12 00:19:43 +02:00
Add database functions for inserting history
No real tests yet :( I would like to avoid running postgres lol
This commit is contained in:
@ -13,7 +13,7 @@ use self::{
|
|||||||
models::{History, NewHistory, NewSession, NewUser, Session, User},
|
models::{History, NewHistory, NewSession, NewUser, Session, User},
|
||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use atuin_common::utils::get_days_from_month;
|
use atuin_common::{record::Record, utils::get_days_from_month};
|
||||||
use chrono::{Datelike, TimeZone};
|
use chrono::{Datelike, TimeZone};
|
||||||
use chronoutil::RelativeDuration;
|
use chronoutil::RelativeDuration;
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
@ -55,6 +55,11 @@ pub trait Database: Sized + Clone + Send + Sync + 'static {
|
|||||||
async fn delete_history(&self, user: &User, id: String) -> DbResult<()>;
|
async fn delete_history(&self, user: &User, id: String) -> DbResult<()>;
|
||||||
async fn deleted_history(&self, user: &User) -> DbResult<Vec<String>>;
|
async fn deleted_history(&self, user: &User) -> DbResult<Vec<String>>;
|
||||||
|
|
||||||
|
async fn add_record(&self, user: &User, record: &[Record]) -> DbResult<()>;
|
||||||
|
|
||||||
|
// Return the tail record ID for each store, so (HostID, Tag, TailRecordID)
|
||||||
|
async fn tail_records(&self, user: &User) -> DbResult<Vec<(String, String, String)>>;
|
||||||
|
|
||||||
async fn count_history_range(
|
async fn count_history_range(
|
||||||
&self,
|
&self,
|
||||||
user: &User,
|
user: &User,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
-- Add migration script here
|
-- Add migration script here
|
||||||
create table records (
|
create table records (
|
||||||
id uuid primary key, -- remember to use uuidv7 for happy indices <3
|
id uuid primary key, -- remember to use uuidv7 for happy indices <3
|
||||||
|
client_id uuid not null, -- I am too uncomfortable with the idea of a client-generated primary key
|
||||||
host uuid not null, -- a unique identifier for the host
|
host uuid not null, -- a unique identifier for the host
|
||||||
parent uuid not null, -- the ID of the parent record, bearing in mind this is a linked list
|
parent uuid not null, -- the ID of the parent record, bearing in mind this is a linked list
|
||||||
timestamp bigint not null, -- not a timestamp type, as those do not have nanosecond precision
|
timestamp bigint not null, -- not a timestamp type, as those do not have nanosecond precision
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use atuin_common::record::Record;
|
||||||
use atuin_server_database::models::{History, NewHistory, NewSession, NewUser, Session, User};
|
use atuin_server_database::models::{History, NewHistory, NewSession, NewUser, Session, User};
|
||||||
use atuin_server_database::{Database, DbError, DbResult};
|
use atuin_server_database::{Database, DbError, DbResult};
|
||||||
use futures_util::TryStreamExt;
|
use futures_util::TryStreamExt;
|
||||||
@ -329,4 +330,49 @@ impl Database for Postgres {
|
|||||||
.map_err(fix_error)
|
.map_err(fix_error)
|
||||||
.map(|DbHistory(h)| h)
|
.map(|DbHistory(h)| h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn add_record(&self, user: &User, records: &[Record]) -> DbResult<()> {
|
||||||
|
let mut tx = self.pool.begin().await.map_err(fix_error)?;
|
||||||
|
|
||||||
|
for i in records {
|
||||||
|
let id = atuin_common::utils::uuid_v7().as_simple().to_string();
|
||||||
|
|
||||||
|
sqlx::query(
|
||||||
|
"insert into records
|
||||||
|
(id, client_id, host, parent, timestamp, version, tag, data, user_id)
|
||||||
|
values ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||||
|
on conflict do nothing
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(id)
|
||||||
|
.bind(&i.id)
|
||||||
|
.bind(&i.host)
|
||||||
|
.bind(&i.parent)
|
||||||
|
.bind(i.timestamp as i64) // throwing away some data, but i64 is still big in terms of time
|
||||||
|
.bind(&i.version)
|
||||||
|
.bind(&i.tag)
|
||||||
|
.bind(&i.data)
|
||||||
|
.bind(user.id)
|
||||||
|
.execute(&mut tx)
|
||||||
|
.await
|
||||||
|
.map_err(fix_error)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.commit().await.map_err(fix_error)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn tail_records(&self, user: &User) -> DbResult<Vec<(String, String, String)>> {
|
||||||
|
const TAIL_RECORDS_SQL: &str = "select host, tag, id from records rp where (select count(1) from records where parent=rp.id and user_id = $1) = 0 group by host, tag;";
|
||||||
|
|
||||||
|
let res = sqlx::query_as(TAIL_RECORDS_SQL)
|
||||||
|
.bind(user.id)
|
||||||
|
.fetch(&self.pool)
|
||||||
|
.try_collect()
|
||||||
|
.await
|
||||||
|
.map_err(fix_error)?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
0
atuin-server/src/handlers/record.rs
Normal file
0
atuin-server/src/handlers/record.rs
Normal file
Reference in New Issue
Block a user