database: Store access times

This commit is contained in:
Elias Projahn 2022-04-10 13:43:31 +02:00
parent 5c64bdef7e
commit a0554a478f
20 changed files with 315 additions and 104 deletions

View file

@ -6,6 +6,7 @@ edition = "2021"
[dependencies]
diesel = { version = "1.4.5", features = ["sqlite"] }
diesel_migrations = "1.4.0"
chrono = "0.4.19"
log = "0.4.14"
rand = "0.7.3"
thiserror = "1.0.23"

View file

@ -0,0 +1,20 @@
ALTER TABLE "persons" DROP COLUMN "last_used";
ALTER TABLE "persons" DROP COLUMN "last_played";
ALTER TABLE "instruments" DROP COLUMN "last_used";
ALTER TABLE "instruments" DROP COLUMN "last_played";
ALTER TABLE "works" DROP COLUMN "last_used";
ALTER TABLE "works" DROP COLUMN "last_played";
ALTER TABLE "ensembles" DROP COLUMN "last_used";
ALTER TABLE "ensembles" DROP COLUMN "last_played";
ALTER TABLE "recordings" DROP COLUMN "last_used";
ALTER TABLE "recordings" DROP COLUMN "last_played";
ALTER TABLE "mediums" DROP COLUMN "last_used";
ALTER TABLE "mediums" DROP COLUMN "last_played";
ALTER TABLE "tracks" DROP COLUMN "last_used";
ALTER TABLE "tracks" DROP COLUMN "last_played";

View file

@ -0,0 +1,21 @@
ALTER TABLE "persons" ADD COLUMN "last_used" BIGINT;
ALTER TABLE "persons" ADD COLUMN "last_played" BIGINT;
ALTER TABLE "instruments" ADD COLUMN "last_used" BIGINT;
ALTER TABLE "instruments" ADD COLUMN "last_played" BIGINT;
ALTER TABLE "works" ADD COLUMN "last_used" BIGINT;
ALTER TABLE "works" ADD COLUMN "last_played" BIGINT;
ALTER TABLE "ensembles" ADD COLUMN "last_used" BIGINT;
ALTER TABLE "ensembles" ADD COLUMN "last_played" BIGINT;
ALTER TABLE "recordings" ADD COLUMN "last_used" BIGINT;
ALTER TABLE "recordings" ADD COLUMN "last_played" BIGINT;
ALTER TABLE "mediums" ADD COLUMN "last_used" BIGINT;
ALTER TABLE "mediums" ADD COLUMN "last_played" BIGINT;
ALTER TABLE "tracks" ADD COLUMN "last_used" BIGINT;
ALTER TABLE "tracks" ADD COLUMN "last_played" BIGINT;

View file

