Merge branch 'tags' into 'main'
feat: add the concept of tags See merge request kernald/reddit-magnet!26
This commit is contained in:
commit
9c993d7c04
13 changed files with 240 additions and 11 deletions
|
|
@ -67,11 +67,19 @@ password = "password" # Optional
|
||||||
username = "reddituser1"
|
username = "reddituser1"
|
||||||
title_filter = "720p|1080p" # Optional regex pattern
|
title_filter = "720p|1080p" # Optional regex pattern
|
||||||
imdb_id = "tt1234567" # Optional IMDB ID for better metadata when sending to Bitmagnet
|
imdb_id = "tt1234567" # Optional IMDB ID for better metadata when sending to Bitmagnet
|
||||||
|
tags = ["movie", "hd"] # Optional tags
|
||||||
|
|
||||||
[sources.example2]
|
[sources.example2]
|
||||||
username = "reddituser2"
|
username = "reddituser2"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Tags
|
||||||
|
|
||||||
|
Tags are optional and can be assigned to sources. They provide additional metadata that actions can use in different ways:
|
||||||
|
|
||||||
|
- **Transmission**: Tags are passed as labels.
|
||||||
|
- **Bitmagnet**: The first tag is used as the content type (e.g., `movie`, `tv_show`), which helps Bitmagnet categorize the content properly.
|
||||||
|
|
||||||
## Potential future features
|
## Potential future features
|
||||||
|
|
||||||
- Support for additional BitTorrent clients (Deluge, qBittorrent, etc.)
|
- Support for additional BitTorrent clients (Deluge, qBittorrent, etc.)
|
||||||
|
|
|
||||||
2
migrations/2025-05-04-035709_add_tags/down.sql
Normal file
2
migrations/2025-05-04-035709_add_tags/down.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
DROP TABLE magnet_tags;
|
||||||
|
DROP TABLE tags;
|
||||||
14
migrations/2025-05-04-035709_add_tags/up.sql
Normal file
14
migrations/2025-05-04-035709_add_tags/up.sql
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
CREATE TABLE tags
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
name TEXT UNIQUE NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE magnet_tags
|
||||||
|
(
|
||||||
|
magnet_id INTEGER NOT NULL,
|
||||||
|
tag_id INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (magnet_id) REFERENCES magnets (id),
|
||||||
|
FOREIGN KEY (tag_id) REFERENCES tags (id),
|
||||||
|
PRIMARY KEY (magnet_id, tag_id)
|
||||||
|
);
|
||||||
|
|
@ -37,12 +37,16 @@ impl Action for BitmagnetAction {
|
||||||
let mut failed_magnets = Vec::new();
|
let mut failed_magnets = Vec::new();
|
||||||
|
|
||||||
for magnet in unprocessed_magnets {
|
for magnet in unprocessed_magnets {
|
||||||
|
let tags = db.get_tags_for_magnet(magnet.id)?;
|
||||||
|
let tag_refs: Vec<&str> = tags.iter().map(|s| s.as_str()).collect();
|
||||||
|
|
||||||
match self
|
match self
|
||||||
.client
|
.client
|
||||||
.submit_magnet(
|
.submit_magnet(
|
||||||
&magnet.link,
|
&magnet.link,
|
||||||
&magnet.published_at.and_utc(),
|
&magnet.published_at.and_utc(),
|
||||||
&magnet.imdb_id,
|
&magnet.imdb_id,
|
||||||
|
tag_refs,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
|
@ -53,6 +57,9 @@ impl Action for BitmagnetAction {
|
||||||
magnet.title
|
magnet.title
|
||||||
);
|
);
|
||||||
debug!("Magnet link: {}", magnet.link);
|
debug!("Magnet link: {}", magnet.link);
|
||||||
|
if !tags.is_empty() {
|
||||||
|
debug!("Tags: {:?}", tags);
|
||||||
|
}
|
||||||
db.mark_magnet_processed_for_table::<BitmagnetProcessedTable>(magnet.id)?;
|
db.mark_magnet_processed_for_table::<BitmagnetProcessedTable>(magnet.id)?;
|
||||||
processed_magnets.push(magnet);
|
processed_magnets.push(magnet);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ impl BitmagnetClient {
|
||||||
magnet: &str,
|
magnet: &str,
|
||||||
published_at: &DateTime<Utc>,
|
published_at: &DateTime<Utc>,
|
||||||
imdb_id: &Option<String>,
|
imdb_id: &Option<String>,
|
||||||
|
tags: Vec<&str>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let url = self
|
let url = self
|
||||||
.base_url
|
.base_url
|
||||||
|
|
@ -43,7 +44,6 @@ impl BitmagnetClient {
|
||||||
let structured_magnet =
|
let structured_magnet =
|
||||||
Magnet::new(magnet).map_err(|e| eyre!("Invalid magnet link: {:?}", e))?;
|
Magnet::new(magnet).map_err(|e| eyre!("Invalid magnet link: {:?}", e))?;
|
||||||
|
|
||||||
// Create a JSON object with the required fields
|
|
||||||
let mut json_body = json!({
|
let mut json_body = json!({
|
||||||
"publishedAt": published_at.to_rfc3339(),
|
"publishedAt": published_at.to_rfc3339(),
|
||||||
"source": "reddit-magnet",
|
"source": "reddit-magnet",
|
||||||
|
|
@ -71,6 +71,10 @@ impl BitmagnetClient {
|
||||||
json_body["size"] = json!(size);
|
json_body["size"] = json!(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(tag) = tags.first() {
|
||||||
|
json_body["contentType"] = json!(tag);
|
||||||
|
}
|
||||||
|
|
||||||
let response = self
|
let response = self
|
||||||
.client
|
.client
|
||||||
.post(url)
|
.post(url)
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,10 @@ impl Action for TransmissionAction {
|
||||||
let mut failed_magnets = Vec::new();
|
let mut failed_magnets = Vec::new();
|
||||||
|
|
||||||
for magnet in unprocessed_magnets {
|
for magnet in unprocessed_magnets {
|
||||||
match self.client.submit_magnet(&magnet.link).await {
|
let tags = db.get_tags_for_magnet(magnet.id)?;
|
||||||
|
let tag_refs: Vec<&str> = tags.iter().map(|s| s.as_str()).collect();
|
||||||
|
|
||||||
|
match self.client.submit_magnet(&magnet.link, tag_refs).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
debug!(
|
debug!(
|
||||||
"Successfully submitted magnet link to {}: {}",
|
"Successfully submitted magnet link to {}: {}",
|
||||||
|
|
@ -45,6 +48,9 @@ impl Action for TransmissionAction {
|
||||||
magnet.title
|
magnet.title
|
||||||
);
|
);
|
||||||
debug!("Magnet link: {}", magnet.link);
|
debug!("Magnet link: {}", magnet.link);
|
||||||
|
if !tags.is_empty() {
|
||||||
|
debug!("Tags: {:?}", tags);
|
||||||
|
}
|
||||||
db.mark_magnet_processed_for_table::<TransmissionProcessedTable>(magnet.id)?;
|
db.mark_magnet_processed_for_table::<TransmissionProcessedTable>(magnet.id)?;
|
||||||
processed_magnets.push(magnet);
|
processed_magnets.push(magnet);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,11 @@ impl TransmissionClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Submit a magnet link to Transmission
|
/// Submit a magnet link to Transmission
|
||||||
pub async fn submit_magnet(&mut self, magnet: &str) -> Result<()> {
|
pub async fn submit_magnet(&mut self, magnet: &str, tags: Vec<&str>) -> Result<()> {
|
||||||
let args = TorrentAddArgs {
|
let args = TorrentAddArgs {
|
||||||
filename: Some(magnet.to_string()),
|
filename: Some(magnet.to_string()),
|
||||||
download_dir: Some(self.download_dir.clone()),
|
download_dir: Some(self.download_dir.clone()),
|
||||||
|
labels: Some(tags.iter().map(|t| t.to_string()).collect()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ impl App {
|
||||||
magnet_links,
|
magnet_links,
|
||||||
timestamp: post.created,
|
timestamp: post.created,
|
||||||
imdb_id: source_config.imdb_id.clone(),
|
imdb_id: source_config.imdb_id.clone(),
|
||||||
|
tags: source_config.tags.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Store the post info in the database
|
// Store the post info in the database
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ pub struct SourceConfig {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub title_filter: Option<String>,
|
pub title_filter: Option<String>,
|
||||||
pub imdb_id: Option<String>,
|
pub imdb_id: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub tags: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Main application configuration
|
/// Main application configuration
|
||||||
|
|
|
||||||
146
src/db.rs
146
src/db.rs
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::models::{Magnet, NewBitmagnetProcessed, NewMagnet, NewTransmissionProcessed};
|
use crate::models::{Magnet, NewBitmagnetProcessed, NewMagnet, NewTag, NewTransmissionProcessed};
|
||||||
use crate::schema::{bitmagnet_processed, magnets, transmission_processed};
|
use crate::schema::{bitmagnet_processed, magnet_tags, magnets, tags, transmission_processed};
|
||||||
use crate::PostInfo;
|
use crate::PostInfo;
|
||||||
use color_eyre::eyre::{eyre, Result, WrapErr};
|
use color_eyre::eyre::{eyre, Result, WrapErr};
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
|
@ -129,10 +129,69 @@ impl Database {
|
||||||
})
|
})
|
||||||
.collect::<Vec<NewMagnet>>();
|
.collect::<Vec<NewMagnet>>();
|
||||||
|
|
||||||
diesel::insert_into(magnets::table)
|
self.conn.transaction(|connection| {
|
||||||
.values(&links)
|
// Insert magnets
|
||||||
.execute(&mut self.conn)
|
let insert = diesel::insert_into(magnets::table)
|
||||||
.wrap_err("Failed to save new magnet")
|
.values(&links)
|
||||||
|
.execute(connection)
|
||||||
|
.wrap_err("Failed to save new magnet")?;
|
||||||
|
|
||||||
|
// If we have tags, insert them and associate with the new magnets
|
||||||
|
// TODO: Can we get the list of inserted IDs above instead of re-querying?
|
||||||
|
if !post.tags.is_empty() && insert > 0 {
|
||||||
|
// Get the IDs of the newly inserted magnets
|
||||||
|
let new_magnet_ids: Vec<i32> = magnets::table
|
||||||
|
.select(magnets::id)
|
||||||
|
.filter(magnets::link.eq_any(&post.magnet_links))
|
||||||
|
.filter(magnets::title.eq(&post.title))
|
||||||
|
.load(connection)
|
||||||
|
.wrap_err("Failed to get IDs of newly inserted magnets")?;
|
||||||
|
|
||||||
|
// For each tag, ensure it exists and get its ID
|
||||||
|
for tag_name in &post.tags {
|
||||||
|
// Insert tag if it doesn't exist
|
||||||
|
let new_tag = NewTag { name: tag_name };
|
||||||
|
diesel::insert_into(tags::table)
|
||||||
|
.values(&new_tag)
|
||||||
|
.on_conflict_do_nothing()
|
||||||
|
.execute(connection)
|
||||||
|
.wrap_err("Failed to insert tag")?;
|
||||||
|
|
||||||
|
// Get the tag ID
|
||||||
|
let tag_id = tags::table
|
||||||
|
.select(tags::id)
|
||||||
|
.filter(tags::name.eq(tag_name))
|
||||||
|
.first::<i32>(connection)
|
||||||
|
.wrap_err("Failed to get tag ID")?;
|
||||||
|
|
||||||
|
// Associate the tag with each new magnet
|
||||||
|
for magnet_id in &new_magnet_ids {
|
||||||
|
diesel::insert_into(magnet_tags::table)
|
||||||
|
.values((
|
||||||
|
magnet_tags::magnet_id.eq(magnet_id),
|
||||||
|
magnet_tags::tag_id.eq(tag_id),
|
||||||
|
))
|
||||||
|
.on_conflict_do_nothing()
|
||||||
|
.execute(connection)
|
||||||
|
.wrap_err("Failed to associate tag with magnet")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(insert)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get tags for a specific magnet
|
||||||
|
pub fn get_tags_for_magnet(&mut self, magnet_id: i32) -> Result<Vec<String>> {
|
||||||
|
let tag_names = tags::table
|
||||||
|
.inner_join(magnet_tags::table.on(tags::id.eq(magnet_tags::tag_id)))
|
||||||
|
.filter(magnet_tags::magnet_id.eq(magnet_id))
|
||||||
|
.select(tags::name)
|
||||||
|
.load::<String>(&mut self.conn)
|
||||||
|
.wrap_err("Failed to load tags for magnet")?;
|
||||||
|
|
||||||
|
Ok(tag_names)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all magnets that have not been processed by a specific table
|
/// Get all magnets that have not been processed by a specific table
|
||||||
|
|
@ -195,6 +254,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
timestamp: Utc::now(),
|
timestamp: Utc::now(),
|
||||||
imdb_id: None,
|
imdb_id: None,
|
||||||
|
tags: vec![],
|
||||||
};
|
};
|
||||||
let expected_timestamp = post_info.timestamp.naive_utc();
|
let expected_timestamp = post_info.timestamp.naive_utc();
|
||||||
|
|
||||||
|
|
@ -234,6 +294,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
timestamp: Utc::now(),
|
timestamp: Utc::now(),
|
||||||
imdb_id: None,
|
imdb_id: None,
|
||||||
|
tags: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
// First insertion should succeed and insert 2 links
|
// First insertion should succeed and insert 2 links
|
||||||
|
|
@ -252,6 +313,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
timestamp: Utc::now(),
|
timestamp: Utc::now(),
|
||||||
imdb_id: Some("tt1234567".to_string()),
|
imdb_id: Some("tt1234567".to_string()),
|
||||||
|
tags: vec!["test".to_string()],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Second insertion should succeed but only insert the new link
|
// Second insertion should succeed but only insert the new link
|
||||||
|
|
@ -274,6 +336,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
timestamp: Utc::now(),
|
timestamp: Utc::now(),
|
||||||
imdb_id: None,
|
imdb_id: None,
|
||||||
|
tags: vec!["another_test".to_string()],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Third insertion should succeed but insert 0 links
|
// Third insertion should succeed but insert 0 links
|
||||||
|
|
@ -285,4 +348,75 @@ mod tests {
|
||||||
let magnets = db.get_all_magnets().unwrap();
|
let magnets = db.get_all_magnets().unwrap();
|
||||||
assert_eq!(magnets.len(), 3);
|
assert_eq!(magnets.len(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_store_and_retrieve_tags() {
|
||||||
|
let temp_dir = tempdir().unwrap();
|
||||||
|
let db_path = temp_dir.path().join("test.db");
|
||||||
|
|
||||||
|
let mut db = Database::new(&db_path).unwrap();
|
||||||
|
|
||||||
|
// Create a post with tags
|
||||||
|
let post_info = PostInfo {
|
||||||
|
title: "Test Title with Tags".to_string(),
|
||||||
|
submitter: "test_user".to_string(),
|
||||||
|
subreddit: "test_subreddit".to_string(),
|
||||||
|
magnet_links: vec![
|
||||||
|
"magnet:?xt=urn:btih:test_tag1".to_string(),
|
||||||
|
"magnet:?xt=urn:btih:test_tag2".to_string(),
|
||||||
|
],
|
||||||
|
timestamp: Utc::now(),
|
||||||
|
imdb_id: None,
|
||||||
|
tags: vec!["action".to_string(), "comedy".to_string()],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Insert the post with tags
|
||||||
|
let result = db.store_magnets(&post_info);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
assert_eq!(result.unwrap(), 2); // 2 links inserted
|
||||||
|
|
||||||
|
// Get all magnets to find their IDs
|
||||||
|
let magnets = db.get_all_magnets().unwrap();
|
||||||
|
assert_eq!(magnets.len(), 2);
|
||||||
|
|
||||||
|
// Verify tags for each magnet
|
||||||
|
for magnet in magnets {
|
||||||
|
let tags = db.get_tags_for_magnet(magnet.id).unwrap();
|
||||||
|
assert_eq!(tags.len(), 2);
|
||||||
|
assert!(tags.contains(&"action".to_string()));
|
||||||
|
assert!(tags.contains(&"comedy".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test adding a new magnet with some duplicate and some new tags
|
||||||
|
let post_info2 = PostInfo {
|
||||||
|
title: "Test Title with More Tags".to_string(),
|
||||||
|
submitter: "test_user".to_string(),
|
||||||
|
subreddit: "test_subreddit".to_string(),
|
||||||
|
magnet_links: vec!["magnet:?xt=urn:btih:test_tag3".to_string()],
|
||||||
|
timestamp: Utc::now(),
|
||||||
|
imdb_id: None,
|
||||||
|
tags: vec!["comedy".to_string(), "drama".to_string()], // One duplicate, one new
|
||||||
|
};
|
||||||
|
|
||||||
|
// Insert the second post
|
||||||
|
let result2 = db.store_magnets(&post_info2);
|
||||||
|
assert!(result2.is_ok());
|
||||||
|
assert_eq!(result2.unwrap(), 1); // 1 link inserted
|
||||||
|
|
||||||
|
// Get all magnets again
|
||||||
|
let magnets = db.get_all_magnets().unwrap();
|
||||||
|
assert_eq!(magnets.len(), 3);
|
||||||
|
|
||||||
|
// Find the new magnet (the one with test_tag3)
|
||||||
|
let new_magnet = magnets
|
||||||
|
.iter()
|
||||||
|
.find(|m| m.link == "magnet:?xt=urn:btih:test_tag3")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Verify tags for the new magnet
|
||||||
|
let tags = db.get_tags_for_magnet(new_magnet.id).unwrap();
|
||||||
|
assert_eq!(tags.len(), 2);
|
||||||
|
assert!(tags.contains(&"comedy".to_string()));
|
||||||
|
assert!(tags.contains(&"drama".to_string()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ pub struct PostInfo {
|
||||||
pub subreddit: String,
|
pub subreddit: String,
|
||||||
pub timestamp: DateTime<Utc>,
|
pub timestamp: DateTime<Utc>,
|
||||||
pub imdb_id: Option<String>,
|
pub imdb_id: Option<String>,
|
||||||
|
pub tags: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::schema::{bitmagnet_processed, magnets, transmission_processed};
|
use crate::schema::{bitmagnet_processed, magnet_tags, magnets, tags, transmission_processed};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
|
@ -28,6 +28,33 @@ pub struct NewMagnet<'a> {
|
||||||
pub imdb_id: Option<&'a str>,
|
pub imdb_id: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Queryable, Selectable, Identifiable)]
|
||||||
|
#[diesel(table_name = tags)]
|
||||||
|
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||||
|
pub struct Tag {
|
||||||
|
pub id: i32,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Insertable)]
|
||||||
|
#[diesel(table_name = tags)]
|
||||||
|
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||||
|
pub struct NewTag<'a> {
|
||||||
|
pub name: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Identifiable, Selectable, Queryable, Associations)]
|
||||||
|
#[diesel(belongs_to(Magnet))]
|
||||||
|
#[diesel(belongs_to(Tag))]
|
||||||
|
#[diesel(table_name = magnet_tags)]
|
||||||
|
#[diesel(primary_key(magnet_id, tag_id))]
|
||||||
|
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||||
|
pub struct MagnetTag {
|
||||||
|
pub magnet_id: i32,
|
||||||
|
pub tag_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Queryable, Selectable)]
|
#[derive(Queryable, Selectable)]
|
||||||
#[diesel(table_name = bitmagnet_processed)]
|
#[diesel(table_name = bitmagnet_processed)]
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,13 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
magnet_tags (magnet_id, tag_id) {
|
||||||
|
magnet_id -> Integer,
|
||||||
|
tag_id -> Integer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
magnets (id) {
|
magnets (id) {
|
||||||
id -> Integer,
|
id -> Integer,
|
||||||
|
|
@ -20,6 +27,13 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
tags (id) {
|
||||||
|
id -> Integer,
|
||||||
|
name -> Text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
transmission_processed (id) {
|
transmission_processed (id) {
|
||||||
id -> Integer,
|
id -> Integer,
|
||||||
|
|
@ -29,6 +43,14 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::joinable!(bitmagnet_processed -> magnets (magnet_id));
|
diesel::joinable!(bitmagnet_processed -> magnets (magnet_id));
|
||||||
|
diesel::joinable!(magnet_tags -> magnets (magnet_id));
|
||||||
|
diesel::joinable!(magnet_tags -> tags (tag_id));
|
||||||
diesel::joinable!(transmission_processed -> magnets (magnet_id));
|
diesel::joinable!(transmission_processed -> magnets (magnet_id));
|
||||||
|
|
||||||
diesel::allow_tables_to_appear_in_same_query!(bitmagnet_processed, magnets, transmission_processed,);
|
diesel::allow_tables_to_appear_in_same_query!(
|
||||||
|
bitmagnet_processed,
|
||||||
|
magnet_tags,
|
||||||
|
magnets,
|
||||||
|
tags,
|
||||||
|
transmission_processed,
|
||||||
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue