Skip to main content

Batches

Struct Batches 

Source
pub struct Batches<T> { /* private fields */ }
Expand description

Batches of rows by increasing id, from Query::batches: Rails’ find_in_batches without holding a cursor open.

next runs one query and returns the next batch, or None when every row was read. after is the last id seen: store it (in a job’s arguments, in KV) to resume later with resume_after.

§Examples

use ocre::{Ctx, Query, Result};

#[derive(serde::Deserialize)]
struct User {
    id: i64,
    email: String,
}

// A scheduled task: at most 4 batches (4 queries) per run.
async fn send_digests(ctx: &Ctx, resume: Option<i64>) -> Result<Option<i64>> {
    let db = ctx.db()?;
    let mut batches = Query::<User>::table("users").batches(100, |user| user.id).resume_after(resume);
    for _ in 0..4 {
        let Some(users) = batches.next(&db).await? else { return Ok(None) };
        for user in users {
            // find_each: one row at a time.
            let _ = user.email;
        }
    }
    Ok(batches.after())
}

Implementations§

Source§

impl<T> Batches<T>

Source

pub fn resume_after(self, id: Option<i64>) -> Self

Starts after id (Rails’ start:, exclusive), or from the first row with None.

§Examples
let batches = ocre::Query::<Post>::table("posts").batches(100, |p| p.id).resume_after(Some(41));
assert_eq!(batches.after(), Some(41));
assert!(batches.statement().sql.contains("posts.id > ?1"));
Source

pub fn after(&self) -> Option<i64>

The last id read so far (None before the first batch).

§Examples
assert_eq!(ocre::Query::<Post>::table("posts").batches(10, |p| p.id).after(), None);
Source

pub fn is_done(&self) -> bool

Whether the last batch was shorter than the batch size: no row is left.

§Examples
let mut batches = ocre::Query::<Post>::table("posts").batches(2, |p| p.id);
batches.advance(&[Post { id: 1 }]);
assert!(batches.is_done());
Source

pub fn statement(&self) -> Statement

The SELECT of the next batch.

§Examples
let batches = ocre::Query::<Post>::table("posts").limit(3).batches(10, |p| p.id);
assert_eq!(batches.statement().sql, "SELECT * FROM posts ORDER BY posts.id ASC LIMIT ?1");
Source

pub fn advance(&mut self, rows: &[T])

Records a batch just read: its last id, and whether it was the last batch.

next calls it; call it yourself after running statement through Db::all.

§Examples
let mut batches = ocre::Query::<Post>::table("posts").batches(2, |p| p.id);
batches.advance(&[Post { id: 3 }, Post { id: 5 }]);
assert_eq!((batches.after(), batches.is_done()), (Some(5), false));
Source§

impl<T: DeserializeOwned> Batches<T>

Source

pub async fn next(&mut self, db: &Db) -> Result<Option<Vec<T>>>

Runs the next batch: up to the batch size of rows after the last id read, or None once every row was read.

See Query::batches.

§Errors

Error::Internal (500) when D1 rejects the statement or a row does not deserialize into T.

§Free plan

One query reading at most the batch size of rows (plus the rows the conditions skip without an index).

§Examples
use ocre::{Ctx, Query, Result};

#[derive(serde::Deserialize)]
struct Post {
    id: i64,
}

async fn count_by_hand(ctx: &Ctx) -> Result<usize> {
    let db = ctx.db()?;
    let mut batches = Query::<Post>::table("posts").batches(500, |post| post.id);
    let mut total = 0;
    while let Some(posts) = batches.next(&db).await? {
        total += posts.len();
    }
    Ok(total)
}

Auto Trait Implementations§

§

impl<T> Freeze for Batches<T>

§

impl<T> RefUnwindSafe for Batches<T>

§

impl<T> Send for Batches<T>

§

impl<T> Sync for Batches<T>

§

impl<T> Unpin for Batches<T>

§

impl<T> UnsafeUnpin for Batches<T>

§

impl<T> UnwindSafe for Batches<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<S, T> Upcast<T> for S
where T: UpcastFrom<S> + ?Sized, S: ?Sized,

Source§

fn upcast(&self) -> &T
where Self: ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider ref type within the Wasm bindgen generics type system. Read more
Source§

fn upcast_into(self) -> T
where Self: Sized + ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider type within the Wasm bindgen generics type system. Read more
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V