1 /* 2 * Copyright (C) 2022 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.server.healthconnect.storage.request; 18 19 import static android.health.connect.Constants.DEFAULT_LONG; 20 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_UNKNOWN; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.health.connect.Constants; 25 import android.health.connect.datatypes.RecordTypeIdentifier; 26 import android.util.Slog; 27 28 import com.android.server.healthconnect.storage.utils.StorageUtils; 29 import com.android.server.healthconnect.storage.utils.WhereClauses; 30 31 import java.util.Collections; 32 import java.util.List; 33 import java.util.Objects; 34 35 /** 36 * No need to have delete-requests for child tables as ideally they should be following cascaded 37 * deletes. If not please rethink the table structure and if possible remove the parent-child 38 * relationship. 39 * 40 * @hide 41 */ 42 public class DeleteTableRequest { 43 44 private static final String TAG = "HealthConnectDelete"; 45 private final String mTableName; 46 @RecordTypeIdentifier.RecordType private final int mRecordType; 47 48 private String mIdColumnName; 49 private String mPackageColumnName; 50 private String mTimeColumnName; 51 private List<Long> mPackageFilters; 52 private long mStartTime = DEFAULT_LONG; 53 private long mEndTime = DEFAULT_LONG; 54 private boolean mRequiresUuId; 55 private List<String> mIds; 56 private boolean mEnforcePackageCheck; 57 private int mNumberOfUuidsToDelete; 58 private WhereClauses mCustomWhereClauses; 59 private long mLessThanOrEqualValue; 60 DeleteTableRequest( @onNull String tableName, @RecordTypeIdentifier.RecordType int recordType)61 public DeleteTableRequest( 62 @NonNull String tableName, @RecordTypeIdentifier.RecordType int recordType) { 63 Objects.requireNonNull(tableName); 64 65 mTableName = tableName; 66 mRecordType = recordType; 67 } 68 DeleteTableRequest(@onNull String tableName)69 public DeleteTableRequest(@NonNull String tableName) { 70 Objects.requireNonNull(tableName); 71 72 mTableName = tableName; 73 mRecordType = RECORD_TYPE_UNKNOWN; 74 } 75 getPackageColumnName()76 public String getPackageColumnName() { 77 return mPackageColumnName; 78 } 79 requiresPackageCheck()80 public boolean requiresPackageCheck() { 81 return mEnforcePackageCheck; 82 } 83 setEnforcePackageCheck( String packageColumnName, String uuidColumnName)84 public DeleteTableRequest setEnforcePackageCheck( 85 String packageColumnName, String uuidColumnName) { 86 mEnforcePackageCheck = true; 87 mPackageColumnName = packageColumnName; 88 mIdColumnName = uuidColumnName; 89 return this; 90 } 91 setIds(@onNull String idColumnName, @NonNull List<String> ids)92 public DeleteTableRequest setIds(@NonNull String idColumnName, @NonNull List<String> ids) { 93 Objects.requireNonNull(ids); 94 Objects.requireNonNull(idColumnName); 95 96 mIds = ids.stream().map(StorageUtils::getNormalisedString).toList(); 97 mIdColumnName = idColumnName; 98 return this; 99 } 100 setId(@onNull String idColumnName, @NonNull String id)101 public DeleteTableRequest setId(@NonNull String idColumnName, @NonNull String id) { 102 Objects.requireNonNull(id); 103 Objects.requireNonNull(idColumnName); 104 105 mIds = Collections.singletonList(StorageUtils.getNormalisedString(id)); 106 mIdColumnName = idColumnName; 107 return this; 108 } 109 requiresRead()110 public boolean requiresRead() { 111 return mRequiresUuId || mEnforcePackageCheck; 112 } 113 setRequiresUuId(@onNull String idColumnName)114 public DeleteTableRequest setRequiresUuId(@NonNull String idColumnName) { 115 Objects.requireNonNull(idColumnName); 116 117 mRequiresUuId = true; 118 mIdColumnName = idColumnName; 119 120 return this; 121 } 122 getRecordType()123 public int getRecordType() { 124 return mRecordType; 125 } 126 127 @Nullable getIdColumnName()128 public String getIdColumnName() { 129 return mIdColumnName; 130 } 131 132 @NonNull getTableName()133 public String getTableName() { 134 return mTableName; 135 } 136 137 @NonNull setPackageFilter( String packageColumnName, List<Long> packageFilters)138 public DeleteTableRequest setPackageFilter( 139 String packageColumnName, List<Long> packageFilters) { 140 mPackageFilters = packageFilters; 141 mPackageColumnName = packageColumnName; 142 143 return this; 144 } 145 146 @NonNull getDeleteCommand()147 public String getDeleteCommand() { 148 return "DELETE FROM " + mTableName + getWhereCommand(); 149 } 150 getReadCommand()151 public String getReadCommand() { 152 return "SELECT " 153 + mIdColumnName 154 + ", " 155 + mPackageColumnName 156 + " FROM " 157 + mTableName 158 + getWhereCommand(); 159 } 160 getWhereCommand()161 public String getWhereCommand() { 162 WhereClauses whereClauses = 163 Objects.isNull(mCustomWhereClauses) ? new WhereClauses() : mCustomWhereClauses; 164 whereClauses.addWhereInLongsClause(mPackageColumnName, mPackageFilters); 165 whereClauses.addWhereBetweenTimeClause(mTimeColumnName, mStartTime, mEndTime); 166 whereClauses.addWhereInClauseWithoutQuotes(mIdColumnName, mIds); 167 168 if (Constants.DEBUG) { 169 Slog.d( 170 TAG, 171 "delete query: tableName: " 172 + mTableName 173 + " whereClause: " 174 + whereClauses.get(true)); 175 } 176 177 return whereClauses.get(true); 178 } 179 180 @NonNull setTimeFilter( @onNull String timeColumnName, long startTime, long endTime)181 public DeleteTableRequest setTimeFilter( 182 @NonNull String timeColumnName, long startTime, long endTime) { 183 Objects.requireNonNull(timeColumnName); 184 185 // Return if the params will result in no impact on the query 186 if (startTime < 0 || endTime < startTime) { 187 return this; 188 } 189 190 mStartTime = startTime; 191 mEndTime = endTime; 192 mTimeColumnName = timeColumnName; 193 194 return this; 195 } 196 197 /** 198 * Sets total number of UUIDs being deleted by this request. 199 * 200 * @param numberOfUuidsToDelete Number of UUIDs being deleted 201 */ setNumberOfUuidsToDelete(int numberOfUuidsToDelete)202 public void setNumberOfUuidsToDelete(int numberOfUuidsToDelete) { 203 this.mNumberOfUuidsToDelete = numberOfUuidsToDelete; 204 } 205 206 /** 207 * Total number of records deleted. 208 * 209 * @return Number of records deleted by this request 210 */ getTotalNumberOfRecordsDeleted()211 public int getTotalNumberOfRecordsDeleted() { 212 if (requiresRead()) { 213 return mNumberOfUuidsToDelete; 214 } 215 return mIds.size(); 216 } 217 } 218