oxibooru-client/szurubooru-client/src/tokens.rs
2024-09-05 13:43:08 -07:00

885 lines
28 KiB
Rust

//! Types that represent various Query tokens for the API endpoints that support them. Be
//! warned that the types here help with the Type safety for the Tag names only. It does
//! not guarantee that a given API endpoint will support the given tag.
#[cfg(feature = "python")]
use pyo3::{exceptions::PyValueError, prelude::*};
use std::fmt::Display;
use strum_macros::AsRefStr;
/// A named token such as `foo:bar`
pub trait NamedToken: AsRef<str> {}
/// A type of token used for sorting. E.g: `sort:random`
pub trait SortableToken: AsRef<str> {}
/// Special tokens such as `liked` posts or `tumbleweed` that
/// don't fit into a query token or sort token
pub trait SpecialToken: AsRef<str> {}
/// Supports types that can be converted to a Query string
pub trait ToQueryString {
/// Convert `&self` into a HTML query string
fn to_query_string(&self) -> String;
}
/// A query token using for searching posts, tags and pools
#[derive(Debug, Clone)]
#[cfg_attr(all(feature = "python"), pyclass(module = "szurubooru_client.tokens"))]
pub struct QueryToken {
/// The key for this token. For `foo:bar` this would be `foo`
pub key: String,
/// The value for this token. For `foo:bar` this would be `bar`
pub value: String,
}
impl QueryToken {
///
/// Construct a named token for a search query. Final results takes the form of
/// `key:value`. Values containing `:` and `-` are automatically escaped.
///
/// `key` can either be one of the existing [NamedToken] types for convenience, or anything
/// that implements [`AsRef<str>`] for custom tokens.
///
/// ```no_run
/// # use szurubooru_client::SzurubooruClient;
/// # let client = SzurubooruClient::new_with_token("http://foo", "user", "pwd", true).unwrap();
/// // let client = SzurubooruClient::new(...)
/// use szurubooru_client::tokens::{PostNamedToken, QueryToken};
/// // Find all posts with at least one comment...
/// let qt = QueryToken::token(PostNamedToken::CommentCount, "0..");
/// // ...with a positive score.
/// let custom = QueryToken::token("score", "0..");
/// client.request().list_posts(Some(&vec![qt, custom]));
/// ```
pub fn token(key: impl AsRef<str>, value: impl AsRef<str>) -> Self {
let escaped = value.as_ref().replace(":", "\\:").replace("-", "\\-");
Self {
key: key.as_ref().to_string(),
value: escaped,
}
}
///
/// Constructs a token for sorting purposes. Final results take the form of
/// `sort:value`.
///
/// `value` can either be one of the existing [SortableToken] types for convenience or any type
/// that implements [`AsRef<str>`]
///
/// ```no_run
/// # use szurubooru_client::SzurubooruClient;
/// # let client = SzurubooruClient::new_with_token("http://foo", "user", "pwd", true).unwrap();
/// // let client = SzurubooruClient::new(...)
/// use szurubooru_client::tokens::{PostSortToken, QueryToken};
/// // Sort posts at random
/// let sort_token = QueryToken::sort(PostSortToken::Random);
/// client.request().list_posts(Some(&vec![sort_token]));
/// ```
pub fn sort(value: impl AsRef<str>) -> Self {
Self {
key: "sort".to_string(),
value: value.as_ref().to_string(),
}
}
///
/// Constructs a new anonymous token. These are resource specific, e.g for [crate::models::PostResource] it's
/// the same as [PostNamedToken::Tag].
///
/// Keys containing `:` and `-` are automatically escaped.
/// ```no_run
/// # use szurubooru_client::SzurubooruClient;
/// # let client = SzurubooruClient::new_with_token("http://foo", "user", "pwd", true).unwrap();
/// // let client = SzurubooruClient::new(...)
/// use szurubooru_client::tokens::QueryToken;
/// // Fetch all posts containing the tag "re:zero"
/// // Tag will be escaped as "re\:zero"
/// let re_zero = QueryToken::anonymous("re:zero");
/// client.request().list_posts(Some(&vec![re_zero]));
/// ```
pub fn anonymous(key: impl AsRef<str>) -> Self {
let escaped = key.as_ref().replace(":", "\\:").replace("-", "\\-");
Self {
key: escaped,
value: "".to_string(),
}
}
///
/// Constructs a new special token. Some resource types (see [PostSpecialToken]) support
/// special tokens. This is a convenience function for `QueryToken::anonymous` that provides
/// type-safe construction of a QueryToken.
/// ```no_run
/// # use szurubooru_client::SzurubooruClient;
/// use szurubooru_client::tokens::{PostSpecialToken, QueryToken};
/// # let client = SzurubooruClient::new_with_token("http://foo", "user", "pwd", true).unwrap();
/// // let client = SzurubooruClient::new(...)
/// // Return posts liked by the current authenticated user
/// let liked_posts = QueryToken::special(PostSpecialToken::Liked);
/// client.request().list_posts(Some(&vec![liked_posts]));
/// ```
pub fn special(key: impl AsRef<str>) -> Self {
QueryToken::anonymous(key)
}
///
/// Negate the existing token. Include becomes Exclude and vice versa.
///
/// E.g: `konosuba` becomes `-konosuba`
///
pub fn negate(&self) -> Self {
let negated_key = if self.key.starts_with("-") {
self.key[1..].to_string()
} else {
format!("-{}", self.key)
};
Self {
key: negated_key,
value: self.value.clone(),
}
}
}
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pyfunction)]
/// Generates a named token. Named tokens are used to filter resources returned by the API.
/// An example of this would be returning posts with a certain safety value.
///
/// This function will accept any string, but if you want to be more sure about your code you
/// can use any of the :ref:`Named token <named-tokens-enums>` types listed below.
/// See the example below.
///
/// :param key: String or Named field
/// :param value: The string or int value to use to filter by
/// :returns: The named query token
/// :rtype: QueryToken
///
/// -----
/// Usage
/// -----
/// This lists all posts that are marked as 'safe'.
///
/// ```python
/// client.list_posts(query=[named_token(PostNamedToken.Safety, 'safe')])
/// ```
///
/// Which is equivalent to the possibly more error-prone:
///
/// ```python
/// client.list_posts(query=[named_token("safety", 'safe')])
/// ```
pub fn named_token(key: &Bound<'_, PyAny>, value: &Bound<'_, PyAny>) -> PyResult<QueryToken> {
QueryToken::token_py(key, value)
}
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pyfunction)]
/// Generates a sorting token. Sorting tokens are used to sort resources returned by the API.
/// An example of this would be returning posts by score descending.
///
/// This function will accept any string, but if you want to be more sure about your code you
/// can use any of the :ref:`Sort token <sort-tokens-enums>` types listed below. See the example below.
///
/// :param key: String or Sort field name
/// :returns: The sort query token
/// :rtype: QueryToken
///
/// -----
/// Usage
/// -----
/// This lists posts by score descending:
///
/// ```python
/// client.list_posts(query=[-sort_token(PostSortToken.Score)])
/// ```
///
/// Which is equivalent to the possibly more error-prone:
///
/// ```python
/// client.list_posts(query=[-sort_token("score")])
/// ```
pub fn sort_token(key: &Bound<'_, PyAny>) -> PyResult<QueryToken> {
QueryToken::sort_py(key)
}
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pyfunction)]
/// Generates an anonymous token. Anonymous tokens are tokens that don't require some
/// sort of prefix to be used in a search. What the anonymous tag corresponds to depends
/// on the type of resource you're listing. For example, when listing posts the anonymous
/// tags correspond to post tags
///
///
/// :param str key: The anonymous token to create
/// :returns: The anonymous query token
/// :rtype: QueryToken
///
/// -----
/// Usage
/// -----
///
/// ```python
/// client.list_posts(fields=[anonymous_token("cat")])
/// ```
pub fn anonymous_token(key: &Bound<'_, PyAny>) -> PyResult<QueryToken> {
QueryToken::anonymous_py(key)
}
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pyfunction)]
/// Special tokens are a very limited set of tokens supported by the ``list_posts`` API.
/// They include being able to filter by posts that the current user has upvoted, or favorited.
/// See :class:`PostSpecialToken` for all the supported token names.
///
/// :param key: The special token name, string or ``PostSpecialToken``
///
/// -----
/// Usage
/// -----
///
/// Selects posts with score of 0, without comments and without favorites
///
/// ```python
/// client.list_post(fields=[special_token(PostSpecialToken.Tumbleweed)])
/// ```
pub fn special_token(key: &Bound<'_, PyAny>) -> PyResult<QueryToken> {
QueryToken::special_py(key)
}
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
impl QueryToken {
#[pyo3(name = "__str__")]
/// Generates a string representation of this QueryToken
pub fn to_python_string(&self) -> PyResult<String> {
Ok(format!("QueryToken(\"{}\", \"{}\")", self.key, self.value))
}
#[pyo3(name = "__repr__")]
/// Generates a string representation of this QueryToken
pub fn to_python_repr(&self) -> PyResult<String> {
self.to_python_string()
}
#[pyo3(name = "token")]
#[staticmethod]
#[doc(hidden)]
pub fn token_py(key: &Bound<'_, PyAny>, value: &Bound<'_, PyAny>) -> PyResult<Self> {
let value = if let Ok(value) = value.extract::<u32>() {
value.to_string()
} else {
value.extract::<String>()?
};
if let Ok(tnt) = key.extract::<TagNamedToken>() {
Ok(QueryToken::token(tnt, value))
} else if let Ok(pnt) = key.extract::<PostNamedToken>() {
Ok(QueryToken::token(pnt, value))
} else if let Ok(pnt) = key.extract::<PoolNamedToken>() {
Ok(QueryToken::token(pnt, value))
} else if let Ok(comment) = key.extract::<CommentNamedToken>() {
Ok(QueryToken::token(comment, value))
} else if let Ok(user) = key.extract::<UserNamedToken>() {
Ok(QueryToken::token(user, value))
} else if let Ok(x) = key.extract::<SnapshotNamedToken>() {
Ok(QueryToken::token(x, value))
} else if let Ok(strvalue) = key.extract::<String>() {
Ok(QueryToken::token(strvalue, value))
} else {
Err(PyErr::new::<PyValueError, _>("Invalid value type for key"))
}
}
#[pyo3(name = "sort")]
#[staticmethod]
#[doc(hidden)]
pub fn sort_py(key: &Bound<'_, PyAny>) -> PyResult<Self> {
if let Ok(tnt) = key.extract::<TagSortToken>() {
Ok(QueryToken::sort(tnt))
} else if let Ok(pnt) = key.extract::<PostSortToken>() {
Ok(QueryToken::sort(pnt))
} else if let Ok(pnt) = key.extract::<PoolSortToken>() {
Ok(QueryToken::sort(pnt))
} else if let Ok(comment) = key.extract::<CommentSortToken>() {
Ok(QueryToken::sort(comment))
} else if let Ok(user) = key.extract::<UserSortToken>() {
Ok(QueryToken::sort(user))
} else if let Ok(strvalue) = key.extract::<String>() {
Ok(QueryToken::sort(strvalue))
} else {
Err(PyErr::new::<PyValueError, _>("Invalid value type for key"))
}
}
#[pyo3(name = "anonymous")]
#[staticmethod]
#[doc(hidden)]
pub fn anonymous_py(key: &Bound<'_, PyAny>) -> PyResult<Self> {
let key = key.extract::<String>()?;
Ok(QueryToken::anonymous(key))
}
#[pyo3(name = "special")]
#[staticmethod]
#[doc(hidden)]
pub fn special_py(key: &Bound<'_, PyAny>) -> PyResult<Self> {
if let Ok(special) = key.extract::<PostSpecialToken>() {
Ok(QueryToken::special(special))
} else if let Ok(strvalue) = key.extract::<String>() {
Ok(QueryToken::special(strvalue))
} else {
Err(PyErr::new::<PyValueError, _>("Invalid value type for key"))
}
}
#[pyo3(name = "negate")]
#[doc(hidden)]
pub fn negate_py(&self) -> PyResult<Self> {
Ok(self.negate())
}
/// Negates the query token. Would turn ``konosuba`` into ``-konosuba``
pub fn __neg__(&self) -> PyResult<Self> {
Ok(self.negate())
}
}
impl Display for QueryToken {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let suffix = if !self.value.is_empty() {
format!(":{}", &self.value)
} else {
"".to_string()
};
write!(f, "{}{}", &self.key, suffix)
}
}
impl ToQueryString for Vec<QueryToken> {
fn to_query_string(&self) -> String {
let query_vec: Vec<String> = self.iter().map(|qv| qv.to_string()).collect();
query_vec.join(" ")
}
}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with [list_tags](crate::SzurubooruRequest::list_tags)
pub enum TagNamedToken {
/// having given name (accepts wildcards)
Name,
/// having given category (accepts wildcards)
Category,
/// created at given date
CreationDate,
/// edited at given date
LastEditDate,
/// alias of [TagNamedToken::LastEditTime]
LastEditTime,
/// alias of [TagNamedToken::LastEditTime]
EditDate,
/// alias of [TagNamedToken::LastEditTime]
EditTime,
/// used in given number of posts
Usages,
/// alias of [TagNamedToken::Usages]
UsageCount,
/// alias of [TagNamedToken::Usages]
PostCount,
/// with given number of suggestions
SuggestionCount,
/// with given number of implications
ImplicationCount,
}
impl NamedToken for TagNamedToken {}
/*#[cfg(feature="python")]
impl<'py> FromPyObject<'py> for TagNamedToken {
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
/*use pyo3::exceptions::PyTypeError;
if ob.is_instance_of::<TagNamedToken>() {
Ok()
}
let strvalue = ob.extract::<String>()?;
match TagNamedToken::from_str(&strvalue) {
Ok(tnt) => Ok(tnt),
Err(_) => Err(PyTypeError::new_err("Invalid variant"))
}*/
Ok(ob.downcast_into_exact::<Self>()?.)
}
}*/
#[derive(Debug, AsRefStr, Eq, PartialEq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe sort query tokens for use with [list_tags](crate::SzurubooruRequest::list_tags)
pub enum TagSortToken {
/// as random as it can get
Random,
/// A to Z
Name,
/// category (A to Z)
Category,
/// recently created first
CreationDate,
/// alias of [TagSortToken::CreationDate]
CreationTime,
/// recently edited first
LastEditDate,
/// alias of [TagSortToken::CreationTime]
LastEditTime,
/// alias of [TagSortToken::CreationTime]
EditDate,
/// alias of [TagSortToken::CreationTime]
EditTime,
/// used in most posts first
Usages,
/// alias of [TagSortToken::Usages]
UsageCount,
/// alias of [TagSortToken::Usages]
PostCount,
/// with most suggestions first
SuggestionCount,
/// with most implications first
ImplicationCount,
}
impl SortableToken for TagSortToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with [list_posts](crate::SzurubooruRequest::list_posts)
pub enum PostNamedToken {
/// having given post number
Id,
/// having given tag (accepts wildcards)
Tag,
/// having given score
Score,
/// uploaded by given user (accepts wildcards)
Uploader,
/// alias of [PostNamedToken::Uploader]
Upload,
/// alias of [PostNamedToken::Uploader]
Submit,
/// commented by given user (accepts wildcards)
Comment,
/// favorited by given user (accepts wildcards)
Fav,
/// belonging to the pool with the given ID
Pool,
/// having given number of tags
TagCount,
/// having given number of comments
CommentCount,
/// favorited by given number of users
FavCount,
/// having given number of annotations
NoteCount,
/// having given note text (accepts wildcards)
NoteText,
/// having given number of relations
RelationCount,
/// having been featured given number of times
FeatureCount,
/// given type of posts. The value can be either `image`, `animation` (or `animated` or `anim`),
/// `flash` (or `swf`) or `video` (or `webm`). Use [PostType](crate::models::PostType)
/// for type-safe values
Type,
/// having given SHA1 checksum
ContentChecksum,
/// having given file size (in bytes)
FileSize,
/// having given image width (where applicable)
ImageWidth,
/// having given image height (where applicable)
ImageHeight,
/// having given number of pixels (image width * image height)
ImageArea,
/// having given aspect ratio (image width / image height)
ImageAspectRatio,
/// alias of [PostNamedToken::ImageAspectRatio]
ImageAr,
/// alias of [PostNamedToken::ImageWidth]
Width,
/// alias of [PostNamedToken::ImageHeight]
Height,
/// alias of [PostNamedToken::ImageAspectRatio]
Ar,
/// alias of [PostNamedToken::ImageAspectRatio]
AspectRatio,
/// posted at given date
CreationDate,
/// alias of [PostNamedToken::CreationDate]
CreationTime,
/// alias of [PostNamedToken::CreationDate]
Date,
/// alias of [PostNamedToken::CreationDate]
Time,
/// edited at given date
LastEditDate,
/// alias of [PostNamedToken::LastEditDate]
LastEditTime,
/// alias of [PostNamedToken::LastEditDate]
EditDate,
/// alias of [PostNamedToken::LastEditDate]
EditTime,
/// commented at given date
CommentDate,
/// alias of [PostNamedToken::CommentDate]
CommentTime,
/// last favorited at given time
FavDate,
/// alias of [PostNamedToken::FavDate]
FavTime,
/// featured at given date
FeatureDate,
/// alias of [PostNamedToken::FeatureDate]
FeatureTime,
/// Post safety. Can be either `safe`, `sketchy` (or `questionable`) or `unsafe`
/// Use [PostSafety](crate::models::PostSafety) for the type-safe version
Safety,
/// alias of [PostNamedToken::Safety]
Rating,
}
impl NamedToken for PostNamedToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe sort query tokens for use with [list_posts](crate::SzurubooruRequest::list_posts)
pub enum PostSortToken {
/// as random as it can get
Random,
/// highest to lowest post number
Id,
/// highest scored
Score,
/// with most tags
TagCount,
/// most commented first
CommentCount,
/// loved by most
FavCount,
/// with most annotations
NoteCount,
/// with most relations
RelationCount,
/// most often featured
FeatureCount,
/// largest files first
FileSize,
/// widest images first
ImageWidth,
/// tallest images first
ImageHeight,
/// largest images first
ImageArea,
/// alias of [PostSortToken::ImageWidth]
Width,
/// alias of [PostSortToken::ImageHeight]
Height,
/// alias of [PostSortToken::ImageArea]
Area,
/// newest to oldest (pretty much same as id)
CreationDate,
/// alias of [PostSortToken::CreationDate]
CreationTime,
/// alias of [PostSortToken::CreationDate]
Date,
/// alias of [PostSortToken::CreationDate]
Time,
/// like [PostSortToken::CreationDate], only looks at last edit time instead
LastEditDate,
/// alias of [PostSortToken::LastEditDate]
LastEditTime,
/// alias of [PostSortToken::LastEditDate]
EditDate,
/// alias of [PostSortToken::LastEditDate]
EditTime,
/// recently commented by anyone
CommentDate,
/// alias of [PostSortToken::CommentDate]
CommentTime,
/// recently added to favorites by anyone
FavDate,
/// alias of [PostSortToken::FavDate]
FavTime,
/// recently featured
FeatureDate,
/// alias of [PostSortToken::FeatureDate]
FeatureTime,
}
impl SortableToken for PostSortToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe special query tokens for use with [list_posts](crate::SzurubooruRequest::list_posts)
pub enum PostSpecialToken {
/// posts liked by currently logged-in user
Liked,
/// posts disliked by currently logged in user
Disliked,
/// posts added to favorites by currently logged-in user
Fav,
/// posts with score of 0, without comments and without favorites
Tumbleweed,
}
impl SpecialToken for PostSpecialToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with [list_pools](crate::SzurubooruRequest::list_pools)
pub enum PoolNamedToken {
/// having given name (accepts wildcards)
Name,
/// having given category (accepts wildcards)
Category,
/// created at given date
CreationDate,
/// alias of [CreationDate](PoolNamedToken::CreationDate)
CreationTime,
/// edited at given date
LastEditDate,
/// alias of [LastEditDate](PoolNamedToken::LastEditDate)
LastEditTime,
/// alias of [LastEditDate](PoolNamedToken::LastEditDate)
EditDate,
/// alias of [LastEditDate](PoolNamedToken::LastEditDate)
EditTime,
/// used in given number of posts
PostCount,
}
impl NamedToken for PoolNamedToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe sort query tokens for use with [list_pools](crate::SzurubooruRequest::list_pools)
pub enum PoolSortToken {
/// as random as it can get
Random,
/// A to Z
Name,
/// category (A to Z)
Category,
/// recently created first
CreationDate,
/// alias of [CreationDate](PoolSortToken::CreationDate)
CreationTime,
/// recently edited first
LastEditDate,
/// alias of [CreationDate](PoolSortToken::LastEditDate)
LastEditTime,
/// alias of [CreationDate](PoolSortToken::LastEditDate)
EditDate,
/// alias of [CreationDate](PoolSortToken::LastEditDate)
EditTime,
/// used in most posts first
PostCount,
}
impl SortableToken for PoolSortToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with
/// [list_comments](crate::SzurubooruRequest::list_comments)
pub enum CommentNamedToken {
/// specific comment ID
Id,
/// specific post ID
Post,
/// created by given user (accepts wildcards)
User,
/// alias of user
Author,
/// containing given text (accepts wildcards)
Text,
/// created at given date
CreationDate,
/// alias of creation-date
CreationTime,
/// whose most recent edit date matches given date
LastEditDate,
/// alias of last-edit-date
LastEditTime,
/// alias of last-edit-date
EditDate,
/// alias of last-edit-date
EditTime,
}
impl NamedToken for CommentNamedToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe sort query tokens for use with
/// [list_comments](crate::SzurubooruRequest::list_comments)
pub enum CommentSortToken {
/// as random as it can get
Random,
/// author name, A to Z
User,
/// alias of user
Author,
/// post ID, newest to oldest
Post,
/// newest to oldest
CreationDate,
/// alias of creation-date
CreationTime,
/// recently edited first
LastEditDate,
/// alias of last-edit-date
LastEditTime,
/// alias of last-edit-date
EditDate,
/// alias of last-edit-date
EditTime,
}
impl SortableToken for CommentSortToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with [list_users](crate::SzurubooruRequest::list_users)
pub enum UserNamedToken {
/// having given name (accepts wildcards)
Name,
/// registered at given date
CreationDate,
/// alias of [CreationDate](UserNamedToken::CreationDate)
CreationTime,
/// whose most recent login date matches given date
LastLoginDate,
/// alias of [LastLoginDate](UserNamedToken::LastLoginDate)
LastLoginTime,
/// alias of [LastLoginDate](UserNamedToken::LastLoginDate)
LoginDate,
/// alias of [LastLoginDate](UserNamedToken::LastLoginDate)
LoginTime,
}
impl NamedToken for UserNamedToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe sort query tokens for use with [list_users](crate::SzurubooruRequest::list_users)
pub enum UserSortToken {
/// as random as it can get
Random,
/// A to Z
Name,
/// newest to oldest
CreationDate,
/// alias of [CreationDate](UserSortToken::CreationDate)
CreationTime,
/// recently active first
LastLoginDate,
/// alias of [LastLoginDate](UserSortToken::LastLoginDate)
LastLoginTime,
/// alias of [LastLoginDate](UserSortToken::LastLoginDate)
LoginDate,
/// alias of [LastLoginDate](UserSortToken::LastLoginDate)
LoginTime,
}
impl SortableToken for UserNamedToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with
/// [list_snapshots](crate::SzurubooruRequest::list_snapshots)
pub enum SnapshotNamedToken {
/// involving given resource type
Type,
/// involving given resource id
Id,
/// created at given date
Date,
/// alias of date
Time,
/// modified, created, deleted or merged
Operation,
/// name of the user that created given snapshot (accepts wildcards)
User,
}
impl NamedToken for SnapshotNamedToken {}
#[cfg(test)]
mod tests {
use crate::tokens::*;
#[test]
fn test_query_token() {
let qt = QueryToken::token(PostNamedToken::CommentCount, "1");
assert_eq!(qt.to_string(), "comment-count:1");
let qt = qt.negate();
assert_eq!(qt.to_string(), "-comment-count:1");
let qt = QueryToken::sort(PostSortToken::Random);
assert_eq!(qt.to_string(), "sort:random");
let qt = QueryToken::token(TagNamedToken::Name, "re:zero");
assert_eq!(qt.to_string(), r#"name:re\:zero"#);
let qt = QueryToken::special(PostSpecialToken::Liked);
assert_eq!(qt.to_string(), "liked");
let qt = QueryToken::anonymous("foo");
assert_eq!(qt.to_string(), "foo");
}
#[test]
fn test_vec_query() {
let query_vec = vec![
QueryToken::token(PostNamedToken::CommentCount, "1"),
QueryToken::sort(PostSortToken::Random),
];
assert_eq!(query_vec.to_query_string(), "comment-count:1 sort:random");
}
}