From 5f8cce3558f7c0ce7a2680b22282adf0c9744b52 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Tue, 13 Jan 2026 14:54:35 +0200 Subject: [PATCH] [#7444] remove unnecessery subquery when resolving single back-relation fields --- core/record_field_resolver_runner.go | 11 ++++++----- core/record_field_resolver_test.go | 8 ++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/core/record_field_resolver_runner.go b/core/record_field_resolver_runner.go index c43a0a42..0d4f406b 100644 --- a/core/record_field_resolver_runner.go +++ b/core/record_field_resolver_runner.go @@ -547,15 +547,11 @@ func (r *runner) processActiveProps() (*search.ResolverResult, error) { // --- cleanProp := inflector.Columnify(prop) cleanBackFieldName := inflector.Columnify(backRelField.Name) + newTableAlias := r.activeTableAlias + "_" + cleanProp + r.resolver.joinAliasSuffix newCollectionName := inflector.Columnify(backCollection.Name) isBackRelMultiple := backRelField.IsMultiple() - if !isBackRelMultiple { - // additionally check if the rel field has a single column unique index - _, hasUniqueIndex := dbutils.FindSingleColumnUniqueIndex(backCollection.Indexes, backRelField.Name) - isBackRelMultiple = !hasUniqueIndex - } if !isBackRelMultiple { err := r.resolver.registerJoin( @@ -592,6 +588,11 @@ func (r *runner) processActiveProps() (*search.ResolverResult, error) { // --- if isBackRelMultiple { r.withMultiMatch = true // enable multimatch if not already + } else if !r.withMultiMatch { + // additionally check if the rel field has a single column unique index; + // if not - apply a multi-match check + _, hasUniqueIndex := dbutils.FindSingleColumnUniqueIndex(backCollection.Indexes, backRelField.Name) + r.withMultiMatch = !hasUniqueIndex } newTableAlias2 := r.multiMatchActiveTableAlias + "_" + cleanProp + r.resolver.joinAliasSuffix diff --git a/core/record_field_resolver_test.go b/core/record_field_resolver_test.go index 58db99f7..0992662e 100644 --- a/core/record_field_resolver_test.go +++ b/core/record_field_resolver_test.go @@ -127,14 +127,14 @@ func TestRecordFieldResolverUpdateQuery(t *testing.T) { expectQuery string }{ { - "non relation field (with all default operators)", + "none relation field (with all default operators)", "demo4", "title = true || title != 'test' || title ~ 'test1' || title !~ '%test2' || title > 1 || title >= 2 || title < 3 || title <= 4", false, "SELECT `demo4`.* FROM `demo4` WHERE ([[demo4.title]] = 1 OR [[demo4.title]] IS NOT {:TEST} OR [[demo4.title]] LIKE {:TEST} ESCAPE '\\' OR [[demo4.title]] NOT LIKE {:TEST} ESCAPE '\\' OR [[demo4.title]] > {:TEST} OR [[demo4.title]] >= {:TEST} OR [[demo4.title]] < {:TEST} OR [[demo4.title]] <= {:TEST})", }, { - "non relation field (with all opt/any operators)", + "none relation field (with all opt/any operators)", "demo4", "title ?= true || title ?!= 'test' || title ?~ 'test1' || title ?!~ '%test2' || title ?> 1 || title ?>= 2 || title ?< 3 || title ?<= 4", false, @@ -292,7 +292,7 @@ func TestRecordFieldResolverUpdateQuery(t *testing.T) { "demo3", "demo4_via_rel_one_cascade.id = true", false, - "SELECT DISTINCT `demo3`.* FROM `demo3` LEFT JOIN `demo4` `demo3_demo4_via_rel_one_cascade` ON [[demo3.id]] IN (SELECT [[__je_demo3_demo4_via_rel_one_cascade.value]] FROM json_each(CASE WHEN iif(json_valid([[demo3_demo4_via_rel_one_cascade.rel_one_cascade]]), json_type([[demo3_demo4_via_rel_one_cascade.rel_one_cascade]])='array', FALSE) THEN [[demo3_demo4_via_rel_one_cascade.rel_one_cascade]] ELSE json_array([[demo3_demo4_via_rel_one_cascade.rel_one_cascade]]) END) {{__je_demo3_demo4_via_rel_one_cascade}}) WHERE ((([[demo3_demo4_via_rel_one_cascade.id]] = 1) AND (NOT EXISTS (SELECT 1 FROM (SELECT [[__mm_demo3_demo4_via_rel_one_cascade.id]] as [[multiMatchValue]] FROM `demo3` `__mm_demo3` LEFT JOIN `demo4` `__mm_demo3_demo4_via_rel_one_cascade` ON [[__mm_demo3.id]] IN (SELECT [[__je___mm_demo3_demo4_via_rel_one_cascade.value]] FROM json_each(CASE WHEN iif(json_valid([[__mm_demo3_demo4_via_rel_one_cascade.rel_one_cascade]]), json_type([[__mm_demo3_demo4_via_rel_one_cascade.rel_one_cascade]])='array', FALSE) THEN [[__mm_demo3_demo4_via_rel_one_cascade.rel_one_cascade]] ELSE json_array([[__mm_demo3_demo4_via_rel_one_cascade.rel_one_cascade]]) END) {{__je___mm_demo3_demo4_via_rel_one_cascade}}) WHERE `__mm_demo3`.`id` = `demo3`.`id`) {{__smTEST}} WHERE NOT ([[__smTEST.multiMatchValue]] = 1)))))", + "SELECT DISTINCT `demo3`.* FROM `demo3` LEFT JOIN `demo4` `demo3_demo4_via_rel_one_cascade` ON [[demo3_demo4_via_rel_one_cascade.rel_one_cascade]] = [[demo3.id]] WHERE ((([[demo3_demo4_via_rel_one_cascade.id]] = 1) AND (NOT EXISTS (SELECT 1 FROM (SELECT [[__mm_demo3_demo4_via_rel_one_cascade.id]] as [[multiMatchValue]] FROM `demo3` `__mm_demo3` LEFT JOIN `demo4` `__mm_demo3_demo4_via_rel_one_cascade` ON [[__mm_demo3_demo4_via_rel_one_cascade.rel_one_cascade]] = [[__mm_demo3.id]] WHERE `__mm_demo3`.`id` = `demo3`.`id`) {{__smTEST}} WHERE NOT ([[__smTEST.multiMatchValue]] = 1)))))", }, { "back relations via single relation field (with unique index)", @@ -334,7 +334,7 @@ func TestRecordFieldResolverUpdateQuery(t *testing.T) { "demo1", "view1_via_rel_one.rel_many.created ?> true", true, - "SELECT DISTINCT `demo1`.* FROM `demo1` LEFT JOIN `view1` `demo1_view1_via_rel_one` ON [[demo1.id]] IN (SELECT [[__je_demo1_view1_via_rel_one.value]] FROM json_each(CASE WHEN iif(json_valid([[demo1_view1_via_rel_one.rel_one]]), json_type([[demo1_view1_via_rel_one.rel_one]])='array', FALSE) THEN [[demo1_view1_via_rel_one.rel_one]] ELSE json_array([[demo1_view1_via_rel_one.rel_one]]) END) {{__je_demo1_view1_via_rel_one}}) LEFT JOIN json_each(CASE WHEN iif(json_valid([[demo1_view1_via_rel_one.rel_many]]), json_type([[demo1_view1_via_rel_one.rel_many]])='array', FALSE) THEN [[demo1_view1_via_rel_one.rel_many]] ELSE json_array([[demo1_view1_via_rel_one.rel_many]]) END) `__je_demo1_view1_via_rel_one_rel_many` LEFT JOIN `users` `demo1_view1_via_rel_one_rel_many` ON [[demo1_view1_via_rel_one_rel_many.id]] = [[__je_demo1_view1_via_rel_one_rel_many.value]] WHERE [[demo1_view1_via_rel_one_rel_many.created]] > 1", + "SELECT DISTINCT `demo1`.* FROM `demo1` LEFT JOIN `view1` `demo1_view1_via_rel_one` ON [[demo1_view1_via_rel_one.rel_one]] = [[demo1.id]] LEFT JOIN json_each(CASE WHEN iif(json_valid([[demo1_view1_via_rel_one.rel_many]]), json_type([[demo1_view1_via_rel_one.rel_many]])='array', FALSE) THEN [[demo1_view1_via_rel_one.rel_many]] ELSE json_array([[demo1_view1_via_rel_one.rel_many]]) END) `__je_demo1_view1_via_rel_one_rel_many` LEFT JOIN `users` `demo1_view1_via_rel_one_rel_many` ON [[demo1_view1_via_rel_one_rel_many.id]] = [[__je_demo1_view1_via_rel_one_rel_many.value]] WHERE [[demo1_view1_via_rel_one_rel_many.created]] > 1", }, { "recursive back relations with non-empty list rule",