Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multi query with multi result #1

Merged
merged 5 commits into from
Dec 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Product>AdysTech.InfluxDB.Client.Net</Product>
<Company>AdysTech</Company>
<Authors>AdysTech;mvadu;Herrenknecht AG</Authors>
<Version>0.9.0.1</Version>
<Version>0.9.0.2</Version>
<PackageId>AdysTech.InfluxDB.Client.Net.Core.HK</PackageId>
<Copyright>© AdysTech 2016-2019</Copyright>
<PackageProjectUrl>https://github.com/AdysTech/InfluxDB.Client.Net</PackageProjectUrl>
Expand Down Expand Up @@ -45,6 +45,7 @@ It currently supports
<Compile Include="..\DataStructures\InfluxMeasurement.cs" Link="DataStructures\InfluxMeasurement.cs" />
<Compile Include="..\DataStructures\InfluxRetentionPolicy.cs" Link="DataStructures\InfluxRetentionPolicy.cs" />
<Compile Include="..\DataStructures\InfluxSeries.cs" Link="DataStructures\InfluxSeries.cs" />
<Compile Include="..\DataStructures\InfluxResult.cs" Link="DataStructures\InfluxResult.cs" />
<Compile Include="..\DataStructures\InfluxValueField.cs" Link="DataStructures\InfluxValueField.cs" />
<Compile Include="..\DataStructures\IInfluxValueField.cs" Link="DataStructures\IInfluxValueField.cs" />
<Compile Include="..\DataStructures\ServiceUnavailableException.cs" Link="DataStructures\ServiceUnavailableException.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
<Compile Include="..\DataStructures\InfluxRetentionPolicy.cs">
<Link>DataStructures\InfluxRetentionPolicy.cs</Link>
</Compile>
<Compile Include="..\DataStructures\InfluxResult.cs">
<Link>DataStructures\InfluxResult.cs</Link>
</Compile>
<Compile Include="..\DataStructures\InfluxSeries.cs">
<Link>DataStructures\InfluxSeries.cs</Link>
</Compile>
Expand Down
47 changes: 47 additions & 0 deletions src/DataStructures/InfluxDBClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,53 @@ public async Task<List<IInfluxSeries>> QueryMultiSeriesAsync(string dbName, stri
return null;
}

/// <summary>
/// Queries Influx DB and gets multiple time series data back. Ideal for fetching measurement values.
/// The return list is of InfluxResult, that contains multiple InfluxSeries and each element in there will have properties named after columns in series.
/// </summary>
/// <param name="dbName">Name of the database</param>
/// <param name="measurementQuery">Query text, Only results with single series are supported for now</param>
/// <param name="precision">epoch precision of the data set</param>
/// <returns>List of InfluxResult that contains multiple InfluxSeries.</returns>
/// <seealso cref="InfluxResult"/>
public async Task<List<InfluxResult>> QueryMultiSeriesMultiResultAsync(string dbName, string measurementQuery, string retentionPolicy = null, TimePrecision precision = TimePrecision.Nanoseconds)
{
var endPoint = new Dictionary<string, string>() { { "db", dbName }, { "q", measurementQuery }, { "epoch", precisionLiterals[(int)precision] } };

if (retentionPolicy != null)
{
endPoint.Add("rp", retentionPolicy);
}
var response = await GetAsync(endPoint, HttpCompletionOption.ResponseHeadersRead);

if (response == null) throw new ServiceUnavailableException();
if (response.StatusCode == HttpStatusCode.OK)
{
var multiResult = new List<InfluxResult>();
var rawResult = JsonConvert.DeserializeObject<InfluxResponse>(await response.Content.ReadAsStringAsync());
var partialResult = rawResult.Results?.Any(r => r.Partial);

rawResult?.Results?.ForEach(currentResult =>
{
if (currentResult?.Series != null)
{
var influxResult = new InfluxResult();
influxResult.StatementID = currentResult.StatementID;
influxResult.Partial = currentResult.Partial;

foreach (var series in currentResult.Series)
influxResult.InfluxSeries = GetInfluxSeries(precision, series, partialResult);

if(influxResult.InfluxSeries.Entries.Any())
multiResult.Add(influxResult);
}
});

return multiResult;
}
return null;
}

/// <summary>
/// Queries Influx DB and gets a time series data back. Ideal for fetching measurement values.
/// The return list is of InfluxSeries, and each element in there will have properties named after columns in series
Expand Down
20 changes: 20 additions & 0 deletions src/DataStructures/InfluxResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace AdysTech.InfluxDB.Client.Net
{
/// <summary>
/// Extend the results returned by Query end point of the InfluxDB engine with the informations of Partial
/// and StatementID.
/// </summary>
public class InfluxResult
{
public int StatementID { get; set; }

public IInfluxSeries InfluxSeries { get; set; }

/// <summary>
/// True if the influx query was answered with a partial response due to e.g. exceeding a configured
/// max-row-limit in the InfluxDB. As we don't know which series was truncated by InfluxDB, all series
/// of the response will be flagged with Partial=true.
/// </summary>
public bool Partial { get; set; }
}
}
10 changes: 10 additions & 0 deletions src/Interfaces/IInfluxDBClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ public interface IInfluxDBClient
/// <returns>List of InfluxSeries</returns>
Task<List<IInfluxSeries>> QueryMultiSeriesAsync(string dbName, string measurementQuery, string retentionPolicy = null, TimePrecision precision = TimePrecision.Nanoseconds);

