pub fn fragments<'a, I, T, K, F>(
ctx: &Ctx,
items: &'a [I],
ttl: Duration,
key: K,
build: F,
) -> impl Future<Output = Result<Vec<Fragment>>> + Send + use<'a, I, T, K, F>Expand description
Collection caching, like Rails’ render collection:, cached: true: one Fragment per item, read from KV in bulk.
key gives each item’s cache key (see cache::key);
all keys are read with KV bulk reads (up to 100 keys per read, one
subrequest each), then only the missing items are rendered with build
and stored, one KV write each. The fragments come back in the order of
items. Everything else works as in fragment.
Free plan: KV bills a bulk read as one read per key (100,000 a day) and each miss as one write (1,000 a day): a list of 20 posts costs 20 reads per view, and up to 20 writes after the posts change.
§Errors
Error::Internal(500) when theCACHEbinding is missing, naming the fix:ocre g cacheaddsCACHE: bindings.kv(),to cloudflare.config.ts.Error::Internalwhen a KV key is longer than 512 bytes orttlis below 60 seconds.Error::Internalwhen a template fails to render.
§Examples
use std::time::Duration;
use askama::Template;
use axum::{extract::State, response::Html};
use ocre::{Ctx, Result, cache::{self, Fragment}, render};
struct Post { id: i64, title: String, updated_at: String }
#[derive(Template)]
#[template(source = "<li>{{ post.title }}</li>", ext = "html")]
struct Row<'a> { post: &'a Post }
#[derive(Template)]
#[template(source = "<ul>{% for row in rows %}{{ row }}{% endfor %}</ul>", ext = "html")]
struct Index { rows: Vec<Fragment> }
async fn index(State(ctx): State<Ctx>) -> Result<Html<String>> {
let posts: Vec<Post> = Vec::new(); // e.g. post::all(&ctx, page).await?
let rows = cache::fragments(
&ctx,
&posts,
Duration::from_secs(86_400),
|post| cache::key(&[&"posts", &post.id, &post.updated_at, &"row-v1"]),
|post| Row { post },
)
.await?;
render(&Index { rows })
}