Add support for generic timeline #525
2 changed files with 73 additions and 13 deletions
|
@ -1,12 +1,13 @@
|
||||||
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl};
|
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl};
|
||||||
|
|
||||||
|
use lists::List;
|
||||||
use posts::Post;
|
use posts::Post;
|
||||||
use schema::{posts, timeline, timeline_definition};
|
use schema::{posts, timeline, timeline_definition};
|
||||||
use {Connection, Error, Result};
|
use {Connection, Error, Result};
|
||||||
|
|
||||||
pub(crate) mod query;
|
pub(crate) mod query;
|
||||||
trinity-1686a
commented
hum, I don't know, my through was that the first one would be on top, the second under and so on, but it clearly limit what can be done, I'll revert that hum, I don't know, my through was that the first one would be on top, the second under and so on, but it clearly limit what can be done, I'll revert that
|
|||||||
|
|
||||||
use self::query::{Kind, TimelineQuery};
|
use self::query::{Kind, QueryError, TimelineQuery};
|
||||||
|
|
||||||
#[derive(Clone, Queryable, Identifiable)]
|
#[derive(Clone, Queryable, Identifiable)]
|
||||||
#[table_name = "timeline_definition"]
|
#[table_name = "timeline_definition"]
|
||||||
|
@ -47,27 +48,74 @@ impl Timeline {
|
||||||
conn: &Connection,
|
conn: &Connection,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
name: String,
|
name: String,
|
||||||
query: String,
|
query_string: String,
|
||||||
) -> Result<Timeline> {
|
) -> Result<Timeline> {
|
||||||
TimelineQuery::parse(&query)?; // verify the query is valid
|
{
|
||||||
|
let query = TimelineQuery::parse(&query_string)?; // verify the query is valid
|
||||||
|
if let Some(err) =
|
||||||
|
query
|
||||||
trinity-1686a
commented
Welcome to the party! Welcome to the party!
Diesel consider that anything eq None unless we are that explicit
trinity-1686a
commented
I've tried for a few hours to add a I've tried for a few hours to add a `eq_optional` via some trait, but the best I got was "only" 4 compiler error, of which the shortest was 4 lines long. I'm giving up on this
kudos for trying. kudos for trying.
|
|||||||
|
.list_used_lists()
|
||||||
|
.into_iter()
|
||||||
|
.find_map(|(name, kind)| {
|
||||||
|
let list = List::find_by_name(conn, Some(user_id), &name)
|
||||||
|
.map(|l| l.kind() == kind);
|
||||||
|
match list {
|
||||||
|
Ok(true) => None,
|
||||||
|
Ok(false) => Some(Error::TimelineQuery(QueryError::RuntimeError(
|
||||||
|
format!("list '{}' has the wrong type for this usage", name),
|
||||||
|
))),
|
||||||
|
Err(_) => Some(Error::TimelineQuery(QueryError::RuntimeError(
|
||||||
|
format!("list '{}' was not found", name),
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Err(err)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Self::insert(
|
Self::insert(
|
||||||
conn,
|
conn,
|
||||||
NewTimeline {
|
NewTimeline {
|
||||||
user_id: Some(user_id),
|
user_id: Some(user_id),
|
||||||
name,
|
name,
|
||||||
query,
|
query: query_string,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_for_instance(conn: &Connection, name: String, query: String) -> Result<Timeline> {
|
pub fn new_for_instance(
|
||||||
TimelineQuery::parse(&query)?; // verify the query is valid
|
conn: &Connection,
|
||||||
|
name: String,
|
||||||
|
query_string: String,
|
||||||
|
) -> Result<Timeline> {
|
||||||
|
{
|
||||||
|
let query = TimelineQuery::parse(&query_string)?; // verify the query is valid
|
||||||
|
if let Some(err) =
|
||||||
|
query
|
||||||
|
.list_used_lists()
|
||||||
|
.into_iter()
|
||||||
|
.find_map(|(name, kind)| {
|
||||||
|
let list = List::find_by_name(conn, None, &name).map(|l| l.kind() == kind);
|
||||||
|
match list {
|
||||||
|
Ok(true) => None,
|
||||||
|
Ok(false) => Some(Error::TimelineQuery(QueryError::RuntimeError(
|
||||||
|
format!("list '{}' has the wrong type for this usage", name),
|
||||||
|
))),
|
||||||
|
Err(_) => Some(Error::TimelineQuery(QueryError::RuntimeError(
|
||||||
|
format!("list '{}' was not found", name),
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Err(err)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Self::insert(
|
Self::insert(
|
||||||
conn,
|
conn,
|
||||||
NewTimeline {
|
NewTimeline {
|
||||||
user_id: None,
|
user_id: None,
|
||||||
name,
|
name,
|
||||||
query,
|
query: query_string,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,8 +177,8 @@ impl<'a> TQ<'a> {
|
||||||
|
|
||||||
fn list_used_lists(&self) -> Vec<(String, ListType)> {
|
fn list_used_lists(&self) -> Vec<(String, ListType)> {
|
||||||
match self {
|
match self {
|
||||||
TQ::Or(inner) => inner.iter().flat_map(|e| e.list_used_lists()).collect(),
|
TQ::Or(inner) => inner.iter().flat_map(TQ::list_used_lists).collect(),
|
||||||
TQ::And(inner) => inner.iter().flat_map(|e| e.list_used_lists()).collect(),
|
TQ::And(inner) => inner.iter().flat_map(TQ::list_used_lists).collect(),
|
||||||
TQ::Arg(Arg::In(typ, List::List(name)), _) => vec![(
|
TQ::Arg(Arg::In(typ, List::List(name)), _) => vec![(
|
||||||
name.to_string(),
|
name.to_string(),
|
||||||
match typ {
|
match typ {
|
||||||
|
@ -270,11 +270,17 @@ impl WithList {
|
||||||
}
|
}
|
||||||
(WithList::Lang, ListType::Prefix) => {
|
(WithList::Lang, ListType::Prefix) => {
|
||||||
let lang = whatlang::detect(post.content.get())
|
let lang = whatlang::detect(post.content.get())
|
||||||
.and_then(|i| if i.is_reliable() { Some(i.lang()) } else {None} )
|
.and_then(|i| {
|
||||||
|
if i.is_reliable() {
|
||||||
|
Some(i.lang())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
.unwrap_or(Lang::Eng)
|
.unwrap_or(Lang::Eng)
|
||||||
.name();
|
.name();
|
||||||
list.contains_prefix(conn, lang)
|
list.contains_prefix(conn, lang)
|
||||||
},
|
}
|
||||||
(_, _) => Err(QueryError::RuntimeError(format!(
|
(_, _) => Err(QueryError::RuntimeError(format!(
|
||||||
"The list '{}' is of the wrong type for this usage",
|
"The list '{}' is of the wrong type for this usage",
|
||||||
name
|
name
|
||||||
|
@ -313,11 +319,17 @@ impl WithList {
|
||||||
}
|
}
|
||||||
WithList::Lang => {
|
WithList::Lang => {
|
||||||
let lang = whatlang::detect(post.content.get())
|
let lang = whatlang::detect(post.content.get())
|
||||||
.and_then(|i| if i.is_reliable() { Some(i.lang()) } else {None} )
|
.and_then(|i| {
|
||||||
|
if i.is_reliable() {
|
||||||
|
Some(i.lang())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
.unwrap_or(Lang::Eng)
|
.unwrap_or(Lang::Eng)
|
||||||
.name();
|
.name();
|
||||||
Ok(list.iter().any(|s| lang.starts_with(s)))
|
Ok(list.iter().any(|s| lang.starts_with(s)))
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue
What is this field for? Is it important to always have a defined order for timelines? And how should it be determined: by the user, or automatically?