@ -1,5 +1,6 @@
use super::schema::ensembles;
use super::{Database, Result};
use chrono::Utc;
use diesel::prelude::*;
use log::info;
@ -8,14 +9,29 @@ use log::info;
pub struct Ensemble {
pub id: String,
pub name: String,
pub last_used: Option<i64>,
pub last_played: Option<i64>,
}
impl Ensemble {
pub fn new(id: String, name: String) -> Self {
Self {
id,
name,
last_used: Some(Utc::now().timestamp()),
last_played: None,
}
}
}
impl Database {
/// Update an existing ensemble or insert a new one.
pub fn update_ensemble(&self, ensemble: Ensemble) -> Result<()> {
pub fn update_ensemble(&self, mut ensemble: Ensemble) -> Result<()> {
info!("Updating ensemble {:?}", ensemble);
self.defer_foreign_keys()?;
ensemble.last_used = Some(Utc::now().timestamp());
self.connection.transaction(|| {
diesel::replace_into(ensembles::table)
.values(ensemble)

View file

@ -1,5 +1,6 @@
use super::schema::instruments;
use super::{Database, Result};
use chrono::Utc;
use diesel::prelude::*;
use log::info;
@ -8,14 +9,29 @@ use log::info;
pub struct Instrument {
pub id: String,
pub name: String,
pub last_used: Option<i64>,
pub last_played: Option<i64>,
}
impl Instrument {
pub fn new(id: String, name: String) -> Self {
Self {
id,
name,
last_used: Some(Utc::now().timestamp()),
last_played: None,
}
}
}
impl Database {
/// Update an existing instrument or insert a new one.
pub fn update_instrument(&self, instrument: Instrument) -> Result<()> {
pub fn update_instrument(&self, mut instrument: Instrument) -> Result<()> {
info!("Updating instrument {:?}", instrument);
self.defer_foreign_keys()?;
instrument.last_used = Some(Utc::now().timestamp());
self.connection.transaction(|| {
diesel::replace_into(instruments::table)
.values(instrument)

View file

@ -1,6 +1,7 @@
use super::generate_id;
use super::schema::{ensembles, mediums, performances, persons, recordings, tracks};
use super::{Database, Error, Recording, Result};
use chrono::{DateTime, TimeZone, Utc};
use diesel::prelude::*;
use log::info;
@ -19,6 +20,22 @@ pub struct Medium {
/// The tracks of the medium.
pub tracks: Vec<Track>,
pub last_used: Option<DateTime<Utc>>,
pub last_played: Option<DateTime<Utc>>,
}
impl Medium {
pub fn new(id: String, name: String, discid: Option<String>, tracks: Vec<Track>) -> Self {
Self {
id,
name,
discid,
tracks,
last_used: Some(Utc::now()),
last_played: None,
}
}
}
/// A track on a medium.
@ -37,6 +54,22 @@ pub struct Track {
/// The path to the audio file containing this track.
pub path: String,
pub last_used: Option<DateTime<Utc>>,
pub last_played: Option<DateTime<Utc>>,
}
impl Track {
pub fn new(recording: Recording, work_parts: Vec<usize>, source_index: usize, path: String) -> Self {
Self {
recording,
work_parts,
source_index,
path,
last_used: Some(Utc::now()),
last_played: None,
}
}
}
/// Table data for a [`Medium`].
@ -46,6 +79,8 @@ struct MediumRow {
pub id: String,
pub name: String,
pub discid: Option<String>,
pub last_used: Option<i64>,
pub last_played: Option<i64>,
}
/// Table data for a [`Track`].
@ -59,6 +94,8 @@ struct TrackRow {
pub work_parts: String,
pub source_index: i32,
pub path: String,
pub last_used: Option<i64>,
pub last_played: Option<i64>,
}
impl Database {
@ -79,6 +116,8 @@ impl Database {
id: medium_id.to_owned(),
name: medium.name.clone(),
discid: medium.discid.clone(),
last_used: Some(Utc::now().timestamp()),
last_played: medium.last_played.map(|t| t.timestamp()),
};
diesel::insert_into(mediums::table)
@ -109,6 +148,8 @@ impl Database {
work_parts,
source_index: track.source_index as i32,
path: track.path.clone(),
last_used: Some(Utc::now().timestamp()),
last_played: track.last_played.map(|t| t.timestamp()),
};
diesel::insert_into(tracks::table)
@ -254,6 +295,8 @@ impl Database {
name: row.name,
discid: row.discid,
tracks,
last_used: row.last_used.map(|t| Utc.timestamp(t, 0)),
last_played: row.last_played.map(|t| Utc.timestamp(t, 0)),
};
Ok(medium)
@ -285,6 +328,8 @@ impl Database {
work_parts: part_indices,
source_index: row.source_index as usize,
path: row.path,
last_used: row.last_used.map(|t| Utc.timestamp(t, 0)),
last_played: row.last_played.map(|t| Utc.timestamp(t, 0)),
};
Ok(track)

View file

@ -1,5 +1,6 @@
use super::schema::persons;
use super::{Database, Result};
use chrono::Utc;
use diesel::prelude::*;
use log::info;
@ -9,9 +10,21 @@ pub struct Person {
pub id: String,
pub first_name: String,
pub last_name: String,
pub last_used: Option<i64>,
pub last_played: Option<i64>,
}
impl Person {
pub fn new(id: String, first_name: String, last_name: String) -> Self {
Self {
id,
first_name,
last_name,
last_used: Some(Utc::now().timestamp()),
last_played: None,
}
}
/// Get the full name in the form "First Last".
pub fn name_fl(&self) -> String {
format!("{} {}", self.first_name, self.last_name)
@ -25,10 +38,12 @@ impl Person {
impl Database {
/// Update an existing person or insert a new one.
pub fn update_person(&self, person: Person) -> Result<()> {
pub fn update_person(&self, mut person: Person) -> Result<()> {
info!("Updating person {:?}", person);
self.defer_foreign_keys()?;
person.last_used = Some(Utc::now().timestamp());
self.connection.transaction(|| {
diesel::replace_into(persons::table)
.values(person)

View file

@ -1,6 +1,7 @@
use super::generate_id;
use super::schema::{ensembles, performances, persons, recordings};
use super::{Database, Ensemble, Error, Instrument, Person, Result, Work};
use chrono::{DateTime, TimeZone, Utc};
use diesel::prelude::*;
use log::info;
@ -11,16 +12,31 @@ pub struct Recording {
pub work: Work,
pub comment: String,
pub performances: Vec<Performance>,
pub last_used: Option<DateTime<Utc>>,
pub last_played: Option<DateTime<Utc>>,
}
impl Recording {
pub fn new(id: String, work: Work, comment: String, performances: Vec<Performance>) -> Self {
Self {
id,
work,
comment,
performances,
last_used: Some(Utc::now()),
last_played: None,
}
}
/// Initialize a new recording with a work.
pub fn new(work: Work) -> Self {
pub fn from_work(work: Work) -> Self {
Self {
id: generate_id(),
work,
comment: String::new(),
performances: Vec::new(),
last_used: Some(Utc::now()),
last_played: None,
}
}
@ -82,6 +98,8 @@ struct RecordingRow {
pub id: String,
pub work: String,
pub comment: String,
pub last_used: Option<i64>,
pub last_played: Option<i64>,
}
impl From<Recording> for RecordingRow {
@ -90,6 +108,8 @@ impl From<Recording> for RecordingRow {
id: recording.id,
work: recording.work.id,
comment: recording.comment,
last_used: Some(Utc::now().timestamp()),
last_played: recording.last_played.map(|t| t.timestamp()),
}
}
}
@ -255,6 +275,8 @@ impl Database {
work,
comment: row.comment,
performances: performance_descriptions,
last_used: row.last_used.map(|t| Utc.timestamp(t, 0)),
last_played: row.last_played.map(|t| Utc.timestamp(t, 0)),
};
Ok(recording_description)

View file

@ -2,6 +2,8 @@ table! {
ensembles (id) {
id -> Text,
name -> Text,
last_used -> Nullable<BigInt>,
last_played -> Nullable<BigInt>,
}
}
@ -17,6 +19,8 @@ table! {
instruments (id) {
id -> Text,
name -> Text,
last_used -> Nullable<BigInt>,
last_played -> Nullable<BigInt>,
}
}
@ -25,6 +29,8 @@ table! {
id -> Text,
name -> Text,
discid -> Nullable<Text>,
last_used -> Nullable<BigInt>,
last_played -> Nullable<BigInt>,
}
}
@ -43,6 +49,8 @@ table! {
id -> Text,
first_name -> Text,
last_name -> Text,
last_used -> Nullable<BigInt>,
last_played -> Nullable<BigInt>,
}
}
@ -51,6 +59,8 @@ table! {
id -> Text,
work -> Text,
comment -> Text,
last_used -> Nullable<BigInt>,
last_played -> Nullable<BigInt>,
}
}
@ -63,6 +73,8 @@ table! {
work_parts -> Text,
source_index -> Integer,
path -> Text,
last_used -> Nullable<BigInt>,
last_played -> Nullable<BigInt>,
}
}
@ -80,6 +92,8 @@ table! {
id -> Text,
composer -> Text,
title -> Text,
last_used -> Nullable<BigInt>,
last_played -> Nullable<BigInt>,
}
}

View file

@ -1,6 +1,7 @@
use super::generate_id;
use super::schema::{instrumentations, work_parts, works};
use super::{Database, Error, Instrument, Person, Result};
use chrono::{DateTime, TimeZone, Utc};
use diesel::prelude::*;
use diesel::{Insertable, Queryable};
use log::info;
@ -12,6 +13,8 @@ struct WorkRow {
pub id: String,
pub composer: String,
pub title: String,
pub last_used: Option<i64>,
pub last_played: Option<i64>,
}
impl From<Work> for WorkRow {
@ -20,6 +23,8 @@ impl From<Work> for WorkRow {
id: work.id,
composer: work.composer.id,
title: work.title,
last_used: Some(Utc::now().timestamp()),
last_played: work.last_played.map(|t| t.timestamp()),
}
}
}
@ -57,17 +62,33 @@ pub struct Work {
pub composer: Person,
pub instruments: Vec<Instrument>,
pub parts: Vec<WorkPart>,
pub last_used: Option<DateTime<Utc>>,
pub last_played: Option<DateTime<Utc>>,
}
impl Work {
pub fn new(id: String, title: String, composer: Person, instruments: Vec<Instrument>, parts: Vec<WorkPart>) -> Self {
Self {
id,
title,
composer,
instruments,
parts,
last_used: Some(Utc::now()),
last_played: None,
}
}
/// Initialize a new work with a composer.
pub fn new(composer: Person) -> Self {
pub fn from_composer(composer: Person) -> Self {
Self {
id: generate_id(),
title: String::new(),
composer,
instruments: Vec::new(),
parts: Vec::new(),
last_used: Some(Utc::now()),
last_played: None,
}
}
@ -109,9 +130,7 @@ impl Database {
.execute(&self.connection)?;
let Work {
instruments,
parts,
..
instruments, parts, ..
} = work;
for instrument in instruments {
@ -200,6 +219,8 @@ impl Database {
title: row.title,
instruments,
parts,
last_used: row.last_used.map(|t| Utc.timestamp(t, 0)),
last_played: row.last_played.map(|t| Utc.timestamp(t, 0)),
})
}