2 Commits
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
e35b2289ce |
fix(bitable): cross-table recalc + merge_record_values + SSRF tests
Test / backend-test (pull_request) Has been cancelled
Details
Test / frontend-unit (pull_request) Has been cancelled
Details
Test / api-e2e (pull_request) Has been cancelled
Details
Test / frontend-e2e (pull_request) Has been cancelled
Details
Fixes 4 bugs blocking AE1 acceptance scenario (rollup returns 0): 1. Decimal not recognized as numeric: PostgreSQL JSONB returns numbers as Decimal; _evaluate_rollup's isinstance(v, (int,float)) missed them. Added _to_float() helper (also excludes bool, an int subclass). Applied to _evaluate_lookup for JSON serialization safety. 2. add_relation_link clobbers record values: update_record_values does full-replace, so setting the relation field wiped amount/etc. Added merge_record_values (|| operator) and switched all relation link mutations to use it (add + remove + reverse cleanup). 3. enqueue_recalc ON CONFLICT DO NOTHING swallowed re-enqueues: once a task reached 'done', the unique constraint silently dropped new requests for the same (record_id, field_id) — field showed stale data forever. Changed to ON CONFLICT DO UPDATE: reset done/error tasks to pending; leave pending/calculating as-is (no double-process). 4. No cross-table recalc on record update: update_record_values only triggered recalc on the record's own table; rollup on the target table never updated when source values changed. Added _trigger_cross_table_recalc() — finds relation fields on the record's table, triggers recalc on linked target records. Tests: - AE1 acceptance: 3 e2e tests (SUM on insert, update-triggered recalc, AVG aggregation) — all pass against real PG. - Bidirectional relation deletion: verifies _cleanup_reverse_link removes source from target's reverse field. - SSRF guard: 3 tests blocking loopback, private IP, non-HTTP scheme. - Updated test_recalc_deduplication for new ON CONFLICT DO UPDATE semantics (returns existing task, not None). - Fixed test_crash_recovery to use stale_threshold=0 (was always broken with default 600s threshold). |
|
|
|
6d5a34ada2 |
feat(bitable): formula relations v2 — U1-U8 + review fixes
Test / backend-test (pull_request) Has been cancelled
Details
Test / frontend-unit (pull_request) Has been cancelled
Details
Test / api-e2e (pull_request) Has been cancelled
Details
Test / frontend-e2e (pull_request) Has been cancelled
Details
Implements bitable v2: formula engine expansion (10->64 functions),
cross-table formula references, relation CRUD (1:1/1:N/N:N + bidirectional),
lookup/rollup fields, cross-table dependency graph, automation engine
(3 triggers + 5 actions + retry + webhook), and REST API + BitableTool actions.
Implementation units:
- U1: Schema V3 migration (junction table, automations, cross_table_deps)
- U2: Formula functions 10->64 (datetime/text/logical/aggregate/lookup)
- U3: Cross-table formula {rel.target} syntax (parser 3-tuple, engine resolve)
- U4: Relation CRUD + bidirectional + self-reference
- U5: Lookup & Rollup field types with recalc worker routing
- U6: Cross-table dependency graph + recalc trigger
- U7: Automation engine (asyncio queue, 3x retry, execution logs)
- U8: REST API (11 endpoints) + BitableTool (17 actions)
Review fixes applied (ce-code-review mode:agent):
- P1: SSRF guard on outbound webhook (reuse _assert_safe_host from ingestion)
- P1: Bidirectional relation removal now cleans reverse field (symmetric with add)
- P2: Ownership check on target_table_id in relation field creation (IDOR fix)
- P2: Typed AutomationUpdate Pydantic model (prevents table_id injection)
- P3: Tracked automation fire-and-forget tasks (error visibility)
- P3: Public FormulaEngine.get_cross_table_mapping (remove private attr access)
Tests: 267 passed, 153 skipped (PG). Ruff clean.
Deferred: generate_formula/generate_automation LLM actions, frontend components.
|