Commit a6d9dac7 authored by Ben Boeckel's avatar Ben Boeckel
Browse files

api/endpoint: simplify endpoint implementation more

By having the implementable trait actually be just an endpoint, the
combinators to page or ignore the results is much more ergonomic.
parent 66f8fcae
......@@ -16,14 +16,21 @@
//! releases.
mod client;
mod endpoint;
mod ignore;
mod paged;
mod query;
pub mod endpoint_prelude;
pub mod projects;
pub mod users;
pub use self::client::Client;
pub use self::endpoint::Endpoint;
pub use self::endpoint::Pairs;
pub use self::ignore::ignore;
pub use self::ignore::Ignore;
......@@ -32,3 +39,5 @@ pub use self::paged::LinkHeaderParseError;
pub use self::paged::Pageable;
pub use self::paged::Paged;
pub use self::paged::Pagination;
pub use self::query::Query;
......@@ -11,30 +11,35 @@ use serde::de::DeserializeOwned;
use url::form_urlencoded::Serializer;
use url::UrlQuery;
use crate::api::Client;
use crate::api::{Client, Query};
use crate::gitlab::GitlabError;
/// A type for managing query parameters.
pub type Pairs<'a> = Serializer<'a, UrlQuery<'a>>;
pub trait Query<T> {
fn query(&self, client: &dyn Client) -> Result<T, GitlabError>;
}
pub trait SingleQuery<T>
where
T: DeserializeOwned,
{
/// A trait for providing the necessary information for a single REST API endpoint.
pub trait Endpoint {
/// The HTTP method to use for the endpoint.
fn method(&self) -> Method;
/// The path to the endpoint.
fn endpoint(&self) -> Cow<'static, str>;
/// Add query parameters for the endpoint.
#[allow(unused_variables)]
fn add_parameters(&self, pairs: Pairs) {}
/// Form data for the endpoint.
fn form_data(&self) -> Vec<u8> {
Vec::new()
}
}
fn single_query(&self, client: &dyn Client) -> Result<T, GitlabError> {
impl<E, T> Query<T> for E
where
E: Endpoint,
T: DeserializeOwned,
{
fn query(&self, client: &dyn Client) -> Result<T, GitlabError> {
let mut url = client.rest_endpoint(&self.endpoint())?;
self.add_parameters(url.query_pairs_mut());
......
......@@ -4,19 +4,19 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Endpoint prelude
//!
//! This module re-exports all of the types needed for endpoints to implement the
//! [`Endpoint`](../trait.Endpoint.html) trait.
pub use std::borrow::Cow;
pub use reqwest::Method;
pub use serde::de::DeserializeOwned;
pub use crate::api::Client;
pub use crate::api::Endpoint;
pub use crate::api::Pageable;
pub use crate::gitlab::GitlabError;
pub use crate::query::Pairs;
pub use crate::query::Query;
pub use crate::query::SingleQuery;
pub use crate::api::Pairs;
pub use crate::query_common::EnableState;
pub use crate::query_common::SortOrder;
......@@ -4,9 +4,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::api::Client;
use crate::api::{Client, Endpoint, Query};
use crate::gitlab::GitlabError;
use crate::query::{Query, SingleQuery};
/// A query modifier that ignores the data returned from an endpoint.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
......@@ -23,7 +22,7 @@ pub fn ignore<E>(endpoint: E) -> Ignore<E> {
impl<E> Query<()> for Ignore<E>
where
E: SingleQuery<()>,
E: Endpoint,
{
fn query(&self, client: &dyn Client) -> Result<(), GitlabError> {
let mut url = client.rest_endpoint(&self.endpoint.endpoint())?;
......
......@@ -10,9 +10,8 @@ use serde::de::DeserializeOwned;
use thiserror::Error;
use url::Url;
use crate::api::Client;
use crate::api::{Client, Endpoint, Query};
use crate::gitlab::{GitlabError, PaginationError};
use crate::query::{Query, SingleQuery};
struct LinkHeader<'a> {
url: &'a str,
......@@ -154,7 +153,7 @@ pub trait Pageable {
impl<E, T> Query<Vec<T>> for Paged<E>
where
E: SingleQuery<Vec<T>>,
E: Endpoint,
E: Pageable,
T: DeserializeOwned,
{
......
......@@ -6,8 +6,8 @@
use derive_builder::Builder;
use crate::api::endpoint_prelude::*;
use crate::query_common::NameOrId;
use crate::query_prelude::*;
/// Query for a job within a project.
#[derive(Debug, Builder)]
......@@ -27,10 +27,7 @@ impl<'a> Job<'a> {
}
}
impl<'a, T> SingleQuery<T> for Job<'a>
where
T: DeserializeOwned,
{
impl<'a> Endpoint for Job<'a> {
fn method(&self) -> Method {
Method::GET
}
......@@ -40,15 +37,6 @@ where
}
}
impl<'a, T> Query<T> for Job<'a>
where
T: DeserializeOwned,
{
fn query(&self, client: &dyn Client) -> Result<T, GitlabError> {
self.single_query(client)
}
}
#[cfg(test)]
mod tests {
use crate::api::projects::pipelines::Pipelines;
......
......@@ -9,8 +9,8 @@ use std::fmt;
use derive_builder::Builder;
use crate::api::endpoint_prelude::*;
use crate::query_common::NameOrId;
use crate::query_prelude::*;
/// Scopes for jobs.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
......@@ -96,10 +96,7 @@ impl<'a> JobsBuilder<'a> {
}
}
impl<'a, T> SingleQuery<Vec<T>> for Jobs<'a>
where
T: DeserializeOwned,
{
impl<'a> Endpoint for Jobs<'a> {
fn method(&self) -> Method {
Method::GET
}
......
......@@ -6,8 +6,8 @@
use derive_builder::Builder;
use crate::api::endpoint_prelude::*;
use crate::query_common::NameOrId;
use crate::query_prelude::*;
/// Cancel a pipeline.
#[derive(Debug, Builder)]
......@@ -26,10 +26,7 @@ impl<'a> CancelPipeline<'a> {
}
}
impl<'a, T> SingleQuery<T> for CancelPipeline<'a>
where
T: DeserializeOwned,
{
impl<'a> Endpoint for CancelPipeline<'a> {
fn method(&self) -> Method {
Method::POST
}
......@@ -43,15 +40,6 @@ where
}
}
impl<'a, T> Query<T> for CancelPipeline<'a>
where
T: DeserializeOwned,
{
fn query(&self, client: &dyn Client) -> Result<T, GitlabError> {
self.single_query(client)
}
}
#[cfg(test)]
mod tests {
use crate::api::projects::pipelines::CancelPipeline;
......
......@@ -9,8 +9,8 @@ use std::fmt;
use derive_builder::Builder;
use crate::api::endpoint_prelude::*;
use crate::query_common::NameOrId;
use crate::query_prelude::*;
/// The type of a pipeline variable.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
......@@ -114,10 +114,7 @@ impl<'a> CreatePipelineBuilder<'a> {
}
}
impl<'a, T> SingleQuery<T> for CreatePipeline<'a>
where
T: DeserializeOwned,
{
impl<'a> Endpoint for CreatePipeline<'a> {
fn method(&self) -> Method {
Method::POST
}
......@@ -142,15 +139,6 @@ where
}
}
impl<'a, T> Query<T> for CreatePipeline<'a>
where
T: DeserializeOwned,
{
fn query(&self, client: &dyn Client) -> Result<T, GitlabError> {
self.single_query(client)
}
}
#[cfg(test)]
mod tests {
use crate::api::projects::pipelines::CreatePipeline;
......
......@@ -6,8 +6,8 @@
use derive_builder::Builder;
use crate::api::endpoint_prelude::*;
use crate::query_common::NameOrId;
use crate::query_prelude::*;
/// Delete a pipeline.
#[derive(Debug, Builder)]
......@@ -26,10 +26,7 @@ impl<'a> DeletePipeline<'a> {
}
}
impl<'a, T> SingleQuery<T> for DeletePipeline<'a>
where
T: DeserializeOwned,
{
impl<'a> Endpoint for DeletePipeline<'a> {
fn method(&self) -> Method {
Method::DELETE
}
......@@ -39,15 +36,6 @@ where
}
}
impl<'a, T> Query<T> for DeletePipeline<'a>
where
T: DeserializeOwned,
{
fn query(&self, client: &dyn Client) -> Result<T, GitlabError> {
self.single_query(client)
}
}
#[cfg(test)]
mod tests {
use crate::api::projects::pipelines::DeletePipeline;
......
......@@ -8,9 +8,9 @@ use std::collections::HashSet;
use derive_builder::Builder;
use crate::api::endpoint_prelude::*;
use crate::api::projects::JobScope;
use crate::query_common::NameOrId;
use crate::query_prelude::*;
/// Query for jobs within a pipeline.
#[derive(Debug, Builder)]
......@@ -55,10 +55,7 @@ impl<'a> JobsBuilder<'a> {
}
}
impl<'a, T> SingleQuery<Vec<T>> for Jobs<'a>
where
T: DeserializeOwned,
{
impl<'a> Endpoint for Jobs<'a> {
fn method(&self) -> Method {
Method::GET
}
......
......@@ -6,8 +6,8 @@
use derive_builder::Builder;
use crate::api::endpoint_prelude::*;
use crate::query_common::NameOrId;
use crate::query_prelude::*;
/// Query a single pipeline on a project.
#[derive(Debug, Builder)]
......@@ -27,10 +27,7 @@ impl<'a> Pipeline<'a> {
}
}
impl<'a, T> SingleQuery<T> for Pipeline<'a>
where
T: DeserializeOwned,
{
impl<'a> Endpoint for Pipeline<'a> {
fn method(&self) -> Method {
Method::GET
}
......@@ -40,15 +37,6 @@ where
}
}
impl<'a, T> Query<T> for Pipeline<'a>
where
T: DeserializeOwned,
{
fn query(&self, client: &dyn Client) -> Result<T, GitlabError> {
self.single_query(client)
}
}
#[cfg(test)]
mod tests {
use crate::api::projects::pipelines::Pipeline;
......
......@@ -10,8 +10,8 @@ use std::fmt;
use chrono::{DateTime, Utc};
use derive_builder::Builder;
use crate::api::endpoint_prelude::*;
use crate::query_common::NameOrId;
use crate::query_prelude::*;
/// Scopes for pipelines.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
......@@ -190,10 +190,7 @@ fn bool_as_str(b: bool) -> &'static str {
}
}
impl<'a, T> SingleQuery<Vec<T>> for Pipelines<'a>
where
T: DeserializeOwned,
{
impl<'a> Endpoint for Pipelines<'a> {
fn method(&self) -> Method {
Method::GET
}
......
......@@ -6,8 +6,8 @@
use derive_builder::Builder;
use crate::api::endpoint_prelude::*;
use crate::query_common::NameOrId;
use crate::query_prelude::*;
/// Retry a pipeline.
///
......@@ -28,10 +28,7 @@ impl<'a> RetryPipeline<'a> {
}
}
impl<'a, T> SingleQuery<T> for RetryPipeline<'a>
where
T: DeserializeOwned,
{
impl<'a> Endpoint for RetryPipeline<'a> {
fn method(&self) -> Method {
Method::POST
}
......@@ -45,15 +42,6 @@ where
}
}
impl<'a, T> Query<T> for RetryPipeline<'a>
where
T: DeserializeOwned,
{
fn query(&self, client: &dyn Client) -> Result<T, GitlabError> {
self.single_query(client)
}
}
#[cfg(test)]
mod tests {
use crate::api::projects::pipelines::RetryPipeline;
......
......@@ -6,8 +6,8 @@
use derive_builder::Builder;
use crate::api::endpoint_prelude::*;
use crate::query_common::NameOrId;
use crate::query_prelude::*;
/// Query for the variables of a pipeline.
#[derive(Debug, Builder)]
......@@ -26,10 +26,7 @@ impl<'a> PipelineVariables<'a> {
}
}
impl<'a, T> SingleQuery<Vec<T>> for PipelineVariables<'a>
where
T: DeserializeOwned,
{
impl<'a> Endpoint for PipelineVariables<'a> {
fn method(&self) -> Method {
Method::GET
}
......@@ -43,15 +40,6 @@ where
}
}
impl<'a, T> Query<Vec<T>> for PipelineVariables<'a>
where
T: DeserializeOwned,
{
fn query(&self, client: &dyn Client) -> Result<Vec<T>, GitlabError> {
self.single_query(client)
}
}
#[cfg(test)]
mod tests {
use crate::api::projects::pipelines::PipelineVariables;
......
......@@ -10,7 +10,7 @@ use std::fmt;
use chrono::{DateTime, Utc};
use derive_builder::Builder;
use crate::query_prelude::*;
use crate::api::endpoint_prelude::*;
use crate::types::{AccessLevel, VisibilityLevel};
/// Keys project results may be ordered by.
......@@ -192,10 +192,7 @@ fn bool_as_str(b: bool) -> &'static str {
}
}
impl<T> SingleQuery<Vec<T>> for Projects
where
T: DeserializeOwned,
{
impl Endpoint for Projects {
fn method(&self) -> Method {
Method::GET
}
......
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::api::Client;
use crate::gitlab::GitlabError;
/// A trait which represents a query which may be made to a GitLab client.
pub trait Query<T> {
/// Perform the query against the client.
fn query(&self, client: &dyn Client) -> Result<T, GitlabError>;
}
......@@ -6,7 +6,7 @@
use derive_builder::Builder;
use crate::query_prelude::*;
use crate::api::endpoint_prelude::*;
/// Query information about the API calling user.
#[derive(Debug, Clone, Copy, Builder)]
......@@ -19,10 +19,7 @@ impl CurrentUser {
}
}
impl<T> SingleQuery<T> for CurrentUser
where
T: DeserializeOwned,
{
impl Endpoint for CurrentUser {
fn method(&self) -> Method {
Method::GET
}
......@@ -32,15 +29,6 @@ where
}
}
impl<T> Query<T> for CurrentUser
where
T: DeserializeOwned,
{
fn query(&self, client: &dyn Client) -> Result<T, GitlabError> {
self.single_query(client)
}
}
#[cfg(test)]
mod tests {
use crate::api::users::CurrentUser;
......
......@@ -6,7 +6,7 @@
use derive_builder::Builder;
use crate::query_prelude::*;
use crate::api::endpoint_prelude::*;
/// Query a user by ID.
#[derive(Debug, Clone, Copy, Builder)]
......@@ -22,10 +22,7 @@ impl User {
}
}
impl<T> SingleQuery<T> for User
where
T: DeserializeOwned,
{
impl Endpoint for User {
fn method(&self) -> Method {
Method::GET
}
......@@ -35,15 +32,6 @@ where
}
}
impl<T> Query<T> for User
where
T: DeserializeOwned,
{
fn query(&self, client: &dyn Client) -> Result<T, GitlabError> {
self.single_query(client)
}
}
#[cfg(test)]
mod tests {
use crate::api::users::User;
......
......@@ -11,7 +11,7 @@ use std::fmt;
use chrono::{DateTime, Utc};
use derive_builder::Builder;
use crate::query_prelude::*;
use crate::api::endpoint_prelude::*;
/// Keys user results may be ordered by.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
......@@ -173,10 +173,7 @@ fn bool_as_str(b: bool) -> &'static str {
}
}
impl<'a, T> SingleQuery<Vec<T>> for Users<'a>
where
T: DeserializeOwned,
{
impl<'a> Endpoint for Users<'a> {
fn method(&self) -> Method {
Method::GET
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment