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

knowledgepixels / nanodash / 17678939499

12 Sep 2025 03:28PM UTC coverage: 13.777% (-0.01%) from 13.79%
17678939499

push

github

tkuhn
fix: Refreshing of Spaces

433 of 3982 branches covered (10.87%)

Branch coverage included in aggregate %.

1112 of 7232 relevant lines covered (15.38%)

0.68 hits per line

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

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

3
import java.io.Serializable;
4
import java.util.ArrayList;
5
import java.util.Collections;
6
import java.util.HashMap;
7
import java.util.HashSet;
8
import java.util.List;
9
import java.util.Map;
10
import java.util.Set;
11

12
import org.eclipse.rdf4j.model.IRI;
13
import org.eclipse.rdf4j.model.Literal;
14
import org.eclipse.rdf4j.model.Statement;
15
import org.eclipse.rdf4j.model.vocabulary.DCTERMS;
16
import org.eclipse.rdf4j.model.vocabulary.RDF;
17
import org.eclipse.rdf4j.model.vocabulary.RDFS;
18
import org.eclipse.rdf4j.query.algebra.Var;
19
import org.eclipse.rdf4j.query.algebra.helpers.AbstractSimpleQueryModelVisitor;
20
import org.eclipse.rdf4j.query.parser.ParsedQuery;
21
import org.eclipse.rdf4j.query.parser.sparql.SPARQLParser;
22
import org.nanopub.Nanopub;
23
import org.slf4j.Logger;
24
import org.slf4j.LoggerFactory;
25

26
import com.knowledgepixels.nanodash.component.QueryParamField;
27

28
import net.trustyuri.TrustyUriUtils;
29

30
/**
31
 * Represents a GRLC query extracted from a nanopublication.
32
 * This class parses the query details, including SPARQL, endpoint, label, description, and placeholders.
33
 */
34
public class GrlcQuery implements Serializable {
35

36
    private static final Logger logger = LoggerFactory.getLogger(GrlcQuery.class);
3✔
37

38
    private static Map<String, GrlcQuery> instanceMap = new HashMap<>();
4✔
39

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

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

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

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

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

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

137
        final Set<String> placeholders = new HashSet<>();
4✔
138
        ParsedQuery query = new SPARQLParser().parseQuery(sparql, null);
8✔
139
        query.getTupleExpr().visitChildren(new AbstractSimpleQueryModelVisitor<>() {
14✔
140

141
            @Override
142
            public void meet(Var node) throws RuntimeException {
143
                super.meet(node);
3✔
144
                if (!node.isConstant() && !node.isAnonymous() && node.getName().startsWith("_")) {
11!
145
                    placeholders.add(node.getName());
×
146
                }
147
            }
1✔
148

149
        });
150
        List<String> placeholdersListPre = new ArrayList<>(placeholders);
5✔
151
        Collections.sort(placeholdersListPre);
2✔
152
        placeholdersList = Collections.unmodifiableList(placeholdersListPre);
4✔
153
    }
1✔
154

155
    /**
156
     * Returns the unique query ID.
157
     *
158
     * @return The query ID.
159
     */
160
    public String getQueryId() {
161
        return queryId;
3✔
162
    }
163

164
    /**
165
     * Returns the artifact code extracted from the nanopublication.
166
     *
167
     * @return The artifact code.
168
     */
169
    public String getArtifactCode() {
170
        return artifactCode;
3✔
171
    }
172

173
    /**
174
     * Returns the suffix of the query.
175
     *
176
     * @return The query suffix.
177
     */
178
    public String getQuerySuffix() {
179
        return querySuffix;
3✔
180
    }
181

182
    /**
183
     * Returns the nanopublication containing the query.
184
     *
185
     * @return The nanopublication.
186
     */
187
    public Nanopub getNanopub() {
188
        return nanopub;
3✔
189
    }
190

191
    /**
192
     * Returns the URI of the query.
193
     *
194
     * @return The query URI.
195
     */
196
    public IRI getQueryUri() {
197
        return queryUri;
3✔
198
    }
199

200
    /**
201
     * Returns the SPARQL query string.
202
     *
203
     * @return The SPARQL query.
204
     */
205
    public String getSparql() {
206
        return sparql;
3✔
207
    }
208

209
    /**
210
     * Returns the endpoint URI for the query.
211
     *
212
     * @return The endpoint URI.
213
     */
214
    public IRI getEndpoint() {
215
        return endpoint;
3✔
216
    }
217

218
    /**
219
     * Returns the label of the query.
220
     *
221
     * @return The query label.
222
     */
223
    public String getLabel() {
224
        return label;
3✔
225
    }
226

227
    /**
228
     * Returns the description of the query.
229
     *
230
     * @return The query description.
231
     */
232
    public String getDescription() {
233
        return description;
3✔
234
    }
235

236
    /**
237
     * Returns a list of placeholders in the query.
238
     *
239
     * @return The list of placeholders.
240
     */
241
    public List<String> getPlaceholdersList() {
242
        return placeholdersList;
3✔
243
    }
244

245
    /**
246
     * Creates a list of query parameter fields for the placeholders in the query.
247
     *
248
     * @param markupId The markup ID for the fields.
249
     * @return A list of query parameter fields.
250
     */
251
    public List<QueryParamField> createParamFields(String markupId) {
252
        List<QueryParamField> l = new ArrayList<>();
4✔
253
        for (String s : placeholdersList) {
7!
254
            l.add(new QueryParamField(markupId, s));
×
255
        }
×
256
        return l;
2✔
257
    }
258

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