Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
<dependency>
<groupId>org.nanopub</groupId>
<artifactId>nanopub</artifactId>
<version>1.89.0</version>
<version>1.90.0</version>
</dependency>
<!-- Temporary: dependency on Jitpack for snapshot builds -->
<!-- <dependency>
Expand Down
48 changes: 8 additions & 40 deletions src/main/java/com/knowledgepixels/nanodash/GrlcQuery.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,49 +109,21 @@ public List<QueryParamField> createParamFields(String markupId) {
}

/**
* Expands the SPARQL query by substituting placeholder values from the given param fields.
* Unlike the strict server-side expansion in {@link QueryTemplate}, missing/unset params are
* simply skipped (not thrown as errors), to support the partial substitution used for the
* Yasgui link. Placeholder conventions follow {@link QueryParamField} (which recognizes
* {@code _multi_val} in addition to the standard suffixes).
* Expands the SPARQL query by substituting the user-entered param-field values. This adapts the
* UI {@link QueryParamField}s into the parameter map of {@link QueryTemplate#expandQuery(Map, boolean)}
* and expands non-strictly: missing/unset params are not errors but left partially expanded (the
* placeholder kept for single values, the empty {@code VALUES} block dropped for multi values), as
* needed for the Yasgui link.
*
* @param paramFields the list of query parameter fields with user-entered values
* @return the expanded SPARQL query string
*/
public String expandQuery(List<QueryParamField> paramFields) {
Map<String, QueryParamField> fieldMap = new HashMap<>();
Map<String, List<String>> params = new HashMap<>();
for (QueryParamField f : paramFields) {
fieldMap.put(f.getParamName(), f);
if (f.isSet()) params.put(f.getParamName(), List.of(f.getValues()));
}
String expandedQueryContent = getSparql();
for (String ph : getPlaceholdersList()) {
String paramName = QueryParamField.getParamName(ph);
QueryParamField field = fieldMap.get(paramName);
if (field == null || !field.isSet()) continue;
if (QueryParamField.isMultiPlaceholder(ph)) {
String[] values = field.getValues();
StringBuilder valueList = new StringBuilder();
for (String v : values) {
if (isIriPlaceholder(ph)) {
valueList.append(serializeIri(v)).append(" ");
} else {
valueList.append(serializeLiteral(v)).append(" ");
}
}
expandedQueryContent = expandedQueryContent.replaceAll(
"values\\s*\\?" + ph + "\\s*\\{\\s*\\}",
"values ?" + ph + " { " + escapeSlashes(valueList.toString()) + "}"
);
} else {
String val = field.getValues()[0];
if (isIriPlaceholder(ph)) {
expandedQueryContent = expandedQueryContent.replaceAll("\\?" + ph + "(?![A-Za-z0-9_])", escapeSlashes(serializeIri(val)));
} else {
expandedQueryContent = expandedQueryContent.replaceAll("\\?" + ph + "(?![A-Za-z0-9_])", escapeSlashes(serializeLiteral(val)));
}
}
}
return expandedQueryContent;
return expandQuery(params, false);
}

/**
Expand All @@ -167,8 +139,4 @@ public static boolean allMandatoryFieldsSet(List<QueryParamField> paramFields) {
return true;
}

private static String escapeSlashes(String string) {
return string.replace("\\", "\\\\");
}

}
4 changes: 2 additions & 2 deletions src/main/java/com/knowledgepixels/nanodash/LookupApis.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.nanopub.extra.services.ApiResponse;
import org.nanopub.extra.services.ApiResponseEntry;
import org.nanopub.extra.services.QueryRef;
import org.nanopub.extra.services.QueryTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -27,7 +28,6 @@
import com.github.openjson.JSONObject;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.knowledgepixels.nanodash.component.QueryParamField;

/**
* Utility class for APIs look up and parsing.
Expand Down Expand Up @@ -287,7 +287,7 @@ private static void lookupNanopubNetwork(String apiString, String searchterm, Ma
}
String queryParamName = "query";
if (q.getPlaceholdersList().size() == 1) {
queryParamName = QueryParamField.getParamName(q.getPlaceholdersList().get(0));
queryParamName = QueryTemplate.getParamName(q.getPlaceholdersList().get(0));
}
params.put(queryParamName, searchterm);
ApiResponse result = ApiCache.retrieveResponseSync(new QueryRef(queryId, params), false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.ValidationError;
import org.eclipse.rdf4j.common.net.ParsedIRI;
import org.nanopub.extra.services.QueryTemplate;

import java.net.URISyntaxException;

Expand Down Expand Up @@ -76,7 +77,7 @@ public String getParamId() {
* @return the parameter name
*/
public String getParamName() {
return getParamName(paramId);
return QueryTemplate.getParamName(paramId);
}

