-- test/sql/09_balance_cache.sql -- Tests for balance_cache — direct SQL access, edge cases BEGIN; SELECT plan(11); -- Setup SELECT accum.register_create( name := 'bc', dimensions := '{"account": "int", "currency": "text"}', resources := '{"debit": "numeric(18,2)", "credit": "numeric(18,2)", "net": "numeric(18,2)"}', kind := 'balance' ); -- ============================================================ -- TEST: Empty register — no cache rows -- ============================================================ SELECT is( (SELECT count(*)::int FROM accum.bc_balance_cache), 0, 'Empty register should have no cache rows' ); -- ============================================================ -- TEST: First movement creates cache row -- ============================================================ SELECT accum.register_post('bc', '{ "recorder":"t:1","period":"2026-04-18", "account":1001,"currency":"UAH", "debit":0,"credit":5000,"net":-5000 }'); SELECT is( (SELECT count(*)::int FROM accum.bc_balance_cache), 1, 'First movement should create one cache row' ); SELECT is( (SELECT net FROM accum.bc_balance_cache WHERE account=1001 AND currency='UAH'), -5000::numeric, 'Net balance should be -5000' ); -- ============================================================ -- TEST: Counter-movement -- ============================================================ SELECT accum.register_post('bc', '{ "recorder":"t:2","period":"2026-04-18", "account":1001,"currency":"UAH", "debit":3000,"credit":0,"net":3000 }'); SELECT is( (SELECT net FROM accum.bc_balance_cache WHERE account=1001 AND currency='UAH'), -2000::numeric, 'Net should be -5000+3000=-2000' ); -- ============================================================ -- TEST: Multiple currencies — separate cache rows -- ============================================================ SELECT accum.register_post('bc', '{ "recorder":"t:3","period":"2026-04-18", "account":1001,"currency":"USD", "debit":100,"credit":0,"net":100 }'); SELECT is( (SELECT count(*)::int FROM accum.bc_balance_cache WHERE account=1001), 2, 'Different currencies should create separate cache rows' ); -- ============================================================ -- TEST: Direct SQL query on cache table -- ============================================================ SELECT is( (SELECT currency FROM accum.bc_balance_cache WHERE account=1001 AND net > 0), 'USD', 'Direct SQL query should work on cache table' ); -- ============================================================ -- TEST: last_movement_at is updated -- ============================================================ SELECT isnt( (SELECT last_movement_at FROM accum.bc_balance_cache WHERE account=1001 AND currency='UAH'), NULL::timestamptz, 'last_movement_at should be set' ); -- ============================================================ -- TEST: version tracks updates -- ============================================================ SELECT is( (SELECT version FROM accum.bc_balance_cache WHERE account=1001 AND currency='UAH'), 2::bigint, 'Version should be 2 after two movements' ); -- ============================================================ -- TEST: Unpost back to zero -- ============================================================ SELECT accum.register_unpost('bc', 't:1'); SELECT accum.register_unpost('bc', 't:2'); SELECT is( (SELECT net FROM accum.bc_balance_cache WHERE account=1001 AND currency='UAH'), 0::numeric, 'Net should be 0 after unposting all UAH movements' ); -- ============================================================ -- TEST: Cache row persists even at zero balance -- ============================================================ SELECT is( (SELECT count(*)::int FROM accum.bc_balance_cache WHERE account=1001 AND currency='UAH'), 1, 'Cache row should persist even when balance is 0' ); -- ============================================================ -- TEST: Turnover register has no balance_cache -- ============================================================ SELECT accum.register_create( name := 'bc_turnover', dimensions := '{"x": "int"}', resources := '{"y": "numeric"}', kind := 'turnover' ); SELECT hasnt_table('accum', 'bc_turnover_balance_cache', 'Turnover register should not have balance_cache' ); -- Cleanup SELECT accum.register_drop('bc', force := true); SELECT accum.register_drop('bc_turnover'); SELECT * FROM finish(); ROLLBACK;