private string GetSeriesNames(IEnumerable<string> sensorSerials, ReadingsFetchFilter filter)
 {
     var seriesNames = sensorSerials.Select(p => GetSeriesName(p, filter)).Distinct();
     return String.Join(", ", seriesNames);
 }
        /// <summary>
        /// Fetches readings for single or multiple sensores in a batched query. If the batched query fails,
        /// a fallback query which fetches readings sensor per sensor will get executed.
        /// </summary>
        /// <param name="filter">Fetch filter.</param>
        /// <returns></returns>
        public async Task<IList<Serie>> GetReadings(ReadingsFetchFilter filter)
        {
            IList<Serie> seriesResults = new List<Serie>();
            var errorOccured = false;

            try
            {
                var query = GetQuery(filter.SensorSerials, filter);
                var result = await QueryReading(query);
                seriesResults = result.ToList();
            }
            catch (Exception e)
            {
                errorOccured = true;
            }

            if (errorOccured)
                seriesResults = await GetReadingsOneByOneFallback(filter);

            seriesResults.ToList().ForEach(CleanUpSensorSerial);
            return seriesResults;
        }
        private string GetSeriesName(string sensorSerial, ReadingsFetchFilter filter)
        {
            var isResolutionQuery = IsResolutionQuery(filter.Resolution);
            var seriesName = String.Format("{0}.{1}", _influxDbReadingSeries, sensorSerial);

            if (isResolutionQuery)
                seriesName = String.Format("{0}.{1}", filter.Resolution, seriesName);

            return seriesName;
        }
 /// <summary>
 /// Gets base query for fetching sensors.
 /// 
 /// NOTE: SHOULD ONLY BE CALLED FROM GetQuery methods, and not any other "higher-level" methods from the chain.
 /// </summary>
 /// <param name="seriesToQuery">Series to query already prepared as a comma delimited string array.</param>
 /// <param name="filter">Readings fetch filter.</param>
 /// <returns>Base query string.</returns>
 private string GetBaseQuery(string seriesToQuery, ReadingsFetchFilter filter)
 {
     return String.Format("select {0} from {1} where time > '{2}' and time < '{3}'", filter.Metric, seriesToQuery, filter.TimeFrom, filter.TimeTo);
 }
 private string GetQuery(IEnumerable<string> sensorSerials, ReadingsFetchFilter filter)
 {
     var seriesNames = GetSeriesNames(sensorSerials, filter);
     return GetBaseQuery(seriesNames, filter);
 }
 private string GetQuery(string sensorSerial, ReadingsFetchFilter filter)
 {
     var seriesName = GetSeriesName(sensorSerial, filter);
     return GetBaseQuery(seriesName, filter);
 }
        /// <summary>
        /// Fetches readings sensor per sensor. If fetch is for a single sensor, it will rethrow the exception, if not,
        /// it will return, an empty Serie List. Because of this, batched queries will not "fail". They simply won't
        /// include readings for that sensor (for example on custom charts, or in AQR report). In case of a single sensor
        /// fetch - we actually want to know that the sensor is "faulty".
        /// </summary>
        /// <param name="filter">Fetch filter.</param>
        /// <returns>Async task which returns a list of seies.</returns>
        private async Task<IList<Serie>> GetReadingsOneByOneFallback(ReadingsFetchFilter filter)
        {
            IList<IList<Serie>> seriesList = new List<IList<Serie>>();
            var isSingleFetch = filter.SensorSerials.Count() == 1;

            foreach (var sensorSerial in filter.SensorSerials)
            {
                var query = GetQuery(sensorSerial, filter);
                try
                {
                    var series = await QueryReading(query);
                    seriesList.Add(series.ToList());
                }
                catch (Exception)
                {
                    if (isSingleFetch)
                    {
                        throw;
                    }
                    else
                    {
                        seriesList.Add(new List<Serie>());
                    }
                }
            }

            return FlattenSeriesResult(seriesList);
        }