/// <summary>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auch den Kommentar solltest Du noch anpassen.

/// Queries Influx DB and gets multiple time series data back. Ideal for fetching measurement values.
/// The return list is of InfluxResult, that contains multiple InfluxSeries and each element in there will have properties named after columns in series.
/// </summary>
/// <param name="dbName">Name of the database</param>
/// <param name="measurementQuery">Query text, Supports multi series results</param>
/// <param name="retentionPolicy">retention policy containing the measurement</param>
/// <param name="precision">epoch precision of the data set</param>
/// <returns>List of InfluxResult that contains multiple InfluxSeries.</returns>
Task<List<InfluxResult>> QueryMultiSeriesMultiResultAsync(string dbName, string measurementQuery, string retentionPolicy = null, TimePrecision precision = TimePrecision.Nanoseconds);

/// <summary>
/// Queries Influx DB and gets a time series data back. Ideal for fetching measurement values.
Expand Down
53 changes: 53 additions & 0 deletions tests/InfluxDBClientTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,60 @@ public async Task TestQueryMultiSeriesAsync()
Assert.IsTrue(r != null, "QueryMultiSeriesAsync retunred null or invalid data");
}

[TestMethod, TestCategory("Query")]
public async Task TestQueryMultiSeriesMultiResultAsync()
{
var measurement = "QueryMultiSeriesMultiTest";
var client = new InfluxDBClient(influxUrl, dbUName, dbpwd);
await client.CreateDatabaseAsync(dbName);
await client.DropMeasurementAsync(new InfluxDatabase(dbName), new InfluxMeasurement(measurement));
var points = new List<IInfluxDatapoint>();

var today = DateTime.Now.ToShortDateString();
var now = DateTime.UtcNow;
var nowString = DateTime.Now.ToShortTimeString();

for (int i = 0; i < 1; i++)
{
var valMixed = new InfluxDatapoint<InfluxValueField>();
valMixed.Tags.Add("TestDate", today);
valMixed.Tags.Add("TestTime", nowString);
valMixed.UtcTimestamp = now + TimeSpan.FromMilliseconds(i * 100);
valMixed.Fields.Add("Open", new InfluxValueField(DataGen.RandomDouble()));
valMixed.Fields.Add("High", new InfluxValueField(DataGen.RandomInt()));
valMixed.Fields.Add("Low", new InfluxValueField(DataGen.RandomDouble()));
valMixed.Fields.Add("Close", new InfluxValueField(DataGen.RandomDouble()));
valMixed.Fields.Add("Volume", new InfluxValueField(DataGen.RandomDouble()));

valMixed.MeasurementName = measurement;
valMixed.Precision = TimePrecision.Nanoseconds;
points.Add(valMixed);
}

await client.PostPointsAsync(dbName, points, 10000);

Stopwatch s = new Stopwatch();
s.Start();
var r = await client.QueryMultiSeriesMultiResultAsync(dbName, $"SELECT \"Open\", \"High\" FROM {measurement} Limit 1; SELECT \"Low\" FROM {measurement} Limit 1;");

s.Stop();
Debug.WriteLine($"Elapsed{s.ElapsedMilliseconds}");
Assert.IsTrue(r != null, "QueryMultiSeriesAsync retunred null or invalid data");
var firstResult = new Dictionary<string, object>(r[0].InfluxSeries.Entries[0]);
var secondResult = new Dictionary<string, object>(r[1].InfluxSeries.Entries[0]);

var valueActual = Convert.ToDouble(firstResult["Open"].ToString().Replace('.', ','));
var valueExpected = Convert.ToDouble(((InfluxDatapoint<InfluxValueField>)points[0]).Fields["Open"].Value);
Assert.IsTrue(Math.Abs(valueExpected - valueActual) < 0.000001);

valueActual = Convert.ToInt32(firstResult["High"].ToString().Replace('.', ','));
valueExpected = Convert.ToInt32(((InfluxDatapoint<InfluxValueField>)points[0]).Fields["High"].Value);
Assert.IsTrue(Math.Abs(valueExpected - valueActual) < 0.000001);

valueActual = Convert.ToDouble(secondResult["Low"].ToString().Replace('.', ','));
valueExpected = Convert.ToDouble(((InfluxDatapoint<InfluxValueField>)points[0]).Fields["Low"].Value);
Assert.IsTrue(Math.Abs(valueExpected - valueActual) < 0.000001);
}

[TestMethod, TestCategory("Post")]
public async Task TestPostPointsAsync()
Expand Down