private static bool HasAllColumns(DatabaseMeasurementInfo meta, List <string> columns) { foreach (var fieldOrTag in columns) { if (fieldOrTag != InfluxConstants.KeyColumn && fieldOrTag != InfluxConstants.TimeColumn && !meta.Tags.Contains(fieldOrTag) && !meta.Fields.Contains(fieldOrTag)) { return(false); } } return(true); }
internal async Task <DatabaseMeasurementInfo> GetMetaInformationAsync(string db, string measurementName, TimeSpan?expiration) { var key = new DatabaseMeasurementInfoKey(db, measurementName); DatabaseMeasurementInfo info; lock (_seriesMetaCache) { _seriesMetaCache.TryGetValue(key, out info); } var now = DateTime.UtcNow; if (info != null) { if (!expiration.HasValue) // info never expires { return(info); } if (now - info.Timestamp < expiration.Value) // has not expired { return(info); } } // has expired or never existed, lets retrieve it // get metadata information from the store var tagsResult = await this.ShowTagKeysAsync(db, measurementName).ConfigureAwait(false); var tags = tagsResult.Series.FirstOrDefault()?.Rows; info = new DatabaseMeasurementInfo(now); if (tags != null) { foreach (var row in tags) { info.Tags.Add(row.TagKey); } } lock (_seriesMetaCache) { _seriesMetaCache[key] = info; } return(info); }
internal async Task <DatabaseMeasurementInfo> GetMetaInformationAsync(string db, string measurementName, bool forceRefresh) { var key = new DatabaseMeasurementInfoKey(db, measurementName); DatabaseMeasurementInfo info; if (!forceRefresh) { lock ( _seriesMetaCache ) { if (_seriesMetaCache.TryGetValue(key, out info)) { return(info); } } } // get metadata information from the store var fieldTask = ShowFieldKeysAsync(db, measurementName); var tagTask = ShowTagKeysAsync(db, measurementName); await Task.WhenAll(fieldTask, tagTask).ConfigureAwait(false); var fields = fieldTask.Result.Series.FirstOrDefault()?.Rows; var tags = tagTask.Result.Series.FirstOrDefault()?.Rows; info = new DatabaseMeasurementInfo(); if (fields != null) { foreach (var row in fields) { info.Fields.Add(row.FieldKey); } } if (tags != null) { foreach (var row in tags) { info.Tags.Add(row.TagKey); } } lock ( _seriesMetaCache ) { _seriesMetaCache[key] = info; } return(info); }
private static async Task AddValuesToInfluxSeriesByInterfaceAsync <TInfluxRow, TTimestamp>( InfluxSeries <TInfluxRow> influxSerie, SeriesResult series, InfluxClient client, string db, bool allowMetadataQuerying, InfluxRowTypeInfo <TInfluxRow> propertyMap, InfluxQueryOptions options, ITimestampParser <TTimestamp> timestampParser) where TInfluxRow : IInfluxRow <TTimestamp>, new() { // Values will be null, if there are no entries in the result set if (series.Values != null) { var precision = options.Precision; var name = series.Name; var columns = series.Columns; var setters = new Action <TInfluxRow, string, object> [columns.Count]; var dataPoints = new List <TInfluxRow>(); // Get metadata information about the measurement we are querying, as we dont know // which columns are tags/fields otherwise DatabaseMeasurementInfo meta = null; if (allowMetadataQuerying) { meta = await client.GetMetaInformationAsync(db, name, options.MetadataExpiration).ConfigureAwait(false); } for (int i = 0; i < columns.Count; i++) { var columnName = columns[i]; if (!allowMetadataQuerying) { setters[i] = (row, fieldName, value) => row.SetField(fieldName, value); } else if (columnName == InfluxConstants.TimeColumn) { setters[i] = (row, timeName, value) => row.SetTimestamp(timestampParser.ToTimestamp(options.Precision, value)); } else if (meta.Tags.Contains(columnName)) { setters[i] = (row, tagName, value) => row.SetTag(tagName, (string)value); } else { setters[i] = (row, fieldName, value) => row.SetField(fieldName, value); } } // constructs the IInfluxRows using the IInfluxRow interface foreach (var values in series.Values) { var dataPoint = new TInfluxRow(); propertyMap.SetMeasurementName(name, dataPoint); // go through all values that are stored as a List<List<object>> for (int i = 0; i < values.Count; i++) { var value = values[i]; // TODO: What about NULL values? Are they treated as empty strings or actual nulls? if (value != null) { setters[i](dataPoint, columns[i], value); } } dataPoints.Add(dataPoint); } influxSerie.Rows.AddRange(dataPoints); } }
private async static Task <InfluxResultSet <TInfluxRow> > CreateBasedOnInterfaceAsync <TInfluxRow>( InfluxClient client, QueryResult queryResult, string db, bool isExclusivelyFields) where TInfluxRow : new() { // In this case, we will contruct objects based on the IInfluxRow interface List <InfluxResult <TInfluxRow> > results = new List <InfluxResult <TInfluxRow> >(); foreach (var result in queryResult.Results) { var influxSeries = new List <InfluxSeries <TInfluxRow> >(); if (result.Series != null && result.Error == null) { foreach (var series in result.Series) { var name = series.Name; var columns = series.Columns; var dataPoints = new List <TInfluxRow>(); var setters = new Action <IInfluxRow, string, object> [columns.Count]; // Values will be null, if there are no entries in the result set if (series.Values != null) { // Get metadata information about the measurement we are querying, as we dont know // which columns are tags/fields otherwise DatabaseMeasurementInfo meta = null; if (!isExclusivelyFields) { // get the required metadata meta = await client.GetMetaInformationAsync(db, name, false).ConfigureAwait(false); // check that we have all columns, otherwise call method again bool hasAllColumnsAndTags = HasAllColumns(meta, columns); if (!hasAllColumnsAndTags) { // if we dont have all columns, attempt to query the metadata again (might have changed since last query) meta = await client.GetMetaInformationAsync(db, name, false).ConfigureAwait(false); hasAllColumnsAndTags = HasAllColumns(meta, columns); // if we still dont have all columns, we cant do anything, throw exception if (!hasAllColumnsAndTags) { throw new InfluxException(Errors.IndeterminateColumns); } } } for (int i = 0; i < columns.Count; i++) { var columnName = columns[i]; if (isExclusivelyFields) { setters[i] = (row, fieldName, value) => row.SetField(fieldName, value); } else if (columnName == InfluxConstants.TimeColumn) { setters[i] = (row, timeName, value) => row.SetTimestamp(long.Parse(value.ToString())); } else if (meta.Tags.Contains(columnName)) { setters[i] = (row, tagName, value) => row.SetTag(tagName, (string)value); } else if (meta.Fields.Contains(columnName)) { setters[i] = (row, fieldName, value) => row.SetField(fieldName, value); } else { throw new InfluxException(string.Format(Errors.InvalidColumn, columnName)); } } // constructs the IInfluxRows using the IInfluxRow interface foreach (var values in series.Values) { var dataPoint = (IInfluxRow) new TInfluxRow(); // if we implement IHaveMeasurementName, set the measurement name on the IInfluxRow as well var seriesDataPoint = dataPoints as IHaveMeasurementName; if (seriesDataPoint != null) { seriesDataPoint.MeasurementName = name; } // go through all values that are stored as a List<List<object>> for (int i = 0; i < values.Count; i++) { var value = values[i]; // TODO: What about NULL values? Are they treated as empty strings or actual nulls? if (value != null) { setters[i](dataPoint, columns[i], value); } } dataPoints.Add((TInfluxRow)dataPoint); } } // create new dictionary, with correct typing var tags = series.Tags?.ToDictionary(x => x.Key, x => x.Value == string.Empty ? null : (object)x.Value) ?? null; influxSeries.Add(new InfluxSeries <TInfluxRow>(name, dataPoints, tags)); } } results.Add(new InfluxResult <TInfluxRow>(influxSeries, result.Error ?? (result.Series == null ? Errors.UnexpectedQueryResult : null))); } return(new InfluxResultSet <TInfluxRow>(results)); }