diff --git a/CHANGELOG.md b/CHANGELOG.md index 08b184ef..96055d69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ - Added `@yesterday` and `@tomorrow` date filter macros (@todo docs). +- Added `:lower` filter modifier (e.g. `title:lower = "lorem"`). + +- Added `tests.NewTestAppWithConfig(config)` helper if you need more control over the test configurations like `IsDev`, the number of allowed connections, etc. + ## v0.23.5 (WIP) diff --git a/core/record_field_resolver_runner.go b/core/record_field_resolver_runner.go index ec50d1e0..c11dc1a1 100644 --- a/core/record_field_resolver_runner.go +++ b/core/record_field_resolver_runner.go @@ -680,21 +680,6 @@ func (r *runner) processLastProp(collection *Collection, prop string) (*search.R cleanFieldName := inflector.Columnify(field.GetName()) - // field with ":lower" modifier - // ------------------------------------------------------- - if modifier == lowerModifier { - result := &search.ResolverResult{ - Identifier: "LOWER([[" + r.activeTableAlias + "." + cleanFieldName + "]])", - } - - if r.withMultiMatch { - r.multiMatch.valueIdentifier = "LOWER([[" + r.multiMatchActiveTableAlias + "." + cleanFieldName + "]])" - result.MultiMatchSubQuery = r.multiMatch - } - - return result, nil - } - // arrayable fields with ":length" modifier // ------------------------------------------------------- if modifier == lengthModifier && isMultivaluer { @@ -747,11 +732,11 @@ func (r *runner) processLastProp(collection *Collection, prop string) (*search.R // default // ------------------------------------------------------- result := &search.ResolverResult{ - Identifier: fmt.Sprintf("[[%s.%s]]", r.activeTableAlias, cleanFieldName), + Identifier: "[[" + r.activeTableAlias + "." + cleanFieldName + "]]", } if r.withMultiMatch { - r.multiMatch.valueIdentifier = fmt.Sprintf("[[%s.%s]]", r.multiMatchActiveTableAlias, cleanFieldName) + r.multiMatch.valueIdentifier = "[[" + r.multiMatchActiveTableAlias + "." + cleanFieldName + "]]" result.MultiMatchSubQuery = r.multiMatch } @@ -777,5 +762,13 @@ func (r *runner) processLastProp(collection *Collection, prop string) (*search.R } } + // account for the ":lower" modifier + if modifier == lowerModifier { + result.Identifier = "LOWER(" + result.Identifier + ")" + if r.withMultiMatch { + r.multiMatch.valueIdentifier = "LOWER(" + r.multiMatch.valueIdentifier + ")" + } + } + return result, nil } diff --git a/core/record_field_resolver_test.go b/core/record_field_resolver_test.go index 64ba757b..b8fe4b34 100644 --- a/core/record_field_resolver_test.go +++ b/core/record_field_resolver_test.go @@ -262,9 +262,9 @@ func TestRecordFieldResolverUpdateQuery(t *testing.T) { { "hidden field (add emailVisibility)", "users", - "id > true || email > true", + "id > true || email > true || email:lower > false", false, - "SELECT `users`.* FROM `users` WHERE ([[users.id]] > 1 OR (([[users.email]] > 1) AND ([[users.emailVisibility]] = TRUE)))", + "SELECT `users`.* FROM `users` WHERE ([[users.id]] > 1 OR (([[users.email]] > 1) AND ([[users.emailVisibility]] = TRUE)) OR ((LOWER([[users.email]]) > 0) AND ([[users.emailVisibility]] = TRUE)))", }, { "hidden field (force ignore emailVisibility)", @@ -309,7 +309,7 @@ func TestRecordFieldResolverUpdateQuery(t *testing.T) { "rel_many.name:lower > true ||" + "created:lower > true", false, - "SELECT DISTINCT `demo1`.* FROM `demo1` LEFT JOIN `users` `__data_users_rel_many` ON [[__data_users_rel_many.id]] IN ({:p0}, {:p1}) LEFT JOIN json_each(CASE WHEN json_valid([[demo1.rel_many]]) THEN [[demo1.rel_many]] ELSE json_array([[demo1.rel_many]]) END) `demo1_rel_many_je` LEFT JOIN `users` `demo1_rel_many` ON [[demo1_rel_many.id]] = [[demo1_rel_many_je.value]] WHERE (LOWER({:infoLowerrel_oneTEST}) > 1 OR LOWER({:infoLowerrel_manyTEST}) > 1 OR ((LOWER([[__data_users_rel_many.email]]) > 1) AND (NOT EXISTS (SELECT 1 FROM (SELECT LOWER([[__data_mm_users_rel_many.email]]) as [[multiMatchValue]] FROM `demo1` `__mm_demo1` LEFT JOIN `users` `__data_mm_users_rel_many` ON [[__data_mm_users_rel_many.id]] IN ({:p4}, {:p5}) WHERE `__mm_demo1`.`id` = `demo1`.`id`) {{__smTEST}} WHERE ((NOT ([[__smTEST.multiMatchValue]] > 1)) OR ([[__smTEST.multiMatchValue]] IS NULL))))) OR LOWER([[demo1.text]]) > 1 OR LOWER([[demo1.bool]]) > 1 OR LOWER([[demo1.url]]) > 1 OR LOWER([[demo1.select_one]]) > 1 OR LOWER([[demo1.select_many]]) > 1 OR LOWER([[demo1.file_one]]) > 1 OR LOWER([[demo1.file_many]]) > 1 OR LOWER([[demo1.number]]) > 1 OR LOWER([[demo1.email]]) > 1 OR LOWER([[demo1.datetime]]) > 1 OR LOWER([[demo1.json]]) > 1 OR LOWER([[demo1.rel_one]]) > 1 OR LOWER([[demo1.rel_many]]) > 1 OR ((LOWER([[demo1_rel_many.name]]) > 1) AND (NOT EXISTS (SELECT 1 FROM (SELECT LOWER([[__mm_demo1_rel_many.name]]) as [[multiMatchValue]] FROM `demo1` `__mm_demo1` LEFT JOIN json_each(CASE WHEN json_valid([[__mm_demo1.rel_many]]) THEN [[__mm_demo1.rel_many]] ELSE json_array([[__mm_demo1.rel_many]]) END) `__mm_demo1_rel_many_je` LEFT JOIN `users` `__mm_demo1_rel_many` ON [[__mm_demo1_rel_many.id]] = [[__mm_demo1_rel_many_je.value]] WHERE `__mm_demo1`.`id` = `demo1`.`id`) {{__smTEST}} WHERE ((NOT ([[__smTEST.multiMatchValue]] > 1)) OR ([[__smTEST.multiMatchValue]] IS NULL))))) OR LOWER([[demo1.created]]) > 1)", + "SELECT DISTINCT `demo1`.* FROM `demo1` LEFT JOIN `users` `__data_users_rel_many` ON [[__data_users_rel_many.id]] IN ({:p0}, {:p1}) LEFT JOIN json_each(CASE WHEN json_valid([[demo1.rel_many]]) THEN [[demo1.rel_many]] ELSE json_array([[demo1.rel_many]]) END) `demo1_rel_many_je` LEFT JOIN `users` `demo1_rel_many` ON [[demo1_rel_many.id]] = [[demo1_rel_many_je.value]] WHERE (LOWER({:infoLowerrel_oneTEST}) > 1 OR LOWER({:infoLowerrel_manyTEST}) > 1 OR ((LOWER([[__data_users_rel_many.email]]) > 1) AND (NOT EXISTS (SELECT 1 FROM (SELECT LOWER([[__data_mm_users_rel_many.email]]) as [[multiMatchValue]] FROM `demo1` `__mm_demo1` LEFT JOIN `users` `__data_mm_users_rel_many` ON [[__data_mm_users_rel_many.id]] IN ({:p4}, {:p5}) WHERE `__mm_demo1`.`id` = `demo1`.`id`) {{__smTEST}} WHERE ((NOT ([[__smTEST.multiMatchValue]] > 1)) OR ([[__smTEST.multiMatchValue]] IS NULL))))) OR LOWER([[demo1.text]]) > 1 OR LOWER([[demo1.bool]]) > 1 OR LOWER([[demo1.url]]) > 1 OR LOWER([[demo1.select_one]]) > 1 OR LOWER([[demo1.select_many]]) > 1 OR LOWER([[demo1.file_one]]) > 1 OR LOWER([[demo1.file_many]]) > 1 OR LOWER([[demo1.number]]) > 1 OR LOWER([[demo1.email]]) > 1 OR LOWER([[demo1.datetime]]) > 1 OR LOWER((CASE WHEN json_valid([[demo1.json]]) THEN JSON_EXTRACT([[demo1.json]], '$') ELSE JSON_EXTRACT(json_object('pb', [[demo1.json]]), '$.pb') END)) > 1 OR LOWER([[demo1.rel_one]]) > 1 OR LOWER([[demo1.rel_many]]) > 1 OR ((LOWER([[demo1_rel_many.name]]) > 1) AND (NOT EXISTS (SELECT 1 FROM (SELECT LOWER([[__mm_demo1_rel_many.name]]) as [[multiMatchValue]] FROM `demo1` `__mm_demo1` LEFT JOIN json_each(CASE WHEN json_valid([[__mm_demo1.rel_many]]) THEN [[__mm_demo1.rel_many]] ELSE json_array([[__mm_demo1.rel_many]]) END) `__mm_demo1_rel_many_je` LEFT JOIN `users` `__mm_demo1_rel_many` ON [[__mm_demo1_rel_many.id]] = [[__mm_demo1_rel_many_je.value]] WHERE `__mm_demo1`.`id` = `demo1`.`id`) {{__smTEST}} WHERE ((NOT ([[__smTEST.multiMatchValue]] > 1)) OR ([[__smTEST.multiMatchValue]] IS NULL))))) OR LOWER([[demo1.created]]) > 1)", }, { "isset modifier", diff --git a/ui/src/utils/CommonHelper.js b/ui/src/utils/CommonHelper.js index 2087c078..eb0ee3c7 100644 --- a/ui/src/utils/CommonHelper.js +++ b/ui/src/utils/CommonHelper.js @@ -1893,7 +1893,7 @@ export default class CommonHelper { for (const key of keys) { result.push(key); - // add ":isset" and ":lower" modifiers to non-base keys + // add ":isset" modifier to non-base keys const parts = key.split("."); if ( parts.length === 3 &&