/**
Expand Down Expand Up @@ -108,7 +109,7 @@ public void clearValue() {
* @return true if the parameter is optional, false otherwise
*/
public boolean isOptional() {
return isOptional(paramId);
return QueryTemplate.isOptionalPlaceholder(paramId);
}

/**
Expand All @@ -117,7 +118,7 @@ public boolean isOptional() {
* @return true if the parameter is an IRI parameter, false otherwise
*/
public boolean isIri() {
return paramId.endsWith("_iri");
return QueryTemplate.isIriPlaceholder(paramId);
}

/**
Expand All @@ -135,7 +136,7 @@ public boolean isSet() {
* @return true if the parameter is a multi parameter, false otherwise
*/
public boolean isMultiPlaceholder() {
return isMultiPlaceholder(paramId);
return QueryTemplate.isMultiPlaceholder(paramId);
}

private class Validator extends InvalidityHighlighting implements INullAcceptingValidator<String> {
Expand Down Expand Up @@ -180,20 +181,6 @@ public static boolean isSet(String s) {
return s != null && !s.isBlank();
}

/**
* Checks if a parameter ID indicates a multi parameter (ends with "_multi" or "_multi_iri").
*
* @param p the parameter ID to check
* @return true if the parameter ID indicates a multi parameter, false otherwise
*/
public static boolean isMultiPlaceholder(String p) {
return p.endsWith("_multi") || p.endsWith("_multi_iri") || p.endsWith("_multi_val");
}

public static boolean isOptional(String p) {
return p.startsWith("__");
}

/**
* Expands the value string into an array of values based on whether the parameter is multi or not.
*
Expand All @@ -204,21 +191,11 @@ public static boolean isOptional(String p) {
public static String[] expandValues(String s, String paramId) {
if (!isSet(s)) {
return new String[]{};
} else if (isMultiPlaceholder(paramId)) {
} else if (QueryTemplate.isMultiPlaceholder(paramId)) {
return s.replaceFirst("\r?\n$", "").split("\r?\n");
} else {
return new String[]{s};
}
}

/**
* Extracts the parameter name from the placeholder ID.
*
* @param placeholderId the placeholder ID, which may start with underscores and end with "_iri" and/or "_multi"
* @return the parameter name, stripped of leading underscores and "_iri"/"_multi" suffixes
*/
public static String getParamName(String placeholderId) {
return placeholderId.replaceFirst("^_+", "").replaceFirst("_multi_val$", "").replaceFirst("_iri$", "").replaceFirst("_multi$", "");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.apache.wicket.markup.html.panel.Panel;
import org.eclipse.rdf4j.model.IRI;
import org.nanopub.extra.services.QueryRef;
import org.nanopub.extra.services.QueryTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -91,10 +92,10 @@ protected void populateItem(ListItem<ViewDisplay> item) {
View view = item.getModelObject().getView();
Multimap<String, String> queryRefParams = ArrayListMultimap.create();
for (String p : view.getQuery().getPlaceholdersList()) {
String paramName = QueryParamField.getParamName(p);
String paramName = QueryTemplate.getParamName(p);
if (paramName.equals(view.getQueryField())) {
queryRefParams.put(view.getQueryField(), id);
if (QueryParamField.isMultiPlaceholder(p) && resourceWithProfile instanceof Space space) {
if (QueryTemplate.isMultiPlaceholder(p) && resourceWithProfile instanceof Space space) {
// TODO Support this also for maintained resources and users.
for (String altId : space.getAltIDs()) {
queryRefParams.put(view.getQueryField(), altId);
Expand All @@ -103,12 +104,12 @@ protected void populateItem(ListItem<ViewDisplay> item) {
} else if (paramName.equals(view.getQueryField() + "Namespace") && resourceWithProfile.getNamespace() != null) {
queryRefParams.put(view.getQueryField() + "Namespace", resourceWithProfile.getNamespace());
} else if (paramName.equals(view.getQueryField() + "Np")) {
if (!QueryParamField.isOptional(p) && npId == null) {
if (!QueryTemplate.isOptionalPlaceholder(p) && npId == null) {
queryRefParams.put(view.getQueryField() + "Np", "x:");
} else {
queryRefParams.put(view.getQueryField() + "Np", npId);
}
} else if (!QueryParamField.isOptional(p)) {
} else if (!QueryTemplate.isOptionalPlaceholder(p)) {
item.add(new Label("view", "<span class=\"negative\">Error: Query has non-optional parameter</span>").setEscapeModelStrings(false));
logger.error("Error: Query has non-optional parameter: {} {}", view.getQuery().getQueryId(), p);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import com.knowledgepixels.nanodash.Utils;
import com.knowledgepixels.nanodash.View;
import com.knowledgepixels.nanodash.ViewDisplay;
import com.knowledgepixels.nanodash.component.QueryParamField;
import com.knowledgepixels.nanodash.domain.AbstractResourceWithProfile;
import com.knowledgepixels.nanodash.domain.IndividualAgent;
import com.knowledgepixels.nanodash.domain.MaintainedResource;
Expand All @@ -34,6 +33,7 @@
import org.nanopub.extra.services.ApiResponse;
import org.nanopub.extra.services.ApiResponseEntry;
import org.nanopub.extra.services.QueryRef;
import org.nanopub.extra.services.QueryTemplate;
import org.nanopub.extra.setting.IntroNanopub;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -408,23 +408,23 @@ private QueryRef buildQueryRef(ViewDisplay vd, AbstractResourceWithProfile resou

Multimap<String, String> queryRefParams = ArrayListMultimap.create();
for (String p : view.getQuery().getPlaceholdersList()) {
String paramName = QueryParamField.getParamName(p);
String paramName = QueryTemplate.getParamName(p);
if (paramName.equals(view.getQueryField())) {
queryRefParams.put(view.getQueryField(), targetId);
if (QueryParamField.isMultiPlaceholder(p) && resource instanceof Space space) {
if (QueryTemplate.isMultiPlaceholder(p) && resource instanceof Space space) {
for (String altId : space.getAltIDs()) {
queryRefParams.put(view.getQueryField(), altId);
}
}
} else if (paramName.equals(view.getQueryField() + "Namespace") && resource.getNamespace() != null) {
queryRefParams.put(view.getQueryField() + "Namespace", resource.getNamespace());
} else if (paramName.equals(view.getQueryField() + "Np")) {
if (!QueryParamField.isOptional(p) && targetNpId == null) {
if (!QueryTemplate.isOptionalPlaceholder(p) && targetNpId == null) {
queryRefParams.put(view.getQueryField() + "Np", "x:");
} else {
queryRefParams.put(view.getQueryField() + "Np", targetNpId);
}
} else if (!QueryParamField.isOptional(p)) {
} else if (!QueryTemplate.isOptionalPlaceholder(p)) {
logger.error("Query has non-optional parameter that cannot be filled: {} {}", view.getQuery().getQueryId(), p);
return null;
}
Expand Down