Skip to main content

backbone_pos/infrastructure/persistence/
pos_table_repository_custom.rs

1//! Hand-written PosTable reads (user-owned, never regenerated) — the custom methods on
2//! [`PosTableRepository`]. Sibling to the generated newtype file, per the module's custom-code
3//! convention. Holds the SQL per the 4-layer rule: services orchestrate, repositories hold SQL.
4//!
5//! The dining table is a UI-affordance record (geometry, seats); the write path cares about its
6//! IDENTITY only — that a ticket seating itself at a table names a table that exists in the
7//! caller's scope. Geometry is deliberately not read here.
8
9use sqlx::Row;
10use uuid::Uuid;
11
12use crate::infrastructure::persistence::PosTableRepository;
13
14/// A dining table as the ticket write path validates it: identity + the floor it belongs to (so a
15/// caller can scope a register's seating by floor if it chooses).
16pub struct TableRow {
17    pub id: Uuid,
18    pub pos_floor_plan_id: Uuid,
19    pub name: Option<String>,
20}
21
22impl PosTableRepository {
23    /// Read one dining table by id, on the CALLER'S scope-relayed transaction (the seating guard
24    /// runs inside the ring/sync unit of work). `Ok(None)` = no such table visible to the caller's
25    /// scope — the fence is the whole guard (ADR-0029).
26    pub async fn fetch_table(
27        &self,
28        conn: &mut sqlx::PgConnection,
29        pos_table_id: Uuid,
30    ) -> Result<Option<TableRow>, sqlx::Error> {
31        let row = sqlx::query(
32            r#"SELECT id, pos_floor_plan_id, name
33               FROM pos.pos_tables
34               WHERE id=$1 AND (metadata->>'deleted_at') IS NULL"#,
35        )
36        .bind(pos_table_id)
37        .fetch_optional(conn)
38        .await?;
39        Ok(row.map(|r| TableRow {
40            id: r.get("id"),
41            pos_floor_plan_id: r.get("pos_floor_plan_id"),
42            name: r.get("name"),
43        }))
44    }
45}