diff options
Diffstat (limited to 'src/channel')
| -rw-r--r-- | src/channel/app.rs | 48 | ||||
| -rw-r--r-- | src/channel/history.rs | 8 | ||||
| -rw-r--r-- | src/channel/repo.rs | 4 | ||||
| -rw-r--r-- | src/channel/routes.rs | 89 | ||||
| -rw-r--r-- | src/channel/routes/test/list.rs | 65 | ||||
| -rw-r--r-- | src/channel/routes/test/mod.rs | 1 | ||||
| -rw-r--r-- | src/channel/routes/test/on_create.rs | 7 |
7 files changed, 17 insertions, 205 deletions
diff --git a/src/channel/app.rs b/src/channel/app.rs index 1b2cc48..a9a9e84 100644 --- a/src/channel/app.rs +++ b/src/channel/app.rs @@ -7,7 +7,7 @@ use crate::{ clock::DateTime, db::NotFound, event::{broadcaster::Broadcaster, repo::Provider as _, Event, Sequence}, - message::{repo::Provider as _, Message}, + message::repo::Provider as _, }; pub struct Channels<'a> { @@ -36,52 +36,6 @@ impl<'a> Channels<'a> { Ok(channel.as_created()) } - pub async fn all(&self, resume_point: Option<Sequence>) -> Result<Vec<Channel>, InternalError> { - let mut tx = self.db.begin().await?; - let channels = tx.channels().all(resume_point).await?; - tx.commit().await?; - - let channels = channels - .into_iter() - .filter_map(|channel| { - channel - .events() - .filter(Sequence::up_to(resume_point)) - .collect() - }) - .collect(); - - Ok(channels) - } - - pub async fn messages( - &self, - channel: &Id, - resume_point: Option<Sequence>, - ) -> Result<Vec<Message>, Error> { - let mut tx = self.db.begin().await?; - let channel = tx - .channels() - .by_id(channel) - .await - .not_found(|| Error::NotFound(channel.clone()))?; - - let messages = tx - .messages() - .in_channel(&channel, resume_point) - .await? - .into_iter() - .filter_map(|message| { - message - .events() - .filter(Sequence::up_to(resume_point)) - .collect() - }) - .collect(); - - Ok(messages) - } - pub async fn delete(&self, channel: &Id, deleted_at: &DateTime) -> Result<(), Error> { let mut tx = self.db.begin().await?; diff --git a/src/channel/history.rs b/src/channel/history.rs index bd45d8d..383fb7b 100644 --- a/src/channel/history.rs +++ b/src/channel/history.rs @@ -2,7 +2,7 @@ use super::{ event::{Created, Deleted, Event}, Channel, Id, }; -use crate::event::Instant; +use crate::event::{Instant, ResumePoint, Sequence}; #[derive(Clone, Debug, Eq, PartialEq)] pub struct History { @@ -25,6 +25,12 @@ impl History { pub fn as_created(&self) -> Channel { self.channel.clone() } + + pub fn as_of(&self, resume_point: impl Into<ResumePoint>) -> Option<Channel> { + self.events() + .filter(Sequence::up_to(resume_point.into())) + .collect() + } } // Event factories diff --git a/src/channel/repo.rs b/src/channel/repo.rs index 2b48436..2f57581 100644 --- a/src/channel/repo.rs +++ b/src/channel/repo.rs @@ -3,7 +3,7 @@ use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; use crate::{ channel::{Channel, History, Id}, clock::DateTime, - event::{Instant, Sequence}, + event::{Instant, ResumePoint, Sequence}, }; pub trait Provider { @@ -84,7 +84,7 @@ impl<'c> Channels<'c> { Ok(channel) } - pub async fn all(&mut self, resume_at: Option<Sequence>) -> Result<Vec<History>, sqlx::Error> { + pub async fn all(&mut self, resume_at: ResumePoint) -> Result<Vec<History>, sqlx::Error> { let channels = sqlx::query!( r#" select diff --git a/src/channel/routes.rs b/src/channel/routes.rs index 23c0602..5d67af8 100644 --- a/src/channel/routes.rs +++ b/src/channel/routes.rs @@ -2,56 +2,21 @@ use axum::{ extract::{Json, Path, State}, http::StatusCode, response::{IntoResponse, Response}, - routing::{delete, get, post}, + routing::{delete, post}, Router, }; -use axum_extra::extract::Query; use super::{app, Channel, Id}; -use crate::{ - app::App, - clock::RequestedAt, - error::Internal, - event::{Instant, Sequence}, - login::Login, - message::{self, app::SendError}, -}; +use crate::{app::App, clock::RequestedAt, error::Internal, login::Login, message::app::SendError}; #[cfg(test)] mod test; pub fn router() -> Router<App> { Router::new() - .route("/api/channels", get(list)) .route("/api/channels", post(on_create)) .route("/api/channels/:channel", post(on_send)) .route("/api/channels/:channel", delete(on_delete)) - .route("/api/channels/:channel/messages", get(messages)) -} - -#[derive(Default, serde::Deserialize)] -struct ResumeQuery { - resume_point: Option<Sequence>, -} - -async fn list( - State(app): State<App>, - _: Login, - Query(query): Query<ResumeQuery>, -) -> Result<Channels, Internal> { - let channels = app.channels().all(query.resume_point).await?; - let response = Channels(channels); - - Ok(response) -} - -struct Channels(Vec<Channel>); - -impl IntoResponse for Channels { - fn into_response(self) -> Response { - let Self(channels) = self; - Json(channels).into_response() - } } #[derive(Clone, serde::Deserialize)] @@ -150,53 +115,3 @@ impl IntoResponse for ErrorResponse { } } } - -async fn messages( - State(app): State<App>, - Path(channel): Path<Id>, - _: Login, - Query(query): Query<ResumeQuery>, -) -> Result<Messages, ErrorResponse> { - let messages = app - .channels() - .messages(&channel, query.resume_point) - .await?; - let response = Messages( - messages - .into_iter() - .map(|message| MessageView { - sent: message.sent, - sender: message.sender, - message: MessageInner { - id: message.id, - body: message.body, - }, - }) - .collect(), - ); - - Ok(response) -} - -struct Messages(Vec<MessageView>); - -#[derive(serde::Serialize)] -struct MessageView { - #[serde(flatten)] - sent: Instant, - sender: Login, - message: MessageInner, -} - -#[derive(serde::Serialize)] -struct MessageInner { - id: message::Id, - body: String, -} - -impl IntoResponse for Messages { - fn into_response(self) -> Response { - let Self(messages) = self; - Json(messages).into_response() - } -} diff --git a/src/channel/routes/test/list.rs b/src/channel/routes/test/list.rs deleted file mode 100644 index f15a53c..0000000 --- a/src/channel/routes/test/list.rs +++ /dev/null @@ -1,65 +0,0 @@ -use axum::extract::State; -use axum_extra::extract::Query; - -use crate::{channel::routes, test::fixtures}; - -#[tokio::test] -async fn empty_list() { - // Set up the environment - - let app = fixtures::scratch_app().await; - let viewer = fixtures::login::create(&app).await; - - // Call the endpoint - - let routes::Channels(channels) = routes::list(State(app), viewer, Query::default()) - .await - .expect("always succeeds"); - - // Verify the semantics - - assert!(channels.is_empty()); -} - -#[tokio::test] -async fn one_channel() { - // Set up the environment - - let app = fixtures::scratch_app().await; - let viewer = fixtures::login::create(&app).await; - let channel = fixtures::channel::create(&app, &fixtures::now()).await; - - // Call the endpoint - - let routes::Channels(channels) = routes::list(State(app), viewer, Query::default()) - .await - .expect("always succeeds"); - - // Verify the semantics - - assert!(channels.contains(&channel)); -} - -#[tokio::test] -async fn multiple_channels() { - // Set up the environment - - let app = fixtures::scratch_app().await; - let viewer = fixtures::login::create(&app).await; - let channels = vec![ - fixtures::channel::create(&app, &fixtures::now()).await, - fixtures::channel::create(&app, &fixtures::now()).await, - ]; - - // Call the endpoint - - let routes::Channels(response_channels) = routes::list(State(app), viewer, Query::default()) - .await - .expect("always succeeds"); - - // Verify the semantics - - assert!(channels - .into_iter() - .all(|channel| response_channels.contains(&channel))); -} diff --git a/src/channel/routes/test/mod.rs b/src/channel/routes/test/mod.rs index ab663eb..3e5aa17 100644 --- a/src/channel/routes/test/mod.rs +++ b/src/channel/routes/test/mod.rs @@ -1,3 +1,2 @@ -mod list; mod on_create; mod on_send; diff --git a/src/channel/routes/test/on_create.rs b/src/channel/routes/test/on_create.rs index 5733c9e..ed49017 100644 --- a/src/channel/routes/test/on_create.rs +++ b/src/channel/routes/test/on_create.rs @@ -33,8 +33,11 @@ async fn new_channel() { // Verify the semantics - let channels = app.channels().all(None).await.expect("always succeeds"); - assert!(channels.contains(&response_channel)); + let snapshot = app.boot().snapshot().await.expect("boot always succeeds"); + assert!(snapshot + .channels + .iter() + .any(|channel| channel.name == response_channel.name && channel.id == response_channel.id)); let mut events = app .events() |
