mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 19:57:25 +01:00
database: Store access times
This commit is contained in:
parent
5c64bdef7e
commit
a0554a478f
20 changed files with 315 additions and 104 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
21
database/migrations/2022-04-10-103835_access_history/up.sql
Normal file
21
database/migrations/2022-04-10-103835_access_history/up.sql
Normal 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;
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue