Skip to content

Commit

Permalink
feat: updates service accept header to application/json (#733)
Browse files Browse the repository at this point in the history
* feat: updates service accept header to application/json

* chore: remove built-in value extractor methods

* feat: makes Accept header in InfluxQLQueryService dynamic.

* chore: add license to new test

* feat: adds methods queryCSV and queryJSON to InfluxQLQueryAPI and rollsback query method to previous signature.

* test: adds unit tests for InfluxQLQuery

* chore: improves InfluxQLQuery.setAcceptHeader

* chore: cleanup imports

* docs: updates CHANGELOG.md and InfluxQLExample.java

* fix: fixes #744 and possible NPEs

* test: adds test of empty resultsfrom server

* chore: adds check for null values array in JSON desrializer

* chore: move log warning to correct branch

* chore: revert default InfluxQL serializer to CSV to keep backward compatibility.

* chore: update InfluxQL example

* docs: updates CHANGELOG.md a recent javadoc.
  • Loading branch information
karel-rehor authored Jul 19, 2024
1 parent d426da6 commit 7b39e0c
Show file tree
Hide file tree
Showing 12 changed files with 1,239 additions and 39 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
## 7.2.0 [unreleased]

### Features

- [#719](https://github.com/influxdata/influxdb-client-java/issues/719): `InfluxQLQueryService` header changes.
- `Accept` header can now be defined when making `InfluxQLQuery` calls. Supoorted MIME types:
- `application/csv`
- `application/json`
- The value `application/csv` remains the default.
- :warning: Side effects of these changes:
- When using `application/json`, timestamp fields are returned in the [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) format unless `InfluxQLQuery.setPrecision()` has been previously called, in which case they are returned in the POSIX epoch format.
- When using `application/csv`, timestamp fields are returned in the POSIX epoch format.
- Convenience methods have been added to `InfluxQLQueryAPI` to simplify expressly specifying JSON or CSV calls.
- Epoch timestamps can also be ensured by calling `InfluxQLQuery.setPrecision()` before executing a query call.
- An `AcceptHeader` field has also been added to the `InfluxQLQuery` class and can be set with `InfluxQLQuery.setAcceptHeader()`.
- More information from the server side:
- [Generated REST API Documentation](https://docs.influxdata.com/influxdb/v2/api/v1-compatibility/#operation/PostQueryV1)
- [Influx 1.1 query compatibility](https://docs.influxdata.com/influxdb/latest/reference/api/influxdb-1x/query/)
- See the updated InfluxQLExample

### Bug Fixes

1. [#744](https://github.com/influxdata/influxdb-client-java/issues/744) following an `InfluxQLQueryAPI.query()` call, empty results from the server no longer result in a `null` result value.

### Dependencies

Update dependencies:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,21 @@ protected void query(@Nonnull final Call<ResponseBody> query,
Consumer<ResponseBody> bodyConsumer = body -> {
try {
BufferedSource source = body.source();

//
// Source has data => parse
//
while (source.isOpen() && !source.exhausted() && !cancellable.wasCancelled) {

// already exhausted - empty or very short response
if (source.exhausted()) {
LOG.log(Level.WARNING, String.format("Query %s already exhausted.",
query.request().tag(retrofit2.Invocation.class)
.toString().split(" \\[")[1]
.replace("]", "")));
consumer.accept(cancellable, source);
} else {

//
// Source has data => parse
//
while (source.isOpen() && !source.exhausted() && !cancellable.wasCancelled) {
consumer.accept(cancellable, source);
}
}

if (!cancellable.wasCancelled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@ public Object[] getValues() {
return values;
}
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ public interface InfluxQLQueryService {
* @param zapTraceSpan OpenTracing span context (optional)
* @return response in csv format
*/
@Headers({"Accept:application/csv", "Content-Type:application/x-www-form-urlencoded"})
@Headers({"Content-Type:application/x-www-form-urlencoded"})
@FormUrlEncoded
@POST("query")
Call<ResponseBody> query(
@Field("q") String query,
@Nonnull @Query("db") String db,
@Query("rp") String retentionPolicy,
@Query("epoch") String epoch,
@Header("Zap-Trace-Span") String zapTraceSpan
@Header("Zap-Trace-Span") String zapTraceSpan,
@Header("Accept") String accept
);
}
76 changes: 75 additions & 1 deletion client/src/main/java/com/influxdb/client/InfluxQLQueryApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,34 @@
import com.influxdb.query.InfluxQLQueryResult;

/**
* The <code>InfluxQL</code> can be used with <code>/query compatibility</code> endpoint which uses the
* The <code>InfluxQL</code> API can be used with the <code>/query compatibility</code> endpoint which uses the
* <strong>{@link InfluxQLQuery#getDatabase() database}</strong> and
* <strong>{@link InfluxQLQuery#getRetentionPolicy() retention policy}</strong> specified in the query request to
* map the request to an InfluxDB bucket.
*
* <p>Note that as of release 7.2 queries using the legacy <code>InfluxQL</code> compatible endpoint can specify
* the <code>Accept</code> header MIME type. Two MIME types are supported. </p>
* <ul>
* <li><code>application/csv</code> - client default and legacy value.</li>
* <li><code>application/json</code></li>
* </ul>
*
* <p>The selected <code>Accept</code> header mime type impacts the timestamp format returned from the server.</p>
* <ul>
* <li><code>application/csv</code> returns timestamps in the POSIX epoch format.</li>
* <li><code>application/json</code> returns timestamps as RFC3339 strings.
* <ul>
* <li>Caveat. If <code>InfluxQLQuery.setPrecision()</code> is called before the query is sent, then
* the timestamp will be returned as a POSIX epoch reflecting the desired precision, even when using the
* <code>application/json</code> MIME type.</li>
* </ul>
* </li>
* </ul>
*
* <p>To explicitly choose one or the other MIME type new convenience methods are povided: <code>queryCSV</code>
* and <code>queryJSON</code>. Note that the <code>Accept</code> header MIME type can now also be specified
* when instantiating the {@link com.influxdb.client.domain.InfluxQLQuery} class.</p>
*
* <br>
* For more information, see:
* <ul>
Expand All @@ -46,6 +70,11 @@
* Database and retention policy mapping
* </a>
* </li>
* <li>
* <a href="https://docs.influxdata.com/influxdb/v2/api/v1-compatibility/#operation/PostQueryV1">
* OpenApi generated definitions
* </a>
* </li>
* </ul>
**/
@ThreadSafe
Expand Down Expand Up @@ -92,4 +121,49 @@ InfluxQLQueryResult query(
@Nonnull InfluxQLQuery influxQlQuery,
@Nullable InfluxQLQueryResult.Series.ValueExtractor valueExtractor
);

/**
* Convenience method to specify use of the mime type <code>application/csv</code>
* in the <code>Accept</code> header. Result timestamps will be in the Epoch format.
*
* @param influxQLQuery the query
* @return the result
*/
@Nonnull
InfluxQLQueryResult queryCSV(@Nonnull final InfluxQLQuery influxQLQuery);

/**
* Convenience method to specify use of the mime type <code>application/csv</code>
* in the <code>Accept</code> header. Result timestamps will be in the Epoch format.
*
* @param influxQLQuery the query
* @param valueExtractor a callback, to convert column values
* @return the result
*/
InfluxQLQueryResult queryCSV(@Nonnull final InfluxQLQuery influxQLQuery,
@Nullable InfluxQLQueryResult.Series.ValueExtractor valueExtractor);

/**
* Convenience method to specify use of the mime type <code>application/json</code>
* in the <code>Accept</code> header. Result timestamps will be in the RFC3339 format.
*
* @param influxQLQuery the query
* @return the result
*/
@Nonnull
InfluxQLQueryResult queryJSON(@Nonnull final InfluxQLQuery influxQLQuery);

/**
* Convenience method to specify use of the mime type <code>application/json</code>
* in the <code>Accept</code> header. Result timestamps will be in the RFC3339 format.
*
* @param influxQLQuery the query
* @param valueExtractor a callback, to convert column values
* @return the result
*/
@Nonnull
InfluxQLQueryResult queryJSON(@Nonnull final InfluxQLQuery influxQLQuery,
@Nullable InfluxQLQueryResult.Series.ValueExtractor valueExtractor);


}
57 changes: 57 additions & 0 deletions client/src/main/java/com/influxdb/client/domain/InfluxQLQuery.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
* A InfluxQL query.
*/
public class InfluxQLQuery {

private final String command;
private final String database;
private String retentionPolicy;
private InfluxQLPrecision precision;
private AcceptHeader acceptHeader;

/**
* @param command the InfluxQL command to execute
Expand All @@ -42,6 +44,20 @@ public class InfluxQLQuery {
public InfluxQLQuery(@Nonnull final String command, @Nonnull final String database) {
this.command = command;
this.database = database;
this.acceptHeader = AcceptHeader.CSV;
}

/**
* @param command the InfluxQL command to execute
* @param database the database to run this query against
* @param acceptHeader the <code>Accept</code> header to use in the request
*/
public InfluxQLQuery(@Nonnull final String command,
@Nonnull final String database,
@Nonnull final AcceptHeader acceptHeader) {
this.command = command;
this.database = database;
this.acceptHeader = acceptHeader;
}

/**
Expand Down Expand Up @@ -97,6 +113,29 @@ public InfluxQLQuery setPrecision(@Nullable final InfluxQLPrecision precision) {
return this;
}

/**
* @return the current AcceptHeader used when making queries.
*/
public AcceptHeader getAcceptHeader() {
return acceptHeader;
}

/***
* @param acceptHeader the AcceptHeader to be used when making queries.
* @return this
*/
public InfluxQLQuery setAcceptHeader(final AcceptHeader acceptHeader) {
this.acceptHeader = acceptHeader;
return this;
}

/**
* @return the string value of the AcceptHeader used when making queries.
*/
public String getAcceptHeaderVal() {
return acceptHeader != null ? acceptHeader.getVal() : AcceptHeader.CSV.getVal();
}

/**
* The precision used for the timestamps returned by InfluxQL queries.
*/
Expand Down Expand Up @@ -143,4 +182,22 @@ public static InfluxQLPrecision toTimePrecision(final TimeUnit t) {
}
}
}

/**
* The possible values to be used in the header <code>Accept</code>, when making queries.
*/
public enum AcceptHeader {
JSON("application/json"),
CSV("application/csv");

private final String val;

AcceptHeader(final String val) {
this.val = val;
}

public String getVal() {
return val;
}
}
}
Loading

0 comments on commit 7b39e0c

Please sign in to comment.