Skip to content

Commit 14dd089

Browse files
authored
fix: count linked array primary fields (baserow#5279)
* fix: count linked array primary fields * address copilot feedback
1 parent 08abafb commit 14dd089

3 files changed

Lines changed: 124 additions & 2 deletions

File tree

backend/src/baserow/contrib/database/formula/ast/function_defs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2423,10 +2423,10 @@ def type_function(
24232423
func_call: BaserowFunctionCall[UnTyped],
24242424
arg: BaserowExpression[BaserowFormulaValidType],
24252425
) -> BaserowExpression[BaserowFormulaType]:
2426-
if BaserowGetFileCount().can_accept_arg(arg):
2426+
if BaserowGetFileCount().can_accept_arg(arg) and not arg.many:
24272427
return BaserowGetFileCount()(arg)
24282428

2429-
if isinstance(arg.expression_type, BaserowFormulaArrayType):
2429+
if isinstance(arg.expression_type, BaserowFormulaArrayType) and not arg.many:
24302430
return BaserowArrayLength()(arg)
24312431

24322432
return arg.expression_type.count(func_call, arg).with_valid_type(

backend/tests/baserow/contrib/database/field/test_formula_field_type.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2340,3 +2340,116 @@ def test_count_formula_for_link_row_field_with_null_values(data_fixture):
23402340
)
23412341

23422342
assert getattr(row_a, formula_field.db_column) == 3
2343+
2344+
2345+
@pytest.mark.django_db
2346+
def test_count_formula_for_link_row_field_with_array_primary_field(data_fixture):
2347+
"""
2348+
A links to B, and B's primary field is a lookup array through a B to C link.
2349+
count(field('<link field>')) must count linked B rows, not each B row's inner
2350+
primary lookup array length (github issue #5276)
2351+
"""
2352+
2353+
user = data_fixture.create_user()
2354+
2355+
table_a, table_b, link_a_to_b = data_fixture.create_two_linked_tables(user=user)
2356+
table_b_primary = table_b.field_set.get(primary=True)
2357+
table_b_primary.primary = False
2358+
table_b_primary.save()
2359+
2360+
table_c = data_fixture.create_database_table(user=user)
2361+
primary_c = data_fixture.create_text_field(
2362+
table=table_c, name="Field C", primary=True
2363+
)
2364+
link_b_to_c = data_fixture.create_link_row_field(
2365+
table=table_b,
2366+
link_row_table=table_c,
2367+
name="Link C",
2368+
)
2369+
data_fixture.create_formula_field(
2370+
table=table_b,
2371+
name="Primary lookup",
2372+
primary=True,
2373+
formula=f"lookup('{link_b_to_c.name}', '{primary_c.name}')",
2374+
)
2375+
count_formula = data_fixture.create_formula_field(
2376+
table=table_a,
2377+
name="Count",
2378+
formula=f"count(field('{link_a_to_b.name}'))",
2379+
)
2380+
2381+
row_handler = RowHandler()
2382+
rows_c = row_handler.force_create_rows(
2383+
user=user,
2384+
table=table_c,
2385+
rows_values=[{primary_c.db_column: "C1"}, {primary_c.db_column: "C2"}],
2386+
model=table_c.get_model(),
2387+
).created_rows
2388+
rows_b = row_handler.force_create_rows(
2389+
user=user,
2390+
table=table_b,
2391+
rows_values=[
2392+
{link_b_to_c.db_column: [rows_c[0].id]},
2393+
{link_b_to_c.db_column: [rows_c[1].id]},
2394+
],
2395+
model=table_b.get_model(),
2396+
).created_rows
2397+
row_a = row_handler.force_create_rows(
2398+
user=user,
2399+
table=table_a,
2400+
rows_values=[{link_a_to_b.db_column: [row.id for row in rows_b]}],
2401+
model=table_a.get_model(),
2402+
).created_rows[0]
2403+
2404+
assert getattr(row_a, count_formula.db_column) == 2
2405+
2406+
2407+
@pytest.mark.django_db
2408+
def test_count_formula_for_link_row_field_with_file_primary_field(data_fixture):
2409+
"""
2410+
A links to B, and B's primary field is a file field. count(field('<link field>'))
2411+
must count linked B rows, not each B row's primary file count.
2412+
"""
2413+
2414+
user = data_fixture.create_user()
2415+
2416+
table_a, table_b, link_a_to_b = data_fixture.create_two_linked_tables(user=user)
2417+
table_b_primary = table_b.field_set.get(primary=True)
2418+
table_b_primary.primary = False
2419+
table_b_primary.save()
2420+
2421+
primary_b = data_fixture.create_file_field(
2422+
table=table_b, name="Files", primary=True
2423+
)
2424+
count_formula = data_fixture.create_formula_field(
2425+
table=table_a,
2426+
name="Count",
2427+
formula=f"count(field('{link_a_to_b.name}'))",
2428+
)
2429+
2430+
user_file_1 = data_fixture.create_user_file()
2431+
user_file_2 = data_fixture.create_user_file()
2432+
user_file_3 = data_fixture.create_user_file()
2433+
row_handler = RowHandler()
2434+
rows_b = row_handler.force_create_rows(
2435+
user=user,
2436+
table=table_b,
2437+
rows_values=[
2438+
{
2439+
primary_b.db_column: [
2440+
{"name": user_file_1.name},
2441+
{"name": user_file_2.name},
2442+
]
2443+
},
2444+
{primary_b.db_column: [{"name": user_file_3.name}]},
2445+
],
2446+
model=table_b.get_model(),
2447+
).created_rows
2448+
row_a = row_handler.force_create_rows(
2449+
user=user,
2450+
table=table_a,
2451+
rows_values=[{link_a_to_b.db_column: [row.id for row in rows_b]}],
2452+
model=table_a.get_model(),
2453+
).created_rows[0]
2454+
2455+
assert getattr(row_a, count_formula.db_column) == 2
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "bug",
3+
"message": "Fixed count() returning an array instead of a number for link row fields whose linked primary field is an array formula or lookup.",
4+
"issue_origin": "github",
5+
"issue_number": 5276,
6+
"domain": "database",
7+
"bullet_points": [],
8+
"created_at": "2026-04-29"
9+
}

0 commit comments

Comments
 (0)