Commit 90c3a2b533797af7e523acb54c3c2acc59c05c9c
1 parent
7358b4a7
Improve Jpa Timeseries DAO. Fixed SQL Warning Code: -1003. Issue #925, Issue #397.
Showing
4 changed files
with
205 additions
and
57 deletions
@@ -49,35 +49,52 @@ import static org.thingsboard.server.dao.model.ModelConstants.TS_COLUMN; | @@ -49,35 +49,52 @@ import static org.thingsboard.server.dao.model.ModelConstants.TS_COLUMN; | ||
49 | @IdClass(TsKvCompositeKey.class) | 49 | @IdClass(TsKvCompositeKey.class) |
50 | public final class TsKvEntity implements ToData<TsKvEntry> { | 50 | public final class TsKvEntity implements ToData<TsKvEntry> { |
51 | 51 | ||
52 | - public TsKvEntity() { | ||
53 | - } | 52 | + private static final String SUM = "SUM"; |
53 | + private static final String AVG = "AVG"; | ||
54 | + private static final String MIN = "MIN"; | ||
55 | + private static final String MAX = "MAX"; | ||
54 | 56 | ||
55 | - public TsKvEntity(Long longSumValue, Double doubleSumValue, Long longCountValue, Long doubleCountValue) { | ||
56 | - double sum = 0.0; | ||
57 | - if (longSumValue != null) { | ||
58 | - sum += longSumValue; | ||
59 | - } | ||
60 | - if (doubleSumValue != null) { | ||
61 | - sum += doubleSumValue; | ||
62 | - } | ||
63 | - this.doubleValue = sum / (longCountValue + doubleCountValue); | 57 | + public TsKvEntity() { |
64 | } | 58 | } |
65 | 59 | ||
66 | - public TsKvEntity(Long sumLongValue, Double sumDoubleValue) { | ||
67 | - if (sumDoubleValue != null) { | ||
68 | - this.doubleValue = sumDoubleValue + (sumLongValue != null ? sumLongValue.doubleValue() : 0.0); | ||
69 | - } else { | ||
70 | - this.longValue = sumLongValue; | ||
71 | - } | 60 | + public TsKvEntity(String strValue) { |
61 | + this.strValue = strValue; | ||
72 | } | 62 | } |
73 | 63 | ||
74 | - public TsKvEntity(String strValue, Long longValue, Double doubleValue, boolean max) { | ||
75 | - this.strValue = strValue; | ||
76 | - if (longValue != null && doubleValue != null) { | ||
77 | - this.doubleValue = max ? Math.max(doubleValue, longValue.doubleValue()) : Math.min(doubleValue, longValue.doubleValue()); | ||
78 | - } else { | ||
79 | - this.longValue = longValue; | ||
80 | - this.doubleValue = doubleValue; | 64 | + public TsKvEntity(Long longValue, Double doubleValue, Long longCountValue, Long doubleCountValue, String aggType) { |
65 | + switch (aggType) { | ||
66 | + case AVG: | ||
67 | + double sum = 0.0; | ||
68 | + if (longValue != null) { | ||
69 | + sum += longValue; | ||
70 | + } | ||
71 | + if (doubleValue != null) { | ||
72 | + sum += doubleValue; | ||
73 | + } | ||
74 | + long totalCount = longCountValue + doubleCountValue; | ||
75 | + if (totalCount > 0) { | ||
76 | + this.doubleValue = sum / (longCountValue + doubleCountValue); | ||
77 | + } else { | ||
78 | + this.doubleValue = 0.0; | ||
79 | + } | ||
80 | + break; | ||
81 | + case SUM: | ||
82 | + if (doubleCountValue > 0) { | ||
83 | + this.doubleValue = doubleValue + (longValue != null ? longValue.doubleValue() : 0.0); | ||
84 | + } else { | ||
85 | + this.longValue = longValue; | ||
86 | + } | ||
87 | + break; | ||
88 | + case MIN: | ||
89 | + case MAX: | ||
90 | + if (longCountValue > 0 && doubleCountValue > 0) { | ||
91 | + this.doubleValue = MAX.equals(aggType) ? Math.max(doubleValue, longValue.doubleValue()) : Math.min(doubleValue, longValue.doubleValue()); | ||
92 | + } else if (doubleCountValue > 0) { | ||
93 | + this.doubleValue = doubleValue; | ||
94 | + } else if (longCountValue > 0) { | ||
95 | + this.longValue = longValue; | ||
96 | + } | ||
97 | + break; | ||
81 | } | 98 | } |
82 | } | 99 | } |
83 | 100 |
@@ -161,52 +161,62 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp | @@ -161,52 +161,62 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp | ||
161 | } | 161 | } |
162 | 162 | ||
163 | private ListenableFuture<Optional<TsKvEntry>> findAndAggregateAsync(EntityId entityId, String key, long startTs, long endTs, long ts, Aggregation aggregation) { | 163 | private ListenableFuture<Optional<TsKvEntry>> findAndAggregateAsync(EntityId entityId, String key, long startTs, long endTs, long ts, Aggregation aggregation) { |
164 | - CompletableFuture<TsKvEntity> entity; | 164 | + List<CompletableFuture<TsKvEntity>> entitiesFutures = new ArrayList<>(); |
165 | String entityIdStr = fromTimeUUID(entityId.getId()); | 165 | String entityIdStr = fromTimeUUID(entityId.getId()); |
166 | switch (aggregation) { | 166 | switch (aggregation) { |
167 | case AVG: | 167 | case AVG: |
168 | - entity = tsKvRepository.findAvg( | 168 | + entitiesFutures.add(tsKvRepository.findAvg( |
169 | entityIdStr, | 169 | entityIdStr, |
170 | entityId.getEntityType(), | 170 | entityId.getEntityType(), |
171 | key, | 171 | key, |
172 | startTs, | 172 | startTs, |
173 | - endTs); | 173 | + endTs)); |
174 | 174 | ||
175 | break; | 175 | break; |
176 | case MAX: | 176 | case MAX: |
177 | - entity = tsKvRepository.findMax( | 177 | + entitiesFutures.add(tsKvRepository.findStringMax( |
178 | entityIdStr, | 178 | entityIdStr, |
179 | entityId.getEntityType(), | 179 | entityId.getEntityType(), |
180 | key, | 180 | key, |
181 | startTs, | 181 | startTs, |
182 | - endTs); | 182 | + endTs)); |
183 | + entitiesFutures.add(tsKvRepository.findNumericMax( | ||
184 | + entityIdStr, | ||
185 | + entityId.getEntityType(), | ||
186 | + key, | ||
187 | + startTs, | ||
188 | + endTs)); | ||
183 | 189 | ||
184 | break; | 190 | break; |
185 | case MIN: | 191 | case MIN: |
186 | - entity = tsKvRepository.findMin( | 192 | + entitiesFutures.add(tsKvRepository.findStringMin( |
187 | entityIdStr, | 193 | entityIdStr, |
188 | entityId.getEntityType(), | 194 | entityId.getEntityType(), |
189 | key, | 195 | key, |
190 | startTs, | 196 | startTs, |
191 | - endTs); | ||
192 | - | 197 | + endTs)); |
198 | + entitiesFutures.add(tsKvRepository.findNumericMin( | ||
199 | + entityIdStr, | ||
200 | + entityId.getEntityType(), | ||
201 | + key, | ||
202 | + startTs, | ||
203 | + endTs)); | ||
193 | break; | 204 | break; |
194 | case SUM: | 205 | case SUM: |
195 | - entity = tsKvRepository.findSum( | 206 | + entitiesFutures.add(tsKvRepository.findSum( |
196 | entityIdStr, | 207 | entityIdStr, |
197 | entityId.getEntityType(), | 208 | entityId.getEntityType(), |
198 | key, | 209 | key, |
199 | startTs, | 210 | startTs, |
200 | - endTs); | ||
201 | - | 211 | + endTs)); |
202 | break; | 212 | break; |
203 | case COUNT: | 213 | case COUNT: |
204 | - entity = tsKvRepository.findCount( | 214 | + entitiesFutures.add(tsKvRepository.findCount( |
205 | entityIdStr, | 215 | entityIdStr, |
206 | entityId.getEntityType(), | 216 | entityId.getEntityType(), |
207 | key, | 217 | key, |
208 | startTs, | 218 | startTs, |
209 | - endTs); | 219 | + endTs)); |
210 | 220 | ||
211 | break; | 221 | break; |
212 | default: | 222 | default: |
@@ -214,11 +224,27 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp | @@ -214,11 +224,27 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp | ||
214 | } | 224 | } |
215 | 225 | ||
216 | SettableFuture<TsKvEntity> listenableFuture = SettableFuture.create(); | 226 | SettableFuture<TsKvEntity> listenableFuture = SettableFuture.create(); |
217 | - entity.whenComplete((tsKvEntity, throwable) -> { | 227 | + |
228 | + | ||
229 | + CompletableFuture<List<TsKvEntity>> entities = | ||
230 | + CompletableFuture.allOf(entitiesFutures.toArray(new CompletableFuture[entitiesFutures.size()])) | ||
231 | + .thenApply(v -> entitiesFutures.stream() | ||
232 | + .map(CompletableFuture::join) | ||
233 | + .collect(Collectors.toList())); | ||
234 | + | ||
235 | + | ||
236 | + entities.whenComplete((tsKvEntities, throwable) -> { | ||
218 | if (throwable != null) { | 237 | if (throwable != null) { |
219 | listenableFuture.setException(throwable); | 238 | listenableFuture.setException(throwable); |
220 | } else { | 239 | } else { |
221 | - listenableFuture.set(tsKvEntity); | 240 | + TsKvEntity result = null; |
241 | + for (TsKvEntity entity : tsKvEntities) { | ||
242 | + if (entity.isNotEmpty()) { | ||
243 | + result = entity; | ||
244 | + break; | ||
245 | + } | ||
246 | + } | ||
247 | + listenableFuture.set(result); | ||
222 | } | 248 | } |
223 | }); | 249 | }); |
224 | return Futures.transform(listenableFuture, new Function<TsKvEntity, Optional<TsKvEntry>>() { | 250 | return Futures.transform(listenableFuture, new Function<TsKvEntity, Optional<TsKvEntry>>() { |
@@ -35,7 +35,7 @@ public interface TsKvRepository extends CrudRepository<TsKvEntity, TsKvComposite | @@ -35,7 +35,7 @@ public interface TsKvRepository extends CrudRepository<TsKvEntity, TsKvComposite | ||
35 | 35 | ||
36 | @Query("SELECT tskv FROM TsKvEntity tskv WHERE tskv.entityId = :entityId " + | 36 | @Query("SELECT tskv FROM TsKvEntity tskv WHERE tskv.entityId = :entityId " + |
37 | "AND tskv.entityType = :entityType AND tskv.key = :entityKey " + | 37 | "AND tskv.entityType = :entityType AND tskv.key = :entityKey " + |
38 | - "AND tskv.ts > :startTs AND tskv.ts < :endTs") | 38 | + "AND tskv.ts > :startTs AND tskv.ts <= :endTs") |
39 | List<TsKvEntity> findAllWithLimit(@Param("entityId") String entityId, | 39 | List<TsKvEntity> findAllWithLimit(@Param("entityId") String entityId, |
40 | @Param("entityType") EntityType entityType, | 40 | @Param("entityType") EntityType entityType, |
41 | @Param("entityKey") String key, | 41 | @Param("entityKey") String key, |
@@ -55,29 +55,63 @@ public interface TsKvRepository extends CrudRepository<TsKvEntity, TsKvComposite | @@ -55,29 +55,63 @@ public interface TsKvRepository extends CrudRepository<TsKvEntity, TsKvComposite | ||
55 | @Param("endTs") long endTs); | 55 | @Param("endTs") long endTs); |
56 | 56 | ||
57 | @Async | 57 | @Async |
58 | - @Query("SELECT new TsKvEntity(MAX(tskv.strValue), MAX(tskv.longValue), MAX(tskv.doubleValue), true) FROM TsKvEntity tskv " + | 58 | + @Query("SELECT new TsKvEntity(MAX(tskv.strValue)) FROM TsKvEntity tskv " + |
59 | + "WHERE tskv.strValue IS NOT NULL " + | ||
60 | + "AND tskv.entityId = :entityId AND tskv.entityType = :entityType " + | ||
61 | + "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts <= :endTs") | ||
62 | + CompletableFuture<TsKvEntity> findStringMax(@Param("entityId") String entityId, | ||
63 | + @Param("entityType") EntityType entityType, | ||
64 | + @Param("entityKey") String entityKey, | ||
65 | + @Param("startTs") long startTs, | ||
66 | + @Param("endTs") long endTs); | ||
67 | + | ||
68 | + @Async | ||
69 | + @Query("SELECT new TsKvEntity(MAX(COALESCE(tskv.longValue, -9223372036854775807)), " + | ||
70 | + "MAX(COALESCE(tskv.doubleValue, -1.79769E+308)), " + | ||
71 | + "SUM(CASE WHEN tskv.longValue IS NULL THEN 0 ELSE 1 END), " + | ||
72 | + "SUM(CASE WHEN tskv.doubleValue IS NULL THEN 0 ELSE 1 END), " + | ||
73 | + "'MAX') FROM TsKvEntity tskv " + | ||
59 | "WHERE tskv.entityId = :entityId AND tskv.entityType = :entityType " + | 74 | "WHERE tskv.entityId = :entityId AND tskv.entityType = :entityType " + |
60 | - "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts < :endTs") | ||
61 | - CompletableFuture<TsKvEntity> findMax(@Param("entityId") String entityId, | 75 | + "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts <= :endTs") |
76 | + CompletableFuture<TsKvEntity> findNumericMax(@Param("entityId") String entityId, | ||
77 | + @Param("entityType") EntityType entityType, | ||
78 | + @Param("entityKey") String entityKey, | ||
79 | + @Param("startTs") long startTs, | ||
80 | + @Param("endTs") long endTs); | ||
81 | + | ||
82 | + | ||
83 | + @Async | ||
84 | + @Query("SELECT new TsKvEntity(MIN(tskv.strValue)) FROM TsKvEntity tskv " + | ||
85 | + "WHERE tskv.strValue IS NOT NULL " + | ||
86 | + "AND tskv.entityId = :entityId AND tskv.entityType = :entityType " + | ||
87 | + "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts <= :endTs") | ||
88 | + CompletableFuture<TsKvEntity> findStringMin(@Param("entityId") String entityId, | ||
62 | @Param("entityType") EntityType entityType, | 89 | @Param("entityType") EntityType entityType, |
63 | @Param("entityKey") String entityKey, | 90 | @Param("entityKey") String entityKey, |
64 | @Param("startTs") long startTs, | 91 | @Param("startTs") long startTs, |
65 | @Param("endTs") long endTs); | 92 | @Param("endTs") long endTs); |
66 | 93 | ||
67 | @Async | 94 | @Async |
68 | - @Query("SELECT new TsKvEntity(MIN(tskv.strValue), MIN(tskv.longValue), MIN(tskv.doubleValue), false) FROM TsKvEntity tskv " + | 95 | + @Query("SELECT new TsKvEntity(MIN(COALESCE(tskv.longValue, 9223372036854775807)), " + |
96 | + "MIN(COALESCE(tskv.doubleValue, 1.79769E+308)), " + | ||
97 | + "SUM(CASE WHEN tskv.longValue IS NULL THEN 0 ELSE 1 END), " + | ||
98 | + "SUM(CASE WHEN tskv.doubleValue IS NULL THEN 0 ELSE 1 END), " + | ||
99 | + "'MIN') FROM TsKvEntity tskv " + | ||
69 | "WHERE tskv.entityId = :entityId AND tskv.entityType = :entityType " + | 100 | "WHERE tskv.entityId = :entityId AND tskv.entityType = :entityType " + |
70 | - "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts < :endTs") | ||
71 | - CompletableFuture<TsKvEntity> findMin(@Param("entityId") String entityId, | 101 | + "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts <= :endTs") |
102 | + CompletableFuture<TsKvEntity> findNumericMin(@Param("entityId") String entityId, | ||
72 | @Param("entityType") EntityType entityType, | 103 | @Param("entityType") EntityType entityType, |
73 | @Param("entityKey") String entityKey, | 104 | @Param("entityKey") String entityKey, |
74 | @Param("startTs") long startTs, | 105 | @Param("startTs") long startTs, |
75 | @Param("endTs") long endTs); | 106 | @Param("endTs") long endTs); |
76 | 107 | ||
77 | @Async | 108 | @Async |
78 | - @Query("SELECT new TsKvEntity(COUNT(tskv.booleanValue), COUNT(tskv.strValue), COUNT(tskv.longValue), COUNT(tskv.doubleValue)) FROM TsKvEntity tskv " + | 109 | + @Query("SELECT new TsKvEntity(SUM(CASE WHEN tskv.booleanValue IS NULL THEN 0 ELSE 1 END), " + |
110 | + "SUM(CASE WHEN tskv.strValue IS NULL THEN 0 ELSE 1 END), " + | ||
111 | + "SUM(CASE WHEN tskv.longValue IS NULL THEN 0 ELSE 1 END), " + | ||
112 | + "SUM(CASE WHEN tskv.doubleValue IS NULL THEN 0 ELSE 1 END)) FROM TsKvEntity tskv " + | ||
79 | "WHERE tskv.entityId = :entityId AND tskv.entityType = :entityType " + | 113 | "WHERE tskv.entityId = :entityId AND tskv.entityType = :entityType " + |
80 | - "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts < :endTs") | 114 | + "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts <= :endTs") |
81 | CompletableFuture<TsKvEntity> findCount(@Param("entityId") String entityId, | 115 | CompletableFuture<TsKvEntity> findCount(@Param("entityId") String entityId, |
82 | @Param("entityType") EntityType entityType, | 116 | @Param("entityType") EntityType entityType, |
83 | @Param("entityKey") String entityKey, | 117 | @Param("entityKey") String entityKey, |
@@ -85,23 +119,31 @@ public interface TsKvRepository extends CrudRepository<TsKvEntity, TsKvComposite | @@ -85,23 +119,31 @@ public interface TsKvRepository extends CrudRepository<TsKvEntity, TsKvComposite | ||
85 | @Param("endTs") long endTs); | 119 | @Param("endTs") long endTs); |
86 | 120 | ||
87 | @Async | 121 | @Async |
88 | - @Query("SELECT new TsKvEntity(SUM(tskv.longValue), SUM(tskv.doubleValue), COUNT(tskv.longValue), COUNT(tskv.doubleValue)) FROM TsKvEntity tskv " + | 122 | + @Query("SELECT new TsKvEntity(SUM(COALESCE(tskv.longValue, 0)), " + |
123 | + "SUM(COALESCE(tskv.doubleValue, 0.0)), " + | ||
124 | + "SUM(CASE WHEN tskv.longValue IS NULL THEN 0 ELSE 1 END), " + | ||
125 | + "SUM(CASE WHEN tskv.doubleValue IS NULL THEN 0 ELSE 1 END), " + | ||
126 | + "'AVG') FROM TsKvEntity tskv " + | ||
89 | "WHERE tskv.entityId = :entityId AND tskv.entityType = :entityType " + | 127 | "WHERE tskv.entityId = :entityId AND tskv.entityType = :entityType " + |
90 | - "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts < :endTs") | 128 | + "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts <= :endTs") |
91 | CompletableFuture<TsKvEntity> findAvg(@Param("entityId") String entityId, | 129 | CompletableFuture<TsKvEntity> findAvg(@Param("entityId") String entityId, |
92 | @Param("entityType") EntityType entityType, | 130 | @Param("entityType") EntityType entityType, |
93 | @Param("entityKey") String entityKey, | 131 | @Param("entityKey") String entityKey, |
94 | @Param("startTs") long startTs, | 132 | @Param("startTs") long startTs, |
95 | @Param("endTs") long endTs); | 133 | @Param("endTs") long endTs); |
96 | 134 | ||
97 | - | ||
98 | @Async | 135 | @Async |
99 | - @Query("SELECT new TsKvEntity(SUM(tskv.longValue), SUM(tskv.doubleValue)) FROM TsKvEntity tskv " + | 136 | + @Query("SELECT new TsKvEntity(SUM(COALESCE(tskv.longValue, 0)), " + |
137 | + "SUM(COALESCE(tskv.doubleValue, 0.0)), " + | ||
138 | + "SUM(CASE WHEN tskv.longValue IS NULL THEN 0 ELSE 1 END), " + | ||
139 | + "SUM(CASE WHEN tskv.doubleValue IS NULL THEN 0 ELSE 1 END), " + | ||
140 | + "'SUM') FROM TsKvEntity tskv " + | ||
100 | "WHERE tskv.entityId = :entityId AND tskv.entityType = :entityType " + | 141 | "WHERE tskv.entityId = :entityId AND tskv.entityType = :entityType " + |
101 | - "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts < :endTs") | 142 | + "AND tskv.key = :entityKey AND tskv.ts > :startTs AND tskv.ts <= :endTs") |
102 | CompletableFuture<TsKvEntity> findSum(@Param("entityId") String entityId, | 143 | CompletableFuture<TsKvEntity> findSum(@Param("entityId") String entityId, |
103 | @Param("entityType") EntityType entityType, | 144 | @Param("entityType") EntityType entityType, |
104 | @Param("entityKey") String entityKey, | 145 | @Param("entityKey") String entityKey, |
105 | @Param("startTs") long startTs, | 146 | @Param("startTs") long startTs, |
106 | @Param("endTs") long endTs); | 147 | @Param("endTs") long endTs); |
148 | + | ||
107 | } | 149 | } |
@@ -17,10 +17,7 @@ package org.thingsboard.server.dao.service.timeseries; | @@ -17,10 +17,7 @@ package org.thingsboard.server.dao.service.timeseries; | ||
17 | 17 | ||
18 | import com.datastax.driver.core.utils.UUIDs; | 18 | import com.datastax.driver.core.utils.UUIDs; |
19 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
20 | -import org.junit.After; | ||
21 | -import org.junit.Assert; | ||
22 | -import org.junit.Before; | ||
23 | -import org.junit.Test; | 20 | +import org.junit.*; |
24 | import org.thingsboard.server.common.data.EntityView; | 21 | import org.thingsboard.server.common.data.EntityView; |
25 | import org.thingsboard.server.common.data.Tenant; | 22 | import org.thingsboard.server.common.data.Tenant; |
26 | import org.thingsboard.server.common.data.id.DeviceId; | 23 | import org.thingsboard.server.common.data.id.DeviceId; |
@@ -280,6 +277,66 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { | @@ -280,6 +277,66 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { | ||
280 | 277 | ||
281 | assertEquals(50000, list.get(2).getTs()); | 278 | assertEquals(50000, list.get(2).getTs()); |
282 | assertEquals(java.util.Optional.of(2L), list.get(2).getLongValue()); | 279 | assertEquals(java.util.Optional.of(2L), list.get(2).getLongValue()); |
280 | + | ||
281 | + | ||
282 | + entries.add(save(deviceId, 65000, "A1")); | ||
283 | + entries.add(save(deviceId, 75000, "A2")); | ||
284 | + entries.add(save(deviceId, 85000, "B1")); | ||
285 | + entries.add(save(deviceId, 95000, "B2")); | ||
286 | + entries.add(save(deviceId, 105000, "C1")); | ||
287 | + entries.add(save(deviceId, 115000, "C2")); | ||
288 | + | ||
289 | + list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 60000, | ||
290 | + 120000, 20000, 3, Aggregation.NONE))).get(); | ||
291 | + assertEquals(3, list.size()); | ||
292 | + assertEquals(115000, list.get(0).getTs()); | ||
293 | + assertEquals(java.util.Optional.of("C2"), list.get(0).getStrValue()); | ||
294 | + | ||
295 | + assertEquals(105000, list.get(1).getTs()); | ||
296 | + assertEquals(java.util.Optional.of("C1"), list.get(1).getStrValue()); | ||
297 | + | ||
298 | + assertEquals(95000, list.get(2).getTs()); | ||
299 | + assertEquals(java.util.Optional.of("B2"), list.get(2).getStrValue()); | ||
300 | + | ||
301 | + | ||
302 | + list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 60000, | ||
303 | + 120000, 20000, 3, Aggregation.MIN))).get(); | ||
304 | + | ||
305 | + assertEquals(3, list.size()); | ||
306 | + assertEquals(70000, list.get(0).getTs()); | ||
307 | + assertEquals(java.util.Optional.of("A1"), list.get(0).getStrValue()); | ||
308 | + | ||
309 | + assertEquals(90000, list.get(1).getTs()); | ||
310 | + assertEquals(java.util.Optional.of("B1"), list.get(1).getStrValue()); | ||
311 | + | ||
312 | + assertEquals(110000, list.get(2).getTs()); | ||
313 | + assertEquals(java.util.Optional.of("C1"), list.get(2).getStrValue()); | ||
314 | + | ||
315 | + list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 60000, | ||
316 | + 120000, 20000, 3, Aggregation.MAX))).get(); | ||
317 | + | ||
318 | + assertEquals(3, list.size()); | ||
319 | + assertEquals(70000, list.get(0).getTs()); | ||
320 | + assertEquals(java.util.Optional.of("A2"), list.get(0).getStrValue()); | ||
321 | + | ||
322 | + assertEquals(90000, list.get(1).getTs()); | ||
323 | + assertEquals(java.util.Optional.of("B2"), list.get(1).getStrValue()); | ||
324 | + | ||
325 | + assertEquals(110000, list.get(2).getTs()); | ||
326 | + assertEquals(java.util.Optional.of("C2"), list.get(2).getStrValue()); | ||
327 | + | ||
328 | + list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 60000, | ||
329 | + 120000, 20000, 3, Aggregation.COUNT))).get(); | ||
330 | + | ||
331 | + assertEquals(3, list.size()); | ||
332 | + assertEquals(70000, list.get(0).getTs()); | ||
333 | + assertEquals(java.util.Optional.of(2L), list.get(0).getLongValue()); | ||
334 | + | ||
335 | + assertEquals(90000, list.get(1).getTs()); | ||
336 | + assertEquals(java.util.Optional.of(2L), list.get(1).getLongValue()); | ||
337 | + | ||
338 | + assertEquals(110000, list.get(2).getTs()); | ||
339 | + assertEquals(java.util.Optional.of(2L), list.get(2).getLongValue()); | ||
283 | } | 340 | } |
284 | 341 | ||
285 | @Test | 342 | @Test |
@@ -385,6 +442,12 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { | @@ -385,6 +442,12 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { | ||
385 | return entry; | 442 | return entry; |
386 | } | 443 | } |
387 | 444 | ||
445 | + private TsKvEntry save(DeviceId deviceId, long ts, String value) throws Exception { | ||
446 | + TsKvEntry entry = new BasicTsKvEntry(ts, new StringDataEntry(LONG_KEY, value)); | ||
447 | + tsService.save(tenantId, deviceId, entry).get(); | ||
448 | + return entry; | ||
449 | + } | ||
450 | + | ||
388 | 451 | ||
389 | private void saveEntries(DeviceId deviceId, long ts) throws ExecutionException, InterruptedException { | 452 | private void saveEntries(DeviceId deviceId, long ts) throws ExecutionException, InterruptedException { |
390 | tsService.save(tenantId, deviceId, toTsEntry(ts, stringKvEntry)).get(); | 453 | tsService.save(tenantId, deviceId, toTsEntry(ts, stringKvEntry)).get(); |