Ontotext-AD/graphdb.js

Select/Construct query does not work on the TransactionalRepositoryClient

Closed this issue · 5 comments

Library version [3.0.1]

Node.js version [18]

Describe the bug
Select/Construct query does not work on transactional-repository-client.

To Reproduce
Simply start a transaction and send any construct query.

const client: TransactionalRepositoryClient = await repository.beginTransaction();
client.registerParser(new JsonLDParser());
const query = `construct where {?s ?p ?o.} limit 1 `
const payload = new GetQueryPayload()
      .setQuery(query)
      .setQueryType(QueryType.CONSTRUCT)
      .setResponseType(RDFMimeType.JSON_LD)
      .setInference(inference)
const stream = await repository.query(payload);
stream.on('data', (bindings) => {
  // the bindings stream converted to data objects with the registered parser
});
stream.on('end', () => {
  // handle end of the stream
});
await client.commit();

Expected behavior
Execute the query without any error.

Additional context
TransactionalRepositoryClient.query(...) is not implemented correctly.
The following code fixes this:

query(payload) {
  const serviceRequest = this.queryService.query(payload);
  // The body should be the plain query and the 'content-type' header should be 'application/sparql-query'.
  serviceRequest.getHttpRequestBuilder().setData(payload.payload.query)
  serviceRequest.getHttpRequestBuilder().setHeaders({...serviceRequest.getHttpRequestBuilder().getHeaders(), 'Content-Type': 'application/sparql-query'})
  this.decorateServiceRequest(serviceRequest, 'QUERY');
  return serviceRequest.execute();
}

The fix is also implemented here.

Thank you @LesterLyu. We will investigate and fix the issue.

Hi @LesterLyu,

This is not a bug.
The GetQueryPayload has a default ContentType set in it's constructor. It is the QueryContentType.X_WWW_FORM_URLENCODED.
If you content is a query string, you must set the content type of the GetQueryPayload object to QueryContentType.SPARQL_QUERY using the setContentType method.

So your code should be:

  const client = getRepositoryClient();
  const transactionClient = await client.beginTransaction();
  transactionClient.registerParser(new JsonLDParser());
  const query = `construct where {?s ?p ?o.} limit 1 `
  const payload = new GetQueryPayload()
      .setQuery(query)
      .setQueryType(QueryType.CONSTRUCT)
      .setResponseType(RDFMimeType.JSON_LD)
      .setInference(true)
      .setContentType(QueryContentType.SPARQL_QUERY);

  const result = [];
  const stream = await client.query(payload);

  stream.on('data', (bindings) => {
      result.push(bindings);
  });
  stream.on('end', () => {
      res.send(Buffer.concat(result).toString('utf8').trim());
  });
  await transactionClient.commit();

In the docs about the GetQueryPayload:

Content type parameter which is used for setting the Content-Type http header is optional and by default application/x-www-form-urlencoded type is set.

In the fix you have made, you hardcode it to `application/sparql-query` for every request.

I will close the issue. Please try the above way of making the transactional query and if you experience any difficulty we will reopen it.

I found another issue, setInference(false) does not work when it is used in a transactionClient

Hello @LesterLyu. Thank you for reporting this issue. If you don't mind I'll split it as a separate issue so we can track it more easily.

#202