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

knowledgepixels / nanodash / 21662157612

04 Feb 2026 07:12AM UTC coverage: 14.259% (+0.004%) from 14.255%
21662157612

push

github

tkuhn
fix: Compile errors when run through script resolved

582 of 5240 branches covered (11.11%)

Branch coverage included in aggregate %.

1523 of 9523 relevant lines covered (15.99%)

2.08 hits per line

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

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

3
import com.knowledgepixels.nanodash.component.QueryParamField;
4
import net.trustyuri.TrustyUriUtils;
5
import org.eclipse.rdf4j.model.IRI;
6
import org.eclipse.rdf4j.model.Literal;
7
import org.eclipse.rdf4j.model.Statement;
8
import org.eclipse.rdf4j.model.vocabulary.DCTERMS;
9
import org.eclipse.rdf4j.model.vocabulary.RDF;
10
import org.eclipse.rdf4j.model.vocabulary.RDFS;
11
import org.eclipse.rdf4j.query.algebra.Var;
12
import org.eclipse.rdf4j.query.algebra.helpers.AbstractSimpleQueryModelVisitor;
13
import org.eclipse.rdf4j.query.parser.ParsedQuery;
14
import org.eclipse.rdf4j.query.parser.sparql.SPARQLParser;
15
import org.nanopub.Nanopub;
16
import org.nanopub.extra.services.QueryRef;
17
import org.slf4j.Logger;
18
import org.slf4j.LoggerFactory;
19

20
import java.io.Serializable;
21
import java.util.*;
22

23
/**
24
 * Represents a GRLC query extracted from a nanopublication.
25
 * This class parses the query details, including SPARQL, endpoint, label, description, and placeholders.
26
 */
