Skip to content

Commit 1328f4b

Browse files
committed
add an indirection around RenderContext
This should make it easier to render other things than html in the future
1 parent e20f641 commit 1328f4b

File tree

3 files changed

+57
-15
lines changed

3 files changed

+57
-15
lines changed

src/render.rs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub enum PageContext<W: std::io::Write> {
2222
/// Indicates that we should start rendering the body
2323
Body {
2424
http_response: HttpResponseBuilder,
25-
renderer: RenderContext<W>,
25+
renderer: AnyRenderBodyContext<W>,
2626
},
2727

2828
/// The response is ready, and should be sent as is. No further statements should be executed
@@ -232,9 +232,11 @@ impl<'a, W: std::io::Write> HeaderContext<W> {
232232
}
233233

234234
async fn start_body(self, data: JsonValue) -> anyhow::Result<PageContext<W>> {
235-
let renderer = RenderContext::new(self.app_state, self.request_context, self.writer, data)
236-
.await
237-
.with_context(|| "Failed to create a render context from the header context.")?;
235+
let html_renderer =
236+
HtmlRenderContext::new(self.app_state, self.request_context, self.writer, data)
237+
.await
238+
.with_context(|| "Failed to create a render context from the header context.")?;
239+
let renderer = AnyRenderBodyContext::Html(html_renderer);
238240
let http_response = self.response;
239241
Ok(PageContext::Body {
240242
renderer,
@@ -283,8 +285,48 @@ fn take_object_str(json: &mut JsonValue, key: &str) -> Option<String> {
283285
}
284286
}
285287

288+
/**
289+
* Can receive rows, and write them in a given format to an `io::Write`
290+
*/
291+
pub enum AnyRenderBodyContext<W: std::io::Write> {
292+
Html(HtmlRenderContext<W>),
293+
}
294+
295+
/**
296+
* Dummy impl to dispatch method calls to the underlying renderer
297+
*/
298+
impl<W: std::io::Write> AnyRenderBodyContext<W> {
299+
pub async fn handle_row(&mut self, data: &JsonValue) -> anyhow::Result<()> {
300+
match self {
301+
AnyRenderBodyContext::Html(render_context) => render_context.handle_row(data).await,
302+
}
303+
}
304+
pub async fn handle_error(&mut self, error: &anyhow::Error) -> anyhow::Result<()> {
305+
match self {
306+
AnyRenderBodyContext::Html(render_context) => render_context.handle_error(error).await,
307+
}
308+
}
309+
pub async fn finish_query(&mut self) -> anyhow::Result<()> {
310+
match self {
311+
AnyRenderBodyContext::Html(render_context) => render_context.finish_query().await,
312+
}
313+
}
314+
315+
pub fn writer_mut(&mut self) -> &mut W {
316+
match self {
317+
AnyRenderBodyContext::Html(HtmlRenderContext { writer, .. }) => writer,
318+
}
319+
}
320+
321+
pub async fn close(self) -> W {
322+
match self {
323+
AnyRenderBodyContext::Html(render_context) => render_context.close().await,
324+
}
325+
}
326+
}
327+
286328
#[allow(clippy::module_name_repetitions)]
287-
pub struct RenderContext<W: std::io::Write> {
329+
pub struct HtmlRenderContext<W: std::io::Write> {
288330
app_state: Arc<AppState>,
289331
pub writer: W,
290332
current_component: Option<SplitTemplateRenderer>,
@@ -297,13 +339,13 @@ const DEFAULT_COMPONENT: &str = "table";
297339
const PAGE_SHELL_COMPONENT: &str = "shell";
298340
const FRAGMENT_SHELL_COMPONENT: &str = "shell-empty";
299341

300-
impl<W: std::io::Write> RenderContext<W> {
342+
impl<W: std::io::Write> HtmlRenderContext<W> {
301343
pub async fn new(
302344
app_state: Arc<AppState>,
303345
request_context: RequestContext,
304346
mut writer: W,
305347
initial_row: JsonValue,
306-
) -> anyhow::Result<RenderContext<W>> {
348+
) -> anyhow::Result<HtmlRenderContext<W>> {
307349
log::debug!("Creating the shell component for the page");
308350

309351
let mut initial_rows = vec![Cow::Borrowed(&initial_row)];
@@ -340,7 +382,7 @@ impl<W: std::io::Write> RenderContext<W> {
340382
log::debug!("Rendering the shell with properties: {shell_row}");
341383
shell_renderer.render_start(&mut writer, shell_row)?;
342384

343-
let mut initial_context = RenderContext {
385+
let mut initial_context = HtmlRenderContext {
344386
app_state,
345387
writer,
346388
current_component: None,

src/webserver/database/sql.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,7 +1198,7 @@ mod test {
11981198

11991199
#[test]
12001200
fn test_extract_json_columns() {
1201-
let sql = r#"
1201+
let sql = r"
12021202
WITH json_cte AS (
12031203
SELECT json_build_object('a', x, 'b', y) AS cte_json
12041204
FROM generate_series(1, 3) x
@@ -1220,7 +1220,7 @@ mod test {
12201220
FROM some_table
12211221
CROSS JOIN json_cte
12221222
WHERE json_typeof(json_col1) = 'object'
1223-
"#;
1223+
";
12241224

12251225
let stmt = parse_postgres_stmt(sql);
12261226
let json_columns = extract_json_columns(&stmt, AnyKind::Sqlite);

src/webserver/http.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::render::{HeaderContext, PageContext, RenderContext};
1+
use crate::render::{AnyRenderBodyContext, HeaderContext, PageContext};
22
use crate::webserver::content_security_policy::ContentSecurityPolicy;
33
use crate::webserver::database::execute_queries::stop_at_first_error;
44
use crate::webserver::database::{execute_queries::stream_query_results_with_conn, DbItem};
@@ -126,11 +126,11 @@ impl Drop for ResponseWriter {
126126

127127
async fn stream_response(
128128
stream: impl Stream<Item = DbItem>,
129-
mut renderer: RenderContext<ResponseWriter>,
129+
mut renderer: AnyRenderBodyContext<ResponseWriter>,
130130
) {
131131
let mut stream = Box::pin(stream);
132132

133-
if let Err(e) = &renderer.writer.async_flush().await {
133+
if let Err(e) = &renderer.writer_mut().async_flush().await {
134134
log::error!("Unable to flush initial data to client: {e}");
135135
return;
136136
}
@@ -157,7 +157,7 @@ async fn stream_response(
157157
return;
158158
}
159159
}
160-
if let Err(e) = &renderer.writer.async_flush().await {
160+
if let Err(e) = &renderer.writer_mut().async_flush().await {
161161
log::error!(
162162
"Stopping rendering early because we were unable to flush data to client: {e:#}"
163163
);
@@ -228,7 +228,7 @@ async fn build_response_header_and_stream<S: Stream<Item = DbItem>>(
228228
enum ResponseWithWriter<S> {
229229
RenderStream {
230230
http_response: HttpResponse,
231-
renderer: RenderContext<ResponseWriter>,
231+
renderer: AnyRenderBodyContext<ResponseWriter>,
232232
database_entries_stream: Pin<Box<S>>,
233233
},
234234
FinishedResponse {

0 commit comments

Comments
 (0)