You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-11-20 12:02:22 +03:00
Split the storage trait from the implementation
This commit is contained in:
@@ -14,10 +14,8 @@
|
||||
|
||||
//! Utilities to manage paginated queries.
|
||||
|
||||
use sqlx::{Database, QueryBuilder};
|
||||
use thiserror::Error;
|
||||
use ulid::Ulid;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// An error returned when invalid pagination parameters are provided
|
||||
#[derive(Debug, Error)]
|
||||
@@ -26,14 +24,14 @@ pub struct InvalidPagination;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Pagination {
|
||||
before: Option<Ulid>,
|
||||
after: Option<Ulid>,
|
||||
count: usize,
|
||||
direction: PaginationDirection,
|
||||
pub before: Option<Ulid>,
|
||||
pub after: Option<Ulid>,
|
||||
pub count: usize,
|
||||
pub direction: PaginationDirection,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum PaginationDirection {
|
||||
pub enum PaginationDirection {
|
||||
Forward,
|
||||
Backward,
|
||||
}
|
||||
@@ -101,60 +99,8 @@ impl Pagination {
|
||||
self
|
||||
}
|
||||
|
||||
/// Add cursor-based pagination to a query, as used in paginated GraphQL
|
||||
/// connections
|
||||
fn generate_pagination<'a, DB>(&self, query: &mut QueryBuilder<'a, DB>, id_field: &'static str)
|
||||
where
|
||||
DB: Database,
|
||||
Uuid: sqlx::Type<DB> + sqlx::Encode<'a, DB>,
|
||||
i64: sqlx::Type<DB> + sqlx::Encode<'a, DB>,
|
||||
{
|
||||
// ref: https://github.com/graphql/graphql-relay-js/issues/94#issuecomment-232410564
|
||||
// 1. Start from the greedy query: SELECT * FROM table
|
||||
|
||||
// 2. If the after argument is provided, add `id > parsed_cursor` to the `WHERE`
|
||||
// clause
|
||||
if let Some(after) = self.after {
|
||||
query
|
||||
.push(" AND ")
|
||||
.push(id_field)
|
||||
.push(" > ")
|
||||
.push_bind(Uuid::from(after));
|
||||
}
|
||||
|
||||
// 3. If the before argument is provided, add `id < parsed_cursor` to the
|
||||
// `WHERE` clause
|
||||
if let Some(before) = self.before {
|
||||
query
|
||||
.push(" AND ")
|
||||
.push(id_field)
|
||||
.push(" < ")
|
||||
.push_bind(Uuid::from(before));
|
||||
}
|
||||
|
||||
match self.direction {
|
||||
// 4. If the first argument is provided, add `ORDER BY id ASC LIMIT first+1` to the
|
||||
// query
|
||||
PaginationDirection::Forward => {
|
||||
query
|
||||
.push(" ORDER BY ")
|
||||
.push(id_field)
|
||||
.push(" ASC LIMIT ")
|
||||
.push_bind((self.count + 1) as i64);
|
||||
}
|
||||
// 5. If the first argument is provided, add `ORDER BY id DESC LIMIT last+1` to the
|
||||
// query
|
||||
PaginationDirection::Backward => {
|
||||
query
|
||||
.push(" ORDER BY ")
|
||||
.push(id_field)
|
||||
.push(" DESC LIMIT ")
|
||||
.push_bind((self.count + 1) as i64);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Process a page returned by a paginated query
|
||||
#[must_use]
|
||||
pub fn process<T>(&self, mut edges: Vec<T>) -> Page<T> {
|
||||
let is_full = edges.len() == (self.count + 1);
|
||||
if is_full {
|
||||
@@ -198,7 +144,6 @@ impl<T> Page<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn try_map<F, E, T2>(self, f: F) -> Result<Page<T2>, E>
|
||||
where
|
||||
F: FnMut(T) -> Result<T2, E>,
|
||||
@@ -211,23 +156,3 @@ impl<T> Page<T> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An extension trait to the `sqlx` [`QueryBuilder`], to help adding pagination
|
||||
/// to a query
|
||||
pub trait QueryBuilderExt {
|
||||
/// Add cursor-based pagination to a query, as used in paginated GraphQL
|
||||
/// connections
|
||||
fn generate_pagination(&mut self, id_field: &'static str, pagination: Pagination) -> &mut Self;
|
||||
}
|
||||
|
||||
impl<'a, DB> QueryBuilderExt for QueryBuilder<'a, DB>
|
||||
where
|
||||
DB: Database,
|
||||
Uuid: sqlx::Type<DB> + sqlx::Encode<'a, DB>,
|
||||
i64: sqlx::Type<DB> + sqlx::Encode<'a, DB>,
|
||||
{
|
||||
fn generate_pagination(&mut self, id_field: &'static str, pagination: Pagination) -> &mut Self {
|
||||
pagination.generate_pagination(self, id_field);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user