use super::{BuiltIn, SqlWriter};
use crate::role::Role;
use crate::spec::TableSpec;
#[cfg(any(feature = "postgres", feature = "mysql"))]
use crate::statement::ClaimShape;
use crate::statement::Param;
pub(super) const ORDER_KEYS: [Role; 2] = [Role::Priority, Role::RetryAfter];
#[derive(Debug, Clone, Copy)]
pub(super) enum Condition {
InGroup,
Due,
Unfinished,
Free,
}
impl Condition {
fn role(self) -> Role {
match self {
Self::InGroup => Role::Group,
Self::Due => Role::RetryAfter,
Self::Unfinished => Role::ProcessedAt,
Self::Free => Role::LockedUntil,
}
}
}
pub(super) const CLAIMABLE: [Condition; 4] = [
Condition::InGroup,
Condition::Due,
Condition::Unfinished,
Condition::Free,
];
impl<D> SqlWriter<'_, D>
where
D: BuiltIn + ?Sized,
{
pub(crate) fn claimable(&mut self, spec: &TableSpec<'_>) -> &mut Self {
self.conditions(spec, &CLAIMABLE, " WHERE ")
}
pub(super) fn conditions(
&mut self,
spec: &TableSpec<'_>,
conditions: &[Condition],
keyword: &'static str,
) -> &mut Self {
self.conditions_then(spec, conditions, keyword);
self
}
pub(super) fn conditions_then(
&mut self,
spec: &TableSpec<'_>,
conditions: &[Condition],
keyword: &'static str,
) -> &'static str {
let mut keyword = keyword;
for &condition in conditions {
let Some(column) = spec.column(condition.role()) else {
continue;
};
self.push(keyword);
keyword = " AND ";
match condition {
Condition::InGroup => self.ident(column.name()).push(" = ").param(Param::Group),
Condition::Due => self.ident(column.name()).push(" <= ").now(spec),
Condition::Unfinished => self.ident(column.name()).push(" IS NULL"),
Condition::Free => self.lease_free(column.name()),
};
}
keyword
}
pub(crate) fn claim_order(&mut self, spec: &TableSpec<'_>, id: &str) -> &mut Self {
self.push(" ORDER BY ");
for column in ORDER_KEYS.iter().filter_map(|&role| spec.column(role)) {
self.ident(column.name()).push(", ");
}
self.ident(id)
}
pub(super) fn claimed_rows(&mut self, spec: &TableSpec<'_>, lock: &str) -> &mut Self {
let id = spec.id().name();
self.push(" FROM ").table(spec);
if spec.is_fifo() {
self.push(" WHERE ")
.ident(id)
.push(" = (SELECT ")
.ident(id)
.push(" FROM ")
.table(spec)
.head_conditions(spec)
.claim_order(spec, id)
.push(" LIMIT 1)")
.taking_conditions(spec)
.group_free(spec);
} else {
self.claimable(spec)
.claim_order(spec, id)
.push(" LIMIT ")
.param(Param::Limit);
}
self.push(lock)
}
#[cfg(any(feature = "postgres", feature = "mysql"))]
pub(crate) fn claim(
&mut self,
spec: &TableSpec<'_>,
shape: ClaimShape,
lock: &str,
) -> &mut Self {
self.push("SELECT ")
.claimed_columns(spec, shape)
.claimed_rows(spec, lock)
}
}