1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cobalt.data; 18 19 import androidx.room.Dao; 20 import androidx.room.Delete; 21 import androidx.room.Insert; 22 import androidx.room.MapInfo; 23 import androidx.room.OnConflictStrategy; 24 import androidx.room.Query; 25 import androidx.room.Update; 26 27 import com.google.cobalt.AggregateValue; 28 import com.google.cobalt.UnencryptedObservationBatch; 29 import com.google.common.hash.HashCode; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 import java.util.Map; 34 import java.util.Optional; 35 36 /** 37 * Data Access Object offering low-level operations to the database that can be used for more 38 * complex work. 39 */ 40 @Dao 41 public abstract class DaoBuildingBlocks { 42 /** 43 * Inserts an entry into the system profiles table. 44 * 45 * @param systemProfileEntity the system profile to insert 46 */ 47 @Insert(onConflict = OnConflictStrategy.IGNORE) insertSystemProfile(SystemProfileEntity systemProfileEntity)48 abstract Void insertSystemProfile(SystemProfileEntity systemProfileEntity); 49 50 /** 51 * Inserts an aggregate value in the aggregate store. 52 * 53 * @param aggregateStoreEntity the aggregate to insert 54 */ 55 @Insert(onConflict = OnConflictStrategy.ROLLBACK) insertAggregateValue(AggregateStoreEntity aggregateStoreEntity)56 abstract Void insertAggregateValue(AggregateStoreEntity aggregateStoreEntity); 57 58 /** 59 * Inserts a string hash into the string hashes store. 60 * 61 * @param stringHashEntity the string hash to insert 62 */ 63 @Insert(onConflict = OnConflictStrategy.IGNORE) insertStringHash(StringHashEntity stringHashEntity)64 abstract Void insertStringHash(StringHashEntity stringHashEntity); 65 66 /** 67 * Inserts the value for ths key of `globalValueEntity`. 68 * 69 * @param globalValueEntity the key, value pair to insert or update 70 */ 71 @Insert(onConflict = OnConflictStrategy.IGNORE) insertGlobalValue(GlobalValueEntity globalValueEntity)72 abstract Void insertGlobalValue(GlobalValueEntity globalValueEntity); 73 74 /** 75 * Inserts or update the value for ths key of `globalValueEntity`. 76 * 77 * @param globalValueEntity the key, value pair to insert or update 78 */ 79 @Insert(onConflict = OnConflictStrategy.REPLACE) insertOrReplaceGlobalValue(GlobalValueEntity globalValueEntity)80 abstract Void insertOrReplaceGlobalValue(GlobalValueEntity globalValueEntity); 81 82 /** 83 * Inserts the day a report was last sent. 84 * 85 * @param reportKey the report 86 * @param dayIndex the day 87 */ 88 @Insert(onConflict = OnConflictStrategy.IGNORE) insertLastSentDayIndex(ReportKey reportKey, int dayIndex)89 Void insertLastSentDayIndex(ReportKey reportKey, int dayIndex) { 90 return insertLastSentDayIndex(ReportEntity.create(reportKey, dayIndex)); 91 } 92 93 /** 94 * Inserts the day a report was last sent. 95 * 96 * @param reportEntity the report and day index to insert 97 */ 98 @Insert(onConflict = OnConflictStrategy.IGNORE) insertLastSentDayIndex(ReportEntity reportEntity)99 abstract Void insertLastSentDayIndex(ReportEntity reportEntity); 100 101 /** 102 * Inserts observation batches into the observation store. 103 * 104 * @param observationBatches the observation batches to insert 105 */ insertObservationBatches(List<UnencryptedObservationBatch> observationBatches)106 Void insertObservationBatches(List<UnencryptedObservationBatch> observationBatches) { 107 List<ObservationStoreEntity> observationStoreEntities = new ArrayList<>(); 108 for (UnencryptedObservationBatch batch : observationBatches) { 109 observationStoreEntities.add(ObservationStoreEntity.createForInsertion(batch)); 110 } 111 return insertObservations(observationStoreEntities); 112 } 113 114 /** 115 * Inserts observations into the observation store. 116 * 117 * @param observationStoreEntities the observations to insert 118 */ 119 @Insert(onConflict = OnConflictStrategy.ROLLBACK) insertObservations(List<ObservationStoreEntity> observationStoreEntities)120 abstract Void insertObservations(List<ObservationStoreEntity> observationStoreEntities); 121 122 /** 123 * Update the day a report was last sent. 124 * 125 * @param reportKey the report 126 * @param dayIndex the new day index day index to update 127 */ updateLastSentDayIndex(ReportKey reportKey, int dayIndex)128 Void updateLastSentDayIndex(ReportKey reportKey, int dayIndex) { 129 return updateLastSentDayIndex(ReportEntity.create(reportKey, dayIndex)); 130 } 131 132 /** 133 * Update the day a report was last sent. 134 * 135 * @param reportEntity the report and day index to update 136 */ 137 @Update(entity = ReportEntity.class) updateLastSentDayIndex(ReportEntity reportEntity)138 abstract Void updateLastSentDayIndex(ReportEntity reportEntity); 139 140 /** 141 * Update an aggregate value in the aggregate store. 142 * 143 * @param reportKey the report to update the value under 144 * @param dayIndex the day the event occrurred 145 * @param eventVector the event vector the value is being aggregated for 146 * @param systemProfileHash the system profile hash of the event 147 * @param newAggregateValue the new aggregate value 148 */ updateAggregateValue( ReportKey reportKey, int dayIndex, EventVector eventVector, long systemProfileHash, AggregateValue newAggregateValue)149 Void updateAggregateValue( 150 ReportKey reportKey, 151 int dayIndex, 152 EventVector eventVector, 153 long systemProfileHash, 154 AggregateValue newAggregateValue) { 155 return updateAggregateValue( 156 reportKey.customerId(), 157 reportKey.projectId(), 158 reportKey.metricId(), 159 reportKey.reportId(), 160 dayIndex, 161 eventVector, 162 systemProfileHash, 163 newAggregateValue); 164 } 165 166 /** 167 * Update an aggregate value in the aggregate store. 168 * 169 * @param customerId the customer id to update the value under 170 * @param projectId the project id to update the value under 171 * @param metricId the metric id to update the value under 172 * @param reportId the report id to update the value under 173 * @param dayIndex the day the event occrurred 174 * @param eventVector the event vector the value is being aggregated for 175 * @param systemProfileHash the system profile hash of the event 176 * @param newAggregateValue the new aggregate value 177 */ 178 @Query( 179 "UPDATE AggregateStore " 180 + "SET aggregate_value = :newAggregateValue " 181 + "WHERE customer_id = :customerId " 182 + "AND project_id = :projectId " 183 + "AND metric_id = :metricId " 184 + "AND report_id = :reportId " 185 + "AND day_index= :dayIndex " 186 + "AND event_vector = :eventVector " 187 + "AND system_profile_hash = :systemProfileHash") updateAggregateValue( long customerId, long projectId, long metricId, long reportId, int dayIndex, EventVector eventVector, long systemProfileHash, AggregateValue newAggregateValue)188 abstract Void updateAggregateValue( 189 long customerId, 190 long projectId, 191 long metricId, 192 long reportId, 193 int dayIndex, 194 EventVector eventVector, 195 long systemProfileHash, 196 AggregateValue newAggregateValue); 197 198 /** 199 * Update the system profile hash of an aggregate value. 200 * 201 * @param customerId the customer id to update the value under 202 * @param projectId the project id to update the value under 203 * @param metricId the metric id to update the value under 204 * @param reportId the report id to update the value under 205 * @param dayIndex the day the event occrurred 206 * @param eventVector the event vector the value is being aggregated for 207 * @param currentSystemProfileHash the current system profile hash of the event 208 * @param newSystemProfileHash the new system profile hash of the event 209 */ 210 @Query( 211 "UPDATE AggregateStore " 212 + "SET system_profile_hash = :newSystemProfileHash " 213 + "WHERE customer_id = :customerId " 214 + "AND project_id = :projectId " 215 + "AND metric_id = :metricId " 216 + "AND report_id = :reportId " 217 + "AND day_index= :dayIndex " 218 + "AND event_vector = :eventVector " 219 + "AND system_profile_hash = :currentSystemProfileHash") updateSystemProfileHash( long customerId, long projectId, long metricId, long reportId, int dayIndex, EventVector eventVector, long currentSystemProfileHash, long newSystemProfileHash)220 abstract Void updateSystemProfileHash( 221 long customerId, 222 long projectId, 223 long metricId, 224 long reportId, 225 int dayIndex, 226 EventVector eventVector, 227 long currentSystemProfileHash, 228 long newSystemProfileHash); 229 230 /** 231 * Update the system profile hash and aggregate value of an event. 232 * 233 * @param customerId the customer id to update the value under 234 * @param projectId the project id to update the value under 235 * @param metricId the metric id to update the value under 236 * @param reportId the report id to update the value under 237 * @param dayIndex the day the event occrurred 238 * @param eventVector the event vector the value is being aggregated for 239 * @param currentSystemProfileHash the current system profile hash of the event 240 * @param newSystemProfileHash the new system profile hash of the event 241 * @param newAggregateValue the new aggregate value 242 */ 243 @Query( 244 "UPDATE AggregateStore " 245 + "SET system_profile_hash = :newSystemProfileHash, " 246 + "aggregate_value = :newAggregateValue " 247 + "WHERE customer_id = :customerId " 248 + "AND project_id = :projectId " 249 + "AND metric_id = :metricId " 250 + "AND report_id = :reportId " 251 + "AND day_index= :dayIndex " 252 + "AND event_vector = :eventVector " 253 + "AND system_profile_hash = :currentSystemProfileHash") updateSystemProfileHashAndAggregateValue( long customerId, long projectId, long metricId, long reportId, int dayIndex, EventVector eventVector, long currentSystemProfileHash, long newSystemProfileHash, AggregateValue newAggregateValue)254 abstract Void updateSystemProfileHashAndAggregateValue( 255 long customerId, 256 long projectId, 257 long metricId, 258 long reportId, 259 int dayIndex, 260 EventVector eventVector, 261 long currentSystemProfileHash, 262 long newSystemProfileHash, 263 AggregateValue newAggregateValue); 264 265 /** 266 * Query the saved global values related to enablement. 267 * 268 * @return a map of the enablement values which have been saved 269 */ 270 @MapInfo(keyColumn = "key", valueColumn = "value") 271 @Query( 272 "SELECT * FROM GlobalValues WHERE key IN ('INITIAL_ENABLED_TIME'," 273 + " 'INITIAL_DISABLED_TIME')") queryEnablementTimes()274 abstract Map<GlobalValueEntity.Key, String> queryEnablementTimes(); 275 276 /** 277 * Selects one (system profile hash, aggregate value) pair from the DB for the given report, 278 * day, and event vector to update. The returned system profile hash will be 279 * `systemProfileHashHint` if it exists for the report, day, and event vector. Otherwise, a row 280 * with a random system profile associated with report, day, and event vector will be returned. 281 * 282 * @param reportKey the report selected values are for 283 * @param dayIndex the day selected values are aggregated on 284 * @param eventVector the event codes (if any) selected values match 285 * @param systemProfileHashHint the system profile of the record to return, if it exists 286 * @return the system profile hash and aggregate value, if one is found 287 */ queryOneSystemProfileAndAggregateValue( ReportKey reportKey, int dayIndex, EventVector eventVector, long systemProfileHashHint)288 Optional<SystemProfileAndAggregateValue> queryOneSystemProfileAndAggregateValue( 289 ReportKey reportKey, 290 int dayIndex, 291 EventVector eventVector, 292 long systemProfileHashHint) { 293 return queryOneSystemProfileAndAggregateValue( 294 reportKey.customerId(), 295 reportKey.projectId(), 296 reportKey.metricId(), 297 reportKey.reportId(), 298 dayIndex, 299 eventVector, 300 systemProfileHashHint); 301 } 302 303 /** 304 * Selects one (system profile hash, aggregate value) pair from the DB for the given report, 305 * day, and event vector to update. The returned system profile hash will be 306 * `systemProfileHashHint` if it exists for the report, day, and event vector. Otherwise, a row 307 * with a random system profile associated with report, day, and event vector will be returned. 308 * 309 * @param customerId the customer selected values are for 310 * @param projectId the project selected values are for 311 * @param metricId the metric selected values are for 312 * @param reportId the report selected values are for 313 * @param dayIndex the day selected values are aggregated on 314 * @param eventVector the event codes (if any) selected values match 315 * @param systemProfileHashHint the system profile of the record to return, if it exists 316 * @return the system profile hash and aggregate value, if one is found 317 */ 318 @Query( 319 "SELECT system_profile_hash, aggregate_value FROM AggregateStore " 320 + "WHERE customer_id = :customerId " 321 + "AND project_id = :projectId " 322 + "AND metric_id = :metricId " 323 + "AND report_id = :reportId " 324 + "AND day_index = :dayIndex " 325 + "AND event_vector = :eventVector " 326 + "ORDER BY system_profile_hash = :systemProfileHashHint DESC, " 327 + "system_profile_hash ASC " 328 + "LIMIT 1") queryOneSystemProfileAndAggregateValue( long customerId, long projectId, long metricId, long reportId, int dayIndex, EventVector eventVector, long systemProfileHashHint)329 abstract Optional<SystemProfileAndAggregateValue> queryOneSystemProfileAndAggregateValue( 330 long customerId, 331 long projectId, 332 long metricId, 333 long reportId, 334 int dayIndex, 335 EventVector eventVector, 336 long systemProfileHashHint); 337 338 /** 339 * Count the number of distinct event vectors saved for a report on a given day and under a 340 * specific system profile. 341 * 342 * @param reportKey the report to search under 343 * @param dayIndex the day to search under 344 * @param systemProfileHash the system profile hash of the event 345 * @return the number of distnct event codes 346 */ queryCountEventVectors(ReportKey reportKey, int dayIndex, long systemProfileHash)347 int queryCountEventVectors(ReportKey reportKey, int dayIndex, long systemProfileHash) { 348 return queryCountEventVectors( 349 reportKey.customerId(), 350 reportKey.projectId(), 351 reportKey.metricId(), 352 reportKey.reportId(), 353 dayIndex, 354 systemProfileHash); 355 } 356 357 /** 358 * Returns the index a string hash should be assigned for a report on a given day. The returned 359 * value will be the index of `stringHashHint` if it exists in the list, the next string index 360 * value if string buffer max does not apply, or -1 if the string buffer max is in effect. 361 * 362 * @param customerId the customer id to search under 363 * @param projectId the project id to search under 364 * @param metricId the metric id to search under 365 * @param reportId the report id to search under 366 * @param dayIndex the day to search under 367 * @param stringBufferMax the maximum number of strings that should be stored 368 * @param stringHashHint the string hash that will be added 369 * @return the index that should be used for `stringHashHint` or -1 if it should not be inserted 370 */ 371 @Query( 372 "SELECT CASE " 373 + " WHEN hash_is_equal THEN max_list_index " 374 + " WHEN :stringBufferMax < 1 THEN max_list_index + 1 " 375 + " WHEN max_list_index + 1 < :stringBufferMax THEN max_list_index + 1 " 376 + " ELSE -1 " 377 + "END " 378 + "FROM (" 379 + " SELECT " 380 + " string_hash = :stringHashHint AS hash_is_equal, " 381 + " MAX(list_index) AS max_list_index " 382 + " FROM StringHashes " 383 + " WHERE customer_id = :customerId " 384 + " AND project_id = :projectId " 385 + " AND metric_id = :metricId " 386 + " AND report_id = :reportId " 387 + " AND day_index = :dayIndex " 388 + " GROUP BY string_hash = :stringHashHint " 389 + " ORDER BY hash_is_equal DESC " 390 + ") " 391 + "LIMIT 1") queryStringListIndex( long customerId, long projectId, long metricId, long reportId, int dayIndex, long stringBufferMax, HashCode stringHashHint)392 abstract int queryStringListIndex( 393 long customerId, 394 long projectId, 395 long metricId, 396 long reportId, 397 int dayIndex, 398 long stringBufferMax, 399 HashCode stringHashHint); 400 401 /** 402 * Returns the index a string hash should be assigned for a report on a given day. The returned 403 * value will be the index of `stringHashHint` if it exists in the list, the next string index 404 * value if string buffer max does not apply, or -1 if the string buffer max is in effect. 405 * 406 * @param reportKey the report 407 * @param dayIndex the day to search under 408 * @param stringBufferMax the maximum number of strings that should be stored 409 * @param stringHashHint the string hash that will be added 410 * @return the index that should be used for `stringHashHint` or -1 if it should not be inserted 411 */ queryStringListIndex( ReportKey reportKey, int dayIndex, long stringBufferMax, HashCode stringHashHint)412 int queryStringListIndex( 413 ReportKey reportKey, int dayIndex, long stringBufferMax, HashCode stringHashHint) { 414 return queryStringListIndex( 415 reportKey.customerId(), 416 reportKey.projectId(), 417 reportKey.metricId(), 418 reportKey.reportId(), 419 dayIndex, 420 stringBufferMax, 421 stringHashHint); 422 } 423 424 /** 425 * Returns the string hash list for a specific report and day. 426 * 427 * <p>Note, results do not have a guaranteed order. 428 * 429 * @param customerId the customer id to search under 430 * @param projectId the project id to search under 431 * @param metricId the metric id to search under 432 * @param reportId the report id to search under 433 * @param dayIndex the day to search under 434 * @return a list of string hashes and their respective indices 435 */ 436 @Query( 437 "SELECT " 438 + "list_index, " 439 + "string_hash " 440 + "FROM StringHashes " 441 + "WHERE customer_id = :customerId " 442 + "AND project_id = :projectId " 443 + "AND metric_id = :metricId " 444 + "AND report_id = :reportId " 445 + "AND day_index = :dayIndex") queryStringHashList( long customerId, long projectId, long metricId, long reportId, int dayIndex)446 abstract List<StringListEntry> queryStringHashList( 447 long customerId, long projectId, long metricId, long reportId, int dayIndex); 448 449 /** 450 * Returns the string hash list for a specific report and day. 451 * 452 * <p>Note, results do not have a guaranteed order. 453 * 454 * @param reportKey the report 455 * @param dayIndex the day to search under 456 * @return a list of string hashes and their respective indices 457 */ queryStringHashList(ReportKey reportKey, int dayIndex)458 public List<StringListEntry> queryStringHashList(ReportKey reportKey, int dayIndex) { 459 return queryStringHashList( 460 reportKey.customerId(), 461 reportKey.projectId(), 462 reportKey.metricId(), 463 reportKey.reportId(), 464 dayIndex); 465 } 466 467 /** 468 * Count the number of distinct event vectors saved for a report on a given day and under a 469 * specific system profile. 470 * 471 * @param customerId the customer id to search under 472 * @param projectId the project id to search under 473 * @param metricId the metric id to search under 474 * @param reportId the report id to search under 475 * @param dayIndex the day to search under 476 * @param systemProfileHash the system profile hash of the event 477 * @return the number of distnct event codes 478 */ 479 @Query( 480 "SELECT COUNT(DISTINCT event_vector) " 481 + "FROM AggregateStore " 482 + "WHERE customer_id = :customerId " 483 + "AND project_id = :projectId " 484 + "AND metric_id = :metricId " 485 + "AND report_id = :reportId " 486 + "AND day_index= :dayIndex " 487 + "AND system_profile_hash = :systemProfileHash") queryCountEventVectors( long customerId, long projectId, long metricId, long reportId, int dayIndex, long systemProfileHash)488 abstract int queryCountEventVectors( 489 long customerId, 490 long projectId, 491 long metricId, 492 long reportId, 493 int dayIndex, 494 long systemProfileHash); 495 496 /** 497 * Get the aggregated values for a given report on a given day. 498 * 499 * @param reportKey the report to search under 500 * @param dayIndex the day to search under 501 * @return a list of events to be used for observation generation 502 */ queryEventRecordsForDay(ReportKey reportKey, int dayIndex)503 List<EventRecordAndSystemProfile> queryEventRecordsForDay(ReportKey reportKey, int dayIndex) { 504 return queryEventRecordsForDay( 505 reportKey.customerId(), 506 reportKey.projectId(), 507 reportKey.metricId(), 508 reportKey.reportId(), 509 dayIndex); 510 } 511 512 /** 513 * Get the aggregated values for a given report on a given day. 514 * 515 * @param customerId the customer id to search under 516 * @param projectId the project id to search under 517 * @param metricId the metric id to search under 518 * @param reportId the report id to search under 519 * @param dayIndex the day to search under 520 * @return a list of events to be used for observation generation 521 */ 522 @Query( 523 "SELECT " 524 + "profile.system_profile, " 525 + "aggregate.event_vector, " 526 + "aggregate.aggregate_value " 527 + "FROM " 528 + "AggregateStore AS aggregate " 529 + "INNER JOIN SystemProfiles AS profile " 530 + "ON aggregate.system_profile_hash = profile.system_profile_hash " 531 + "WHERE customer_id = :customerId " 532 + "AND project_id = :projectId " 533 + "AND metric_id = :metricId " 534 + "AND report_id = :reportId " 535 + "AND day_index= :dayIndex " 536 + "ORDER BY aggregate.system_profile_hash, " 537 + "aggregate.event_vector") queryEventRecordsForDay( long customerId, long projectId, long metricId, long reportId, int dayIndex)538 abstract List<EventRecordAndSystemProfile> queryEventRecordsForDay( 539 long customerId, long projectId, long metricId, long reportId, int dayIndex); 540 541 /** 542 * Returns the observations in the observation store, ordered by creation time. 543 * 544 * @return an list of observations, ordered by creation time 545 */ 546 @Query("SELECT * FROM ObservationStore ORDER BY observation_store_id ASC") queryOldestObservations()547 abstract List<ObservationStoreEntity> queryOldestObservations(); 548 549 /** 550 * Returns the day a report was last sent, if in the reports table. 551 * 552 * @param reportKey the report 553 * @return the last sent day index, if found 554 */ queryLastSentDayIndex(ReportKey reportKey)555 Optional<Integer> queryLastSentDayIndex(ReportKey reportKey) { 556 return queryLastSentDayIndex( 557 reportKey.customerId(), 558 reportKey.projectId(), 559 reportKey.metricId(), 560 reportKey.reportId()); 561 } 562 563 /** Returns the keys of all reports in the report store. */ 564 @Query("SELECT customer_id, project_id, metric_id, report_id FROM Reports") queryReportKeys()565 abstract List<ReportKey> queryReportKeys(); 566 567 /** 568 * Returns the day a report was last sent, if in the reports table. 569 * 570 * @param customerId the customer id for the report 571 * @param projectId the project id for the report 572 * @param metricId the metric id for the report 573 * @param reportId the report id for the report 574 * @return the last sent day index, if found 575 */ 576 @Query( 577 "SELECT last_sent_day_index " 578 + "FROM Reports " 579 + "WHERE customer_id = :customerId " 580 + "AND project_id = :projectId " 581 + "AND metric_id = :metricId " 582 + "AND report_id = :reportId") queryLastSentDayIndex( long customerId, long projectId, long metricId, long reportId)583 abstract Optional<Integer> queryLastSentDayIndex( 584 long customerId, long projectId, long metricId, long reportId); 585 586 /** Delete the saved initial disabled time. */ 587 @Query("DELETE FROM GlobalValues WHERE key = 'INITIAL_DISABLED_TIME'") deleteDisabledTime()588 abstract Void deleteDisabledTime(); 589 590 /** 591 * Delete aggregate values from before the specified day. 592 * 593 * @param oldestDayIndex oldest day index to keep events from 594 */ 595 @Query("DELETE FROM AggregateStore WHERE day_index < :oldestDayIndex") deleteOldAggregates(int oldestDayIndex)596 abstract Void deleteOldAggregates(int oldestDayIndex); 597 598 /** Deletes string hashes that don't have corresponding values in the aggregate store. */ 599 @Query( 600 "DELETE FROM StringHashes " 601 + "WHERE (customer_id, project_id, metric_id, report_id, day_index) " 602 + "NOT IN ( " 603 + "SELECT DISTINCT customer_id, project_id, metric_id, report_id, day_index " 604 + "FROM AggregateStore " 605 + ")") deleteUnusedStringHashes()606 abstract void deleteUnusedStringHashes(); 607 608 /** Delete system profiles which don't appear in the aggregate store. */ 609 @Query( 610 "DELETE FROM SystemProfiles " 611 + "WHERE system_profile_hash NOT IN (" 612 + "SELECT DISTINCT system_profile_hash FROM AggregateStore" 613 + ")") deleteUnusedSystemProfileHashes()614 abstract Void deleteUnusedSystemProfileHashes(); 615 616 /** 617 * Delete the specified observations from the observation store. 618 * 619 * @param observationStoreIds ids of the observations to delete 620 */ 621 @Query("DELETE FROM ObservationStore WHERE observation_store_id IN (:observationStoreIds)") deleteByObservationId(List<Integer> observationStoreIds)622 abstract Void deleteByObservationId(List<Integer> observationStoreIds); 623 624 /** 625 * Delete the specified reports from the report store. 626 * 627 * @param reportKeys the reports to delete 628 */ 629 @Delete(entity = ReportEntity.class) deleteReports(List<ReportKey> reportKeys)630 abstract Void deleteReports(List<ReportKey> reportKeys); 631 } 632