Archery Range
Migrate archery-range scoring sessions from legacy JSON into Pixeltable, score with date-aware computed columns, and run as an incremental scheduled pipeline
One app.py with 1 table, 13 computed columns. Needs pixeltable>=0.7.16. Updated 2026-10-14.
app.py
"""Archery Lanes scheduled pipeline: migrate legacy JSON sessions, date helpers, alter_computed_column scoring. Tables and @pxt.query live here; UDFs in udfs.py."""from __future__ import annotationsimport pixeltable as pxtimport pixeltable.functions as pxtffrom pixeltable.functions import date as pxtdfrom udfs import archer_tag, boto3_core_probe, score_bandTableModel = pxt.model_base()class Sessions(TableModel, name='sessions', has_default_idxs=False):"""One archery-range scoring session migrated from legacy JSON."""session_id = pxt.Column(value=pxtf.uuid.uuid7(), primary_key=True)session_code: pxt.Stringarcher: pxt.Stringlane: pxt.Intsession_date: pxt.Datearrows: pxt.Inthits: pxt.Intx_rings: pxt.Intnotes: pxt.String# --- fn.date secondary ---session_year = pxtd.year(session_date)session_month = pxtd.month(session_date)session_day = pxtd.day(session_date)session_weekday = pxtd.weekday(session_date) # Mon=0 .. Sun=6session_iso_weekday = pxtd.isoweekday(session_date)session_iso = pxtd.isoformat(session_date)next_practice = pxtd.add_days(session_date, 7)calendar_label = pxtd.strftime(session_date, '%a %b %d, %Y')# --- scoring (v1: hit%; later altered to include X-ring bonus) ---hit_pct = (hits * 100.0) / arrows# Club formula (v2): hit% + 2 per X-ring. pipeline.py alters from v1 hit_pct -> this.score = (hits * 100.0) / arrows + (x_rings * 2.0)band = score_band(hit_pct)tag = archer_tag(archer, lane)boto3_ok = boto3_core_probe()__indexes__ = [pxt.BtreeIndex(archer),pxt.BtreeIndex(lane),pxt.BtreeIndex(session_date),pxt.BtreeIndex(band),pxt.BtreeIndex(session_code),]@pxt.querydef by_archer(archer: str):"""Sessions for one archer, newest first."""return (Sessions.where(Sessions.archer == archer).select(Sessions.session_code,Sessions.session_date,Sessions.lane,Sessions.hit_pct,Sessions.score,Sessions.band,Sessions.calendar_label,Sessions.next_practice,).order_by(Sessions.session_date, asc=False))@pxt.querydef weekend_club(min_pct: float = 70.0):"""Weekend sessions (Sat/Sun) at or above a hit percentage."""return (Sessions.where((Sessions.session_weekday >= 5) & (Sessions.hit_pct >= min_pct)).select(Sessions.session_code,Sessions.archer,Sessions.calendar_label,Sessions.hit_pct,Sessions.score,Sessions.band,Sessions.tag,).order_by(Sessions.hit_pct, asc=False))@pxt.querydef lane_day(lane: int, day_iso: str):"""Sessions on one lane for a given ISO date string (YYYY-MM-DD)."""return (Sessions.where((Sessions.lane == lane) & (Sessions.session_iso == day_iso)).select(Sessions.session_code,Sessions.archer,Sessions.arrows,Sessions.hits,Sessions.score,Sessions.boto3_ok,).order_by(Sessions.session_code))
What app.py declares
Each row links to its line.
- runs on insert
- stored
- index
- route
- session_idsession_codearcherlanesession_datearrowshitsx_ringsnotes
- session_year = pxtd.year(session_date)L29
- session_month = pxtd.month(session_date)L30
- session_day = pxtd.day(session_date)L31
- session_weekday = pxtd.weekday(session_date)L32
- session_iso_weekday = pxtd.isoweekday(session_date)L33
- session_iso = pxtd.isoformat(session_date)L34
- next_practice = pxtd.add_days(session_date, 7)L35
- calendar_label = pxtd.strftime(session_date, '%a %b %d, %Y')L36
- hit_pct = hits * 100.0 / arrowsL39
- score = hits * 100.0 / arrows + x_rings * 2.0L41
- band = score_band(hit_pct)L42
- tag = archer_tag(archer, lane)L43
- boto3_ok = boto3_core_probe()L44
- B-tree index on archerL47
- B-tree index on laneL48
- B-tree index on session_dateL49
- B-tree index on bandL50
- B-tree index on session_codeL51
No HTTP routes: a pipeline you insert into and query from Python.
Run it
Needs uv.
terminal
git clone https://github.com/pierrebrunelle/pixeltable-archery-lanescd pixeltable-archery-lanesuv syncuv run pxt schema update app.py archery
Related apps
- Research Agent MemoryDurable, searchable long-term memory for an AI research assistant: per-user semantic recall, retrieval_udf lookups, tool calling and memory consolidation with custom aggregatesShares: B-tree indexes, UDFs
- Apiary AdvisorRAG + tool-calling beekeeping advisor: custom embedding index, table-as-UDF agent pipeline, expr_udf mite mathShares: B-tree indexes, UDFs
- Orchard Harvest CratesBatch ETL for orchard harvest crates: CSV import/export, packing math, and moisture on_error handlingShares: B-tree indexes, UDFs