Browse Source

Added "mode" parameter to `GET /arbitrary/resources/search`, with possible values of LATEST, ALL.

By default, only the latest resource is returned for a name/service combination. All identifiers can be optionally returned by setting `mode` to "ALL".

More search modes can be added in the future, for instance "RELEVANT" or "POPULAR" (these are just ideas, and are not currently supported).
arbitrary-resources-cache
CalDescent 1 year ago
parent
commit
c210d63c40
  1. 5
      Q-Apps.md
  2. 6
      src/main/java/org/qortal/api/SearchMode.java
  3. 3
      src/main/java/org/qortal/api/resource/ArbitraryResource.java
  4. 3
      src/main/java/org/qortal/repository/ArbitraryRepository.java
  5. 27
      src/main/java/org/qortal/repository/hsqldb/HSQLDBArbitraryRepository.java
  6. 1
      src/main/resources/q-apps/q-apps.js

5
Q-Apps.md

@ -362,6 +362,7 @@ let res = await qortalRequest({
prefix: false, // Optional - if true, only the beginning of fields are matched in all of the above filters
exactMatchNames: true, // Optional - if true, partial name matches are excluded
default: false, // Optional - if true, only resources without identifiers are returned
mode: "LATEST", // Optional - whether to return all resources or just the latest for a name/service combination. Possible values: ALL,LATEST. Default: LATEST
includeStatus: false, // Optional - will take time to respond, so only request if necessary
includeMetadata: false, // Optional - will take time to respond, so only request if necessary
nameListFilter: "QApp1234Subscriptions", // Optional - will only return results if they are from a name included in supplied list
@ -384,12 +385,16 @@ let res = await qortalRequest({
identifier: "search query goes here", // Optional - searches only the "identifier" field
names: ["QortalDemo", "crowetic", "AlphaX"], // Optional - searches only the "name" field for any of the supplied names
prefix: false, // Optional - if true, only the beginning of fields are matched in all of the above filters
exactMatchNames: true, // Optional - if true, partial name matches are excluded
default: false, // Optional - if true, only resources without identifiers are returned
mode: "LATEST", // Optional - whether to return all resources or just the latest for a name/service combination. Possible values: ALL,LATEST. Default: LATEST
includeStatus: false, // Optional - will take time to respond, so only request if necessary
includeMetadata: false, // Optional - will take time to respond, so only request if necessary
nameListFilter: "QApp1234Subscriptions", // Optional - will only return results if they are from a name included in supplied list
followedOnly: false, // Optional - include followed names only
excludeBlocked: false, // Optional - exclude blocked content
// before: 1683546000000, // Optional - limit to resources created before timestamp
// after: 1683546000000, // Optional - limit to resources created after timestamp
limit: 100,
offset: 0,
reverse: true

6
src/main/java/org/qortal/api/SearchMode.java

@ -0,0 +1,6 @@
package org.qortal.api;
public enum SearchMode {
LATEST,
ALL;
}

3
src/main/java/org/qortal/api/resource/ArbitraryResource.java

@ -170,6 +170,7 @@ public class ArbitraryResource {
@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,
@Parameter(description = "Search mode") @QueryParam("mode") SearchMode mode,
@Parameter(description = "Filter names by list (exact matches only)") @QueryParam("namefilter") String nameListFilter,
@Parameter(description = "Include followed names only") @QueryParam("followedonly") Boolean followedOnly,
@Parameter(description = "Exclude blocked content") @QueryParam("excludeblocked") Boolean excludeBlocked,
@ -206,7 +207,7 @@ public class ArbitraryResource {
List<ArbitraryResourceData> resources = repository.getArbitraryRepository()
.searchArbitraryResources(service, query, identifier, names, title, description, usePrefixOnly,
exactMatchNames, defaultRes, followedOnly, excludeBlocked, includeMetadata, includeStatus,
exactMatchNames, defaultRes, mode, followedOnly, excludeBlocked, includeMetadata, includeStatus,
before, after, limit, offset, reverse);
if (resources == null) {

3
src/main/java/org/qortal/repository/ArbitraryRepository.java

@ -1,5 +1,6 @@
package org.qortal.repository;
import org.qortal.api.SearchMode;
import org.qortal.arbitrary.misc.Service;
import org.qortal.data.arbitrary.ArbitraryResourceData;
import org.qortal.data.arbitrary.ArbitraryResourceMetadata;
@ -39,7 +40,7 @@ public interface ArbitraryRepository {
public List<ArbitraryResourceData> getArbitraryResources(Service service, String identifier, List<String> names, boolean defaultResource, Boolean followedOnly, Boolean excludeBlocked, Boolean includeMetadata, Boolean includeStatus, Integer limit, Integer offset, Boolean reverse) throws DataException;
public List<ArbitraryResourceData> searchArbitraryResources(Service service, String query, String identifier, List<String> names, String title, String description, boolean prefixOnly, List<String> namesFilter, boolean defaultResource, Boolean followedOnly, Boolean excludeBlocked, Boolean includeMetadata, Boolean includeStatus, Long before, Long after, Integer limit, Integer offset, Boolean reverse) throws DataException;
public List<ArbitraryResourceData> searchArbitraryResources(Service service, String query, String identifier, List<String> names, String title, String description, boolean prefixOnly, List<String> namesFilter, boolean defaultResource, SearchMode mode, Boolean followedOnly, Boolean excludeBlocked, Boolean includeMetadata, Boolean includeStatus, Long before, Long after, Integer limit, Integer offset, Boolean reverse) throws DataException;
// Arbitrary resources cache save/load

27
src/main/java/org/qortal/repository/hsqldb/HSQLDBArbitraryRepository.java

@ -2,6 +2,7 @@ package org.qortal.repository.hsqldb;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.qortal.api.SearchMode;
import org.qortal.arbitrary.metadata.ArbitraryDataTransactionMetadata;
import org.qortal.arbitrary.misc.Category;
import org.qortal.arbitrary.misc.Service;
@ -639,16 +640,34 @@ public class HSQLDBArbitraryRepository implements ArbitraryRepository {
@Override
public List<ArbitraryResourceData> searchArbitraryResources(Service service, String query, String identifier, List<String> names, String title, String description, boolean prefixOnly,
List<String> exactMatchNames, boolean defaultResource, Boolean followedOnly, Boolean excludeBlocked,
List<String> exactMatchNames, boolean defaultResource, SearchMode mode, Boolean followedOnly, Boolean excludeBlocked,
Boolean includeMetadata, Boolean includeStatus, Long before, Long after, Integer limit, Integer offset, Boolean reverse) throws DataException {
StringBuilder sql = new StringBuilder(512);
List<Object> bindParams = new ArrayList<>();
sql.append("SELECT name, service, identifier, size, status, created_when, updated_when, " +
"title, description, category, tag1, tag2, tag3, tag4, tag5 " +
"FROM ArbitraryResourcesCache " +
"LEFT JOIN ArbitraryMetadataCache USING (service, name, identifier) " +
"WHERE name IS NOT NULL");
"FROM ArbitraryResourcesCache");
// Default to "latest" mode
if (mode == null) {
mode = SearchMode.LATEST;
}
switch (mode) {
case LATEST:
// Include latest item only for a name/service combination
sql.append(" JOIN (SELECT name, service, MAX(created_when) AS latest " +
"FROM ArbitraryResourcesCache GROUP BY name, service) LatestResources " +
"ON name=LatestResources.name AND service=LatestResources.service " +
"AND created_when=LatestResources.latest");
break;
case ALL:
break;
}
sql.append(" LEFT JOIN ArbitraryMetadataCache USING (service, name, identifier) WHERE name IS NOT NULL");
if (service != null) {
sql.append(" AND service = ");

1
src/main/resources/q-apps/q-apps.js

@ -223,6 +223,7 @@ window.addEventListener("message", (event) => {
if (data.prefix != null) url = url.concat("&prefix=" + new Boolean(data.prefix).toString());
if (data.exactMatchNames != null) url = url.concat("&exactmatchnames=" + new Boolean(data.exactMatchNames).toString());
if (data.default != null) url = url.concat("&default=" + new Boolean(data.default).toString());
if (data.mode != null) url = url.concat("&mode=" + data.mode);
if (data.includeStatus != null) url = url.concat("&includestatus=" + new Boolean(data.includeStatus).toString());
if (data.includeMetadata != null) url = url.concat("&includemetadata=" + new Boolean(data.includeMetadata).toString());
if (data.nameListFilter != null) url = url.concat("&namefilter=" + data.nameListFilter);

Loading…
Cancel
Save