From 2e9f358d0bc84a9b0eddafc40cda25973b7eaedc Mon Sep 17 00:00:00 2001 From: PhilReact Date: Thu, 6 Mar 2025 16:10:30 +0200 Subject: [PATCH] changed to list and added to cache --- .../api/resource/ArbitraryResource.java | 2 +- .../repository/ArbitraryRepository.java | 2 +- .../hsqldb/HSQLDBArbitraryRepository.java | 26 +++++++++------- .../repository/hsqldb/HSQLDBCacheUtils.java | 31 +++++++++++++++++++ .../repository/HSQLDBCacheUtilsTests.java | 3 ++ 5 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/qortal/api/resource/ArbitraryResource.java b/src/main/java/org/qortal/api/resource/ArbitraryResource.java index 748ebda9..2aa7b07d 100644 --- a/src/main/java/org/qortal/api/resource/ArbitraryResource.java +++ b/src/main/java/org/qortal/api/resource/ArbitraryResource.java @@ -172,7 +172,7 @@ public class ArbitraryResource { @Parameter(description = "Name (searches name field only)") @QueryParam("name") List names, @Parameter(description = "Title (searches title metadata field only)") @QueryParam("title") String title, @Parameter(description = "Description (searches description metadata field only)") @QueryParam("description") String description, - @Parameter(description = "Keywords (searches description metadata field by keywords. Input is a string of keywords separated by commas.)") @QueryParam("keywords") String keywords, + @Parameter(description = "Keyword (searches description metadata field by keywords)") @QueryParam("keywords") List keywords, @Parameter(description = "Prefix only (if true, only the beginning of fields are matched)") @QueryParam("prefix") Boolean prefixOnly, @Parameter(description = "Exact match names only (if true, partial name matches are excluded)") @QueryParam("exactmatchnames") Boolean exactMatchNamesOnly, @Parameter(description = "Default resources (without identifiers) only") @QueryParam("default") Boolean defaultResource, diff --git a/src/main/java/org/qortal/repository/ArbitraryRepository.java b/src/main/java/org/qortal/repository/ArbitraryRepository.java index 53bbfad5..4770d29b 100644 --- a/src/main/java/org/qortal/repository/ArbitraryRepository.java +++ b/src/main/java/org/qortal/repository/ArbitraryRepository.java @@ -46,7 +46,7 @@ public interface ArbitraryRepository { public List getArbitraryResources(Service service, String identifier, List names, boolean defaultResource, Boolean followedOnly, Boolean excludeBlocked, Boolean includeMetadata, Boolean includeStatus, Integer limit, Integer offset, Boolean reverse) throws DataException; - public List searchArbitraryResources(Service service, String query, String identifier, List names, String title, String description, String keywords, boolean prefixOnly, List namesFilter, boolean defaultResource, SearchMode mode, Integer minLevel, Boolean followedOnly, Boolean excludeBlocked, Boolean includeMetadata, Boolean includeStatus, Long before, Long after, Integer limit, Integer offset, Boolean reverse) throws DataException; + public List searchArbitraryResources(Service service, String query, String identifier, List names, String title, String description, List keywords, boolean prefixOnly, List namesFilter, boolean defaultResource, SearchMode mode, Integer minLevel, Boolean followedOnly, Boolean excludeBlocked, Boolean includeMetadata, Boolean includeStatus, Long before, Long after, Integer limit, Integer offset, Boolean reverse) throws DataException; List searchArbitraryResourcesSimple( Service service, diff --git a/src/main/java/org/qortal/repository/hsqldb/HSQLDBArbitraryRepository.java b/src/main/java/org/qortal/repository/hsqldb/HSQLDBArbitraryRepository.java index 599ac8c0..0e15be77 100644 --- a/src/main/java/org/qortal/repository/hsqldb/HSQLDBArbitraryRepository.java +++ b/src/main/java/org/qortal/repository/hsqldb/HSQLDBArbitraryRepository.java @@ -862,12 +862,11 @@ public class HSQLDBArbitraryRepository implements ArbitraryRepository { } @Override - public List searchArbitraryResources(Service service, String query, String identifier, List names, String title, String description, String keywords, boolean prefixOnly, + public List searchArbitraryResources(Service service, String query, String identifier, List names, String title, String description, List keywords, boolean prefixOnly, List exactMatchNames, boolean defaultResource, SearchMode mode, Integer minLevel, Boolean followedOnly, Boolean excludeBlocked, Boolean includeMetadata, Boolean includeStatus, Long before, Long after, Integer limit, Integer offset, Boolean reverse) throws DataException { if(Settings.getInstance().isDbCacheEnabled()) { - List list = HSQLDBCacheUtils.callCache( ArbitraryResourceCache.getInstance(), @@ -889,6 +888,7 @@ public class HSQLDBArbitraryRepository implements ArbitraryRepository { Optional.ofNullable(description), prefixOnly, Optional.ofNullable(exactMatchNames), + Optional.ofNullable(keywords), defaultResource, Optional.ofNullable(minLevel), Optional.ofNullable(() -> ListUtils.followedNames()), @@ -909,6 +909,7 @@ public class HSQLDBArbitraryRepository implements ArbitraryRepository { } } + StringBuilder sql = new StringBuilder(512); List bindParams = new ArrayList<>(); @@ -995,24 +996,25 @@ public class HSQLDBArbitraryRepository implements ArbitraryRepository { bindParams.add(queryWildcard); } - if (keywords != null) { - String[] encryptedTokens = keywords.split(","); - + if (keywords != null && !keywords.isEmpty()) { + List searchKeywords = new ArrayList<>(keywords); + List conditions = new ArrayList<>(); - List bindValues = new ArrayList<>(); + List bindValues = new ArrayList<>(); - for (String token : encryptedTokens) { - conditions.add("POSITION(? IN description) > 0"); - bindValues.add(token.trim()); + for (int i = 0; i < searchKeywords.size(); i++) { + conditions.add("LOWER(description) LIKE ?"); + bindValues.add("%" + searchKeywords.get(i).trim().toLowerCase() + "%"); } - String finalCondition = String.join(" OR ", conditions); sql.append(" AND (").append(finalCondition).append(")"); - bindParams.addAll(bindValues); - + bindParams.addAll(bindValues); } + + + // Handle name searches if (names != null && !names.isEmpty()) { diff --git a/src/main/java/org/qortal/repository/hsqldb/HSQLDBCacheUtils.java b/src/main/java/org/qortal/repository/hsqldb/HSQLDBCacheUtils.java index 49566be2..726a0c33 100644 --- a/src/main/java/org/qortal/repository/hsqldb/HSQLDBCacheUtils.java +++ b/src/main/java/org/qortal/repository/hsqldb/HSQLDBCacheUtils.java @@ -167,6 +167,7 @@ public class HSQLDBCacheUtils { Optional description, boolean prefixOnly, Optional> exactMatchNames, + Optional> keywords, boolean defaultResource, Optional minLevel, Optional>> includeOnly, @@ -207,6 +208,36 @@ public class HSQLDBCacheUtils { stream = filterTerm(title, data -> data.metadata != null ? data.metadata.getTitle() : null, prefixOnly, stream); stream = filterTerm(description, data -> data.metadata != null ? data.metadata.getDescription() : null, prefixOnly, stream); + // New: Filter by keywords if provided + if (keywords.isPresent() && !keywords.get().isEmpty()) { + List searchKeywords = keywords.get().stream() + .map(String::toLowerCase) + .collect(Collectors.toList()); + + stream = stream.filter(candidate -> { + + if (candidate.metadata != null && candidate.metadata.getDescription() != null) { + String descriptionLower = candidate.metadata.getDescription().toLowerCase(); + return searchKeywords.stream().anyMatch(descriptionLower::contains); + } + return false; + }); + } + + if (keywords.isPresent() && !keywords.get().isEmpty()) { + List searchKeywords = keywords.get().stream() + .map(String::toLowerCase) + .collect(Collectors.toList()); + + stream = stream.filter(candidate -> { + if (candidate.metadata != null && candidate.metadata.getDescription() != null) { + String descriptionLower = candidate.metadata.getDescription().toLowerCase(); + return searchKeywords.stream().anyMatch(descriptionLower::contains); + } + return false; + }); + } + // if exact names is set, retain resources with exact names if( exactMatchNames.isPresent() && !exactMatchNames.get().isEmpty()) { diff --git a/src/test/java/org/qortal/test/repository/HSQLDBCacheUtilsTests.java b/src/test/java/org/qortal/test/repository/HSQLDBCacheUtilsTests.java index 4a75b438..0cda76d4 100644 --- a/src/test/java/org/qortal/test/repository/HSQLDBCacheUtilsTests.java +++ b/src/test/java/org/qortal/test/repository/HSQLDBCacheUtilsTests.java @@ -26,6 +26,7 @@ public class HSQLDBCacheUtilsTests { private static final String DESCRIPTION = "description"; private static final String PREFIX_ONLY = "prefixOnly"; private static final String EXACT_MATCH_NAMES = "exactMatchNames"; + private static final String KEYWORDS = "keywords"; private static final String DEFAULT_RESOURCE = "defaultResource"; private static final String MODE = "mode"; private static final String MIN_LEVEL = "minLevel"; @@ -634,6 +635,7 @@ public class HSQLDBCacheUtilsTests { Optional description = Optional.ofNullable((String) valueByKey.get(DESCRIPTION)); boolean prefixOnly = valueByKey.containsKey(PREFIX_ONLY); Optional> exactMatchNames = Optional.ofNullable((List) valueByKey.get(EXACT_MATCH_NAMES)); + Optional> keywords = Optional.ofNullable((List) valueByKey.get(KEYWORDS)); boolean defaultResource = valueByKey.containsKey(DEFAULT_RESOURCE); Optional mode = Optional.of((SearchMode) valueByKey.getOrDefault(MODE, SearchMode.ALL)); Optional minLevel = Optional.ofNullable((Integer) valueByKey.get(MIN_LEVEL)); @@ -660,6 +662,7 @@ public class HSQLDBCacheUtilsTests { description, prefixOnly, exactMatchNames, + keywords, defaultResource, minLevel, followedOnly,