27
public class GrlcQuery implements Serializable {
28

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

31
    private static Map<String, GrlcQuery> instanceMap = new HashMap<>();
12✔
32

33
    /**
34
     * Returns a singleton instance of GrlcQuery for the given QueryRef.
35
     *
36
     * @param ref the QueryRef object containing the query name
37
     * @return a GrlcQuery instance
38
     */
39
    public static GrlcQuery get(QueryRef ref) {
40
        return get(ref.getName());
12✔
41
    }
42

43
    /**
44
     * Returns a singleton instance of GrlcQuery for the given query ID.
45
     *
46
     * @param id the unique identifier or URI of the query
47
     * @return a GrlcQuery instance
48
     */
49
    public static GrlcQuery get(String id) {
50
        if (!instanceMap.containsKey(id)) {
12!
51
            try {
52
                GrlcQuery q = new GrlcQuery(id);
15✔
53
                id = q.getQueryId();
9✔
54
                if (instanceMap.containsKey(id)) return instanceMap.get(id);
27✔
55
                instanceMap.put(id, q);
15✔
56
            } catch (Exception ex) {
3✔
57
                logger.error("Could not load query: {}", id, ex);
15✔
58
            }
3✔
59
        }
60
        return instanceMap.get(id);
15✔
61
    }
62

63
    /**
64
     * The IRI for the GRLC query class and properties.
65
     */
66
    public final static IRI GRLC_QUERY_CLASS = Utils.vf.createIRI("https://w3id.org/kpxl/grlc/grlc-query");
12✔
67

68
    /**
69
     * The IRI for the SPARQL property and endpoint property in GRLC queries.
70
     */
71
    public final static IRI GRLC_HAS_SPARQL = Utils.vf.createIRI("https://w3id.org/kpxl/grlc/sparql");
12✔
72

73
    /**
74
     * The IRI for the endpoint property in GRLC queries.
75
     */
76
    public final static IRI GRLC_HAS_ENDPOINT = Utils.vf.createIRI("https://w3id.org/kpxl/grlc/endpoint");
15✔
77

78
    private final String queryId;
79
    private final String artifactCode;
80
    private final String querySuffix;
81
    private final Nanopub nanopub;
82
    private IRI queryUri;
83
    private String sparql;
84
    private IRI endpoint;
85
    private String label;
86
    private String description;
87
    private final List<String> placeholdersList;
88

89
    /**
90
     * Constructs a GrlcQuery object by parsing the provided query ID or URI.
91
     *
92
     * @param id The query ID or URI.
93
     * @throws IllegalArgumentException If the ID is null, invalid, or the nanopublication defines multiple queries.
94
     */
95
    private GrlcQuery(String id) {
6✔
96
        if (id == null) {
6✔
97
            throw new IllegalArgumentException("Null value for query ID");
15✔
98
        }
99
        if (TrustyUriUtils.isPotentialTrustyUri(id)) {
9✔
100
            artifactCode = TrustyUriUtils.getArtifactCode(id);
12✔
101
            nanopub = Utils.getNanopub(artifactCode);
15✔
102
            for (Statement st : nanopub.getAssertion()) {
36✔
103
                if (st.getPredicate().equals(RDF.TYPE) && st.getObject().equals(GRLC_QUERY_CLASS)) {
30!
104
                    if (queryUri != null) {
9✔
105
                        throw new IllegalArgumentException("Nanopublication defines more than one query: " + id);
18✔
106
                    }
107
                    queryUri = (IRI) st.getSubject();
15✔
108
                }
109
            }
3✔
110
            if (queryUri == null) {
9✔
111
                throw new IllegalArgumentException("No query found in nanopublication: " + id);
18✔
112
            }
113
            queryId = queryUri.stringValue().replaceFirst("^https?://.*[^A-Za-z0-9-_](RA[A-Za-z0-9-_]{43}[/#][^/#]+)$", "$1").replace("#", "/");
36✔
114
        } else {
115
            if (id.matches("https?://.*[^A-Za-z0-9-_]RA[A-Za-z0-9-_]{43}[/#][^/#]+")) {
12!
116
                queryId = id.replaceFirst("^https?://.*[^A-Za-z0-9-_](RA[A-Za-z0-9-_]{43}[/#][^/#]+)$", "$1").replace("#", "/");
×
117
            } else if (id.matches("RA[A-Za-z0-9-_]{43}[/#][^/#]+")) {
12!
118
                queryId = id;
12✔
119
            } else {
120
                throw new IllegalArgumentException("Not a valid query ID or URI: " + id);
×
121
            }
122
            artifactCode = queryId.replaceFirst("[/#].*$", "");
21✔
123
            nanopub = Utils.getNanopub(artifactCode);
15✔
124
        }
125
        querySuffix = queryId.replaceFirst("^.*[/#]", "");
21✔
126
        for (Statement st : nanopub.getAssertion()) {
36✔
127
            if (!st.getSubject().stringValue().replace("#", "/").endsWith(queryId)) continue;
30!
128
            queryUri = (IRI) st.getSubject();
15✔
129
            if (st.getPredicate().equals(GRLC_HAS_SPARQL) && st.getObject() instanceof Literal objLiteral) {
42!
130
                sparql = objLiteral.stringValue();
15✔
131
            } else if (st.getPredicate().equals(GRLC_HAS_ENDPOINT) && st.getObject() instanceof IRI objIri) {
42!
132
                endpoint = objIri;
12✔
133
            } else if (st.getPredicate().equals(RDFS.LABEL)) {
15✔
134
                label = st.getObject().stringValue();
18✔
135
            } else if (st.getPredicate().equals(DCTERMS.DESCRIPTION)) {
15✔
136
                description = st.getObject().stringValue();
15✔
137
            }
138
        }
3✔
139

140
        final Set<String> placeholders = new HashSet<>();
12✔
141
        ParsedQuery query = new SPARQLParser().parseQuery(sparql, null);
24✔
142
        try {
143
            query.getTupleExpr().visitChildren(new AbstractSimpleQueryModelVisitor<Exception>() {
42✔
144

145
                @Override
146
                public void meet(Var node) throws Exception {
147
                    super.meet(node);
9✔
148
                    if (!node.isConstant() && !node.isAnonymous() && node.getName().startsWith("_")) {
33!
149
                        placeholders.add(node.getName());
×
150
                    }
151
                }
3✔
152

153
            });
154
        } catch (Exception e) {
×
155
            throw new RuntimeException(e);
×
156
        }
3✔
157
        List<String> placeholdersListPre = new ArrayList<>(placeholders);
15✔
158
        Collections.sort(placeholdersListPre);
6✔
159
        placeholdersList = Collections.unmodifiableList(placeholdersListPre);
12✔
160
    }
3✔
161

162
    /**
163
     * Returns the unique query ID.
164
     *
165
     * @return The query ID.
166
     */
167
    public String getQueryId() {
168
        return queryId;
9✔
169
    }
170

171
    /**
172
     * Returns the artifact code extracted from the nanopublication.
173
     *
174
     * @return The artifact code.
175
     */
176
    public String getArtifactCode() {
177
        return artifactCode;
9✔
178
    }
179

180
    /**
181
     * Returns the suffix of the query.
182
     *
183
     * @return The query suffix.
184
     */
185
    public String getQuerySuffix() {
186
        return querySuffix;
9✔
187
    }
188

189
    /**
190
     * Returns the nanopublication containing the query.
191
     *
192
     * @return The nanopublication.
193
     */
194
    public Nanopub getNanopub() {
195
        return nanopub;
9✔
196
    }
197

198
    /**
199
     * Returns the URI of the query.
200
     *
201
     * @return The query URI.
202
     */
203
    public IRI getQueryUri() {
204
        return queryUri;
9✔
205
    }
206

207
    /**
208
     * Returns the SPARQL query string.
209
     *
210
     * @return The SPARQL query.
211
     */
212
    public String getSparql() {
213
        return sparql;
9✔
214
    }
215

216
    /**
217
     * Returns the endpoint URI for the query.
218
     *
219
     * @return The endpoint URI.
220
     */
221
    public IRI getEndpoint() {
222
        return endpoint;
9✔
223
    }
224

225
    /**
226
     * Returns the label of the query.
227
     *
228
     * @return The query label.
229
     */
230
    public String getLabel() {
231
        return label;
9✔
232
    }
233

234
    /**
235
     * Returns the description of the query.
236
     *
237
     * @return The query description.
238
     */
239
    public String getDescription() {
240
        return description;
9✔
241
    }
242

243
    /**
244
     * Returns a list of placeholders in the query.
245
     *
246
     * @return The list of placeholders.
247
     */
248
    public List<String> getPlaceholdersList() {
249
        return placeholdersList;
9✔
250
    }
251

252
    /**
253
     * Creates a list of query parameter fields for the placeholders in the query.
254
     *
255
     * @param markupId The markup ID for the fields.
256
     * @return A list of query parameter fields.
257
     */
258
    public List<QueryParamField> createParamFields(String markupId) {
259
        List<QueryParamField> l = new ArrayList<>();
12✔
260
        for (String s : placeholdersList) {
21!
261
            l.add(new QueryParamField(markupId, s));
×
262
        }
×
263
        return l;
6✔
264
    }
265

266
}
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