Messy code to store samples and test that out, better errors to come
This commit is contained in:
parent
7616cbd4ca
commit
0599148543
9 changed files with 220 additions and 12 deletions
3
migrations/2023-06-15-080643_create_samples/down.sql
Normal file
3
migrations/2023-06-15-080643_create_samples/down.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
DROP TABLE samples_tags;
|
||||
DROP TABLE tags;
|
||||
DROP TABLE samples;
|
20
migrations/2023-06-15-080643_create_samples/up.sql
Normal file
20
migrations/2023-06-15-080643_create_samples/up.sql
Normal file
|
@ -0,0 +1,20 @@
|
|||
CREATE TABLE samples (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
name VARCHAR NOT NULL,
|
||||
path VARCHAR NOT NULL,
|
||||
bpm REAL,
|
||||
key VARCHAR
|
||||
);
|
||||
|
||||
CREATE TABLE tags (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
name VARCHAR NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE samples_tags (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
sample_id INTEGER NOT NULL,
|
||||
tag_id INTEGER NOT NULL,
|
||||
FOREIGN KEY (sample_id) REFERENCES samples (id),
|
||||
FOREIGN KEY (tag_id) REFERENCES tags (id)
|
||||
);
|
14
src/bin/add_sample.rs
Normal file
14
src/bin/add_sample.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use sample_amp::{tag_terms::TagSuggestions, *};
|
||||
use std::{env, path::Path};
|
||||
|
||||
fn main() {
|
||||
let suggestions =
|
||||
TagSuggestions::read_from_file("tag_terms.txt").expect("expected tag file to load");
|
||||
|
||||
let connection = &mut establish_connection();
|
||||
|
||||
let file_str = env::args().nth(1).expect("Need just one argument.");
|
||||
let tags = suggestions.get_suggestions(&file_str);
|
||||
let sample = add_sample(connection, Path::new(&file_str), tags);
|
||||
dbg!(sample);
|
||||
}
|
7
src/bin/list_samples.rs
Normal file
7
src/bin/list_samples.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
fn main() {
|
||||
let connection = &mut establish_connection();
|
||||
println!(
|
||||
"Found tags: {}",
|
||||
list_tags(connection).iter().map(|t| &t.name).join(", ")
|
||||
);
|
||||
}
|
10
src/bin/list_tags.rs
Normal file
10
src/bin/list_tags.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use itertools::Itertools;
|
||||
use sample_amp::{establish_connection, list_tags};
|
||||
|
||||
fn main() {
|
||||
let connection = &mut establish_connection();
|
||||
println!(
|
||||
"Found tags: {}",
|
||||
list_tags(connection).iter().map(|t| &t.name).join(", ")
|
||||
);
|
||||
}
|
82
src/lib.rs
82
src/lib.rs
|
@ -1,8 +1,9 @@
|
|||
use diesel::prelude::*;
|
||||
use dotenvy::dotenv;
|
||||
use std::env;
|
||||
use models::{NewSample, Sample, Tag};
|
||||
use std::{env, path::Path};
|
||||
|
||||
use crate::models::{Library, NewLibrary};
|
||||
use crate::models::{Library, NewLibrary, NewSampleTag, NewTag, SampleTag};
|
||||
|
||||
pub mod models;
|
||||
pub mod schema;
|
||||
|
@ -27,3 +28,80 @@ pub fn create_library(conn: &mut SqliteConnection, name: &str) -> Library {
|
|||
.get_result(conn)
|
||||
.expect("Error saving new post")
|
||||
}
|
||||
|
||||
pub fn get_tag<'a>(conn: &mut SqliteConnection, tag: &'a str) -> Option<Tag> {
|
||||
use crate::schema::tags::dsl::*;
|
||||
tags.filter(name.eq(&tag))
|
||||
.select(Tag::as_select())
|
||||
.first(conn)
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub fn list_tags(conn: &mut SqliteConnection) -> Vec<Tag> {
|
||||
use crate::schema::tags::dsl::*;
|
||||
tags.select(Tag::as_select())
|
||||
.get_results(conn)
|
||||
.expect("can't list tags")
|
||||
}
|
||||
|
||||
pub fn samples_with_tag<'a>(conn: &mut SqliteConnection, tag: &'a str) -> Vec<Sample> {
|
||||
let tag = get_tag(conn, tag).expect("Expected tag to exist...");
|
||||
|
||||
let sample_ids = SampleTag::belonging_to(&tag).select(schema::samples_tags::sample_id);
|
||||
schema::samples::table
|
||||
.filter(schema::samples::id.eq_any(sample_ids))
|
||||
.select(Sample::as_select())
|
||||
.get_results(conn)
|
||||
.expect("expected sample")
|
||||
}
|
||||
|
||||
pub fn add_sample<'a>(
|
||||
conn: &mut SqliteConnection,
|
||||
path: &Path,
|
||||
tags: impl Iterator<Item = &'a String>,
|
||||
) -> (Sample, Vec<Tag>) {
|
||||
use crate::schema::{samples, samples_tags, tags};
|
||||
|
||||
let name = path.file_name().expect("expected file name");
|
||||
let new_sample = NewSample {
|
||||
name: &name.to_string_lossy(),
|
||||
path: &path.to_string_lossy(),
|
||||
bpm: None,
|
||||
key: None,
|
||||
};
|
||||
|
||||
let sample = diesel::insert_into(samples::table)
|
||||
.values(&new_sample)
|
||||
.returning(Sample::as_returning())
|
||||
.get_result(conn)
|
||||
.expect("Error saving new sample");
|
||||
|
||||
let tags: Vec<Tag> = tags
|
||||
.into_iter()
|
||||
.map(|tag_name| {
|
||||
let tag = get_tag(conn, tag_name).unwrap_or_else(|| {
|
||||
let tag = NewTag { name: tag_name };
|
||||
diesel::insert_into(tags::table)
|
||||
.values(&tag)
|
||||
.returning(Tag::as_returning())
|
||||
.get_result(conn)
|
||||
.expect("Error saving tag")
|
||||
});
|
||||
|
||||
let sample_tag = NewSampleTag {
|
||||
tag_id: tag.id,
|
||||
sample_id: sample.id,
|
||||
};
|
||||
|
||||
diesel::insert_into(samples_tags::table)
|
||||
.values(&sample_tag)
|
||||
.returning(SampleTag::as_returning())
|
||||
.get_result(conn)
|
||||
.expect("Error adding sample_tag");
|
||||
|
||||
tag
|
||||
})
|
||||
.collect();
|
||||
|
||||
(sample, tags)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::schema::libraries;
|
||||
use super::schema::{libraries, samples, samples_tags, tags};
|
||||
use diesel::prelude::*;
|
||||
|
||||
#[derive(Queryable, Selectable)]
|
||||
#[derive(Debug, Queryable, Selectable)]
|
||||
#[diesel(table_name = libraries)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct Library {
|
||||
|
@ -9,8 +9,57 @@ pub struct Library {
|
|||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[derive(Debug, Insertable)]
|
||||
#[diesel(table_name = libraries)]
|
||||
pub struct NewLibrary<'a> {
|
||||
pub name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug, Identifiable, Queryable, Selectable)]
|
||||
#[diesel(table_name = samples)]
|
||||
pub struct Sample {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub path: String,
|
||||
pub bpm: Option<f32>,
|
||||
pub key: Option<String>, // For now this seems to be reasonable, instead of creating a giant enum.
|
||||
}
|
||||
|
||||
#[derive(Debug, Insertable)]
|
||||
#[diesel(table_name = samples)]
|
||||
pub struct NewSample<'a> {
|
||||
pub name: &'a str,
|
||||
pub path: &'a str,
|
||||
pub bpm: Option<f32>,
|
||||
pub key: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Identifiable, Queryable, Selectable)]
|
||||
#[diesel(table_name = tags)]
|
||||
pub struct Tag {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Insertable)]
|
||||
#[diesel(table_name = tags)]
|
||||
pub struct NewTag<'a> {
|
||||
pub name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug, Identifiable, Associations, Queryable, Selectable)]
|
||||
#[diesel(belongs_to(Sample))]
|
||||
#[diesel(belongs_to(Tag))]
|
||||
#[diesel(table_name = samples_tags)]
|
||||
pub struct SampleTag {
|
||||
pub id: i32,
|
||||
pub sample_id: i32,
|
||||
pub tag_id: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Insertable)]
|
||||
#[diesel(table_name = samples_tags)]
|
||||
pub struct NewSampleTag {
|
||||
pub sample_id: i32,
|
||||
pub tag_id: i32,
|
||||
}
|
||||
|
|
|
@ -6,3 +6,33 @@ diesel::table! {
|
|||
name -> Text,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
samples (id) {
|
||||
id -> Integer,
|
||||
name -> Text,
|
||||
path -> Text,
|
||||
bpm -> Nullable<Float>,
|
||||
key -> Nullable<Text>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
samples_tags (id) {
|
||||
id -> Integer,
|
||||
sample_id -> Integer,
|
||||
tag_id -> Integer,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
tags (id) {
|
||||
id -> Integer,
|
||||
name -> Text,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::joinable!(samples_tags -> samples (sample_id));
|
||||
diesel::joinable!(samples_tags -> tags (tag_id));
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(libraries, samples, samples_tags, tags,);
|
||||
|
|
|
@ -54,13 +54,10 @@ impl TagSuggestions {
|
|||
self.map.get(input).unwrap_or(input)
|
||||
}
|
||||
|
||||
pub fn get_suggestions<'a>(
|
||||
&'a self,
|
||||
input_list: impl IntoIterator<Item = &'a str>,
|
||||
) -> impl Iterator<Item = &String> {
|
||||
input_list
|
||||
.into_iter()
|
||||
.filter_map(|i| self.map.get(i))
|
||||
pub fn get_suggestions<'a>(&'a self, input: &'a str) -> impl Iterator<Item = &String> {
|
||||
input
|
||||
.split([' ', std::path::MAIN_SEPARATOR, '_', '-', '.']) // todo: pascal case detection
|
||||
.filter_map(|i| self.map.get(&i.to_lowercase()))
|
||||
.unique()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue