• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

knowledgepixels / nanodash / 26518296981

27 May 2026 02:41PM UTC coverage: 20.586% (+0.05%) from 20.537%
26518296981

push

github

web-flow
Merge pull request #471 from knowledgepixels/chore/bump-nanopub-1.90.0

Bump nanopub to 1.90.0 and drop placeholder/expansion code it now provides

1007 of 6204 branches covered (16.23%)

Branch coverage included in aggregate %.

2604 of 11337 relevant lines covered (22.97%)

3.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.81
src/main/java/com/knowledgepixels/nanodash/GrlcQuery.java
1
package com.knowledgepixels.nanodash;
2

3
import com.knowledgepixels.nanodash.component.QueryParamField;
4
import org.nanopub.extra.services.QueryRef;
5
import org.nanopub.extra.services.QueryTemplate;
6
import org.slf4j.Logger;
7
import org.slf4j.LoggerFactory;
8

9
import com.google.common.cache.Cache;
10
import com.google.common.cache.CacheBuilder;
11

12
import java.util.ArrayList;
13
import java.util.HashMap;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.concurrent.TimeUnit;
17
import java.util.regex.Matcher;
18
import java.util.regex.Pattern;
19

20
/**
21
 * Represents a GRLC query extracted from a nanopublication.
22
 * <p>
23
 * Query parsing (SPARQL, endpoint, label, description, placeholders) is inherited from
24
 * {@link QueryTemplate} in nanopub-java. This subclass adds Nanodash-specific concerns:
25
 * an instance cache with {@link #get} factory methods, and integration with the
26
 * {@link QueryParamField} form components used by the query UI.
27
 */
28
public class GrlcQuery extends QueryTemplate {
29

30
    private static final Logger logger = LoggerFactory.getLogger(GrlcQuery.class);
9✔
31

32
    private static final Cache<String, GrlcQuery> instanceMap = CacheBuilder.newBuilder()
6✔
33
        .maximumSize(5_000)
9✔
34
        .expireAfterAccess(24, TimeUnit.HOURS)
3✔
35
        .build();
6✔
36

37
    private static final Pattern ARTIFACT_CODE_PATTERN = Pattern.compile("RA[A-Za-z0-9\\-_]{43}");
12✔
38

39
    /**
40
     * Returns a singleton instance of GrlcQuery for the given QueryRef.
41
     *
42
     * @param ref the QueryRef object containing the query name
43
     * @return a GrlcQuery instance
44
     */
45
    public static GrlcQuery get(QueryRef ref) {
46
        return get(ref.getQueryId());
12✔
47
    }
48

49
    /**
50
     * Returns a singleton instance of GrlcQuery for the given query ID.
51
     *
52
     * @param id the unique identifier or URI of the query
53
     * @return a GrlcQuery instance
54
     */
55
    public static GrlcQuery get(String id) {
56
        if (id == null) return null;
12✔
57
        GrlcQuery cached = instanceMap.getIfPresent(id);
15✔
58
        if (cached == null) {
6!
59
            try {
60
                GrlcQuery q = new GrlcQuery(id);
15✔
61
                id = q.getQueryId();
9✔
62
                cached = instanceMap.getIfPresent(id);
15✔
63
                if (cached != null) return cached;
12✔
64
                instanceMap.put(id, q);
12✔
65
                cached = q;
6✔
66
            } catch (Exception ex) {
3✔
67
                logger.error("Could not load query: {}", id, ex);
15✔
68
            }
3✔
69
        }
70
        return cached;
6✔
71
    }
72

73
    /**
74
     * Constructs a GrlcQuery by parsing the given query ID or URI, fetching the underlying
75
     * nanopublication through Nanodash's {@link Utils#getNanopub(String)} (which uses the
76
     * configured registries and a local cache).
77
     *
78
     * @param id the query ID or URI
79
     * @throws IllegalArgumentException if the ID is invalid or the nanopublication does not
80
     *                                  contain exactly one query
81
     */
82
    private GrlcQuery(String id) {
83
        super(Utils.getNanopub(extractArtifactCode(id)), id);
18✔
84
    }
3✔
85

86
    private static String extractArtifactCode(String id) {
87
        if (id == null) {
6!
88
            throw new IllegalArgumentException("Null value for query ID");
×
89
        }
90
        Matcher m = ARTIFACT_CODE_PATTERN.matcher(id);
12✔
91
        if (m.find()) {
9!
92
            return m.group();
9✔
93
        }
94
        throw new IllegalArgumentException("Not a valid query ID or URI: " + id);
×
95
    }
96

97
    /**
98
     * Creates a list of query parameter fields for the placeholders in the query.
99
     *
100
     * @param markupId The markup ID for the fields.
101
     * @return A list of query parameter fields.
102
     */
103
    public List<QueryParamField> createParamFields(String markupId) {
104
        List<QueryParamField> l = new ArrayList<>();
12✔
105
        for (String s : getPlaceholdersList()) {
21!
106
            l.add(new QueryParamField(markupId, s));
×
107
        }
×
108
        return l;
6✔
109
    }
110

111
    /**
112
     * Expands the SPARQL query by substituting the user-entered param-field values. This adapts the
113
     * UI {@link QueryParamField}s into the parameter map of {@link QueryTemplate#expandQuery(Map, boolean)}
114
     * and expands non-strictly: missing/unset params are not errors but left partially expanded (the
115
     * placeholder kept for single values, the empty {@code VALUES} block dropped for multi values), as
116
     * needed for the Yasgui link.
117
     *
118
     * @param paramFields the list of query parameter fields with user-entered values
119
     * @return the expanded SPARQL query string
120
     */
121
    public String expandQuery(List<QueryParamField> paramFields) {
122
        Map<String, List<String>> params = new HashMap<>();
×
123
        for (QueryParamField f : paramFields) {
×
124
            if (f.isSet()) params.put(f.getParamName(), List.of(f.getValues()));
×
125
        }
×
126
        return expandQuery(params, false);
×
127
    }
128

129
    /**
130
     * Returns true if all mandatory (non-optional) param fields have values set.
131
     *
132
     * @param paramFields the list of query parameter fields
133
     * @return true if all mandatory fields are set
134
     */
135
    public static boolean allMandatoryFieldsSet(List<QueryParamField> paramFields) {
136
        for (QueryParamField f : paramFields) {
×
137
            if (!f.isOptional() && !f.isSet()) return false;
×
138
        }
×
139
        return true;
×
140
    }
141

142
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc