@@ -22,3 +22,51 @@ def test_materialize_project_joins_and_aggregates() -> None:
2222 assert lead_2 ["interaction_count" ] == 2
2323 assert lead_2 ["channel_count" ] == 2
2424 assert lead_2 ["latest_channel" ] == "meeting"
25+
26+
27+ def test_one_to_many_count_is_zero_for_parents_without_children (tmp_path : Path ) -> None :
28+ import pandas as pd
29+
30+ from auto_bayesian import build_project
31+
32+ parents = pd .DataFrame ({"tender_id" : ["T1" , "T2" , "T3" ], "won" : ["1" , "0" , "0" ]})
33+ children = pd .DataFrame (
34+ {
35+ "bid_id" : ["B1" , "B2" , "B3" ],
36+ "tender_id" : ["T1" , "T1" , "T2" ],
37+ "bidder" : ["a" , "b" , "a" ],
38+ "price" : [0.9 , 1.1 , 0.95 ],
39+ }
40+ )
41+ project = build_project (
42+ root = tmp_path ,
43+ root_table = "tenders" ,
44+ target_column = "won" ,
45+ positive_label = "1" ,
46+ output_dir = tmp_path / "artifacts" ,
47+ tables = [
48+ {"name" : "tenders" , "primary_key" : "tender_id" },
49+ {"name" : "bids" , "primary_key" : "bid_id" },
50+ ],
51+ relations = [
52+ {
53+ "parent" : "tenders" ,
54+ "child" : "bids" ,
55+ "parent_key" : "tender_id" ,
56+ "child_key" : "tender_id" ,
57+ "kind" : "one_to_many" ,
58+ "aggregations" : [
59+ {"op" : "count" , "name" : "bid_count" },
60+ {"column" : "bidder" , "op" : "nunique" , "name" : "bidder_count" },
61+ {"column" : "price" , "op" : "mean" , "name" : "mean_price" },
62+ ],
63+ }
64+ ],
65+ )
66+ frame = materialize_project (project , tables = {"tenders" : parents , "bids" : children })
67+ childless = frame .loc [frame ["tender_id" ] == "T3" ].iloc [0 ]
68+
69+ assert childless ["bid_count" ] == 0
70+ assert childless ["bidder_count" ] == 0
71+ assert pd .isna (childless ["mean_price" ])
72+ assert frame .loc [frame ["tender_id" ] == "T1" ].iloc [0 ]["bid_count" ] == 2
0 commit comments