• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_PAGE_SIZE;
20 
21 import static com.android.server.healthconnect.storage.utils.StorageUtils.DELIMITER;
22 import static com.android.server.healthconnect.storage.utils.StorageUtils.LIMIT_SIZE;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.health.connect.Constants;
27 import android.util.Slog;
28 
29 import com.android.server.healthconnect.storage.TransactionManager;
30 import com.android.server.healthconnect.storage.datatypehelpers.RecordHelper;
31 import com.android.server.healthconnect.storage.utils.OrderByClause;
32 import com.android.server.healthconnect.storage.utils.SqlJoin;
33 import com.android.server.healthconnect.storage.utils.WhereClauses;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.Objects;
38 
39 /**
40  * A request for {@link TransactionManager} to read the DB
41  *
42  * @hide
43  */
44 public class ReadTableRequest {
45     private static final String TAG = "HealthConnectRead";
46     private static final String UNION_ALL = " UNION ALL ";
47 
48     private final String mTableName;
49     private RecordHelper<?> mRecordHelper;
50     private List<String> mColumnNames;
51     private SqlJoin mJoinClause;
52     private WhereClauses mWhereClauses = new WhereClauses();
53     private boolean mDistinct = false;
54     private OrderByClause mOrderByClause = new OrderByClause();
55     private String mLimitClause = "";
56     private int mPageSize = DEFAULT_PAGE_SIZE;
57     private List<ReadTableRequest> mExtraReadRequests;
58     private List<ReadTableRequest> mUnionReadRequests;
59 
ReadTableRequest(@onNull String tableName)60     public ReadTableRequest(@NonNull String tableName) {
61         Objects.requireNonNull(tableName);
62 
63         mTableName = tableName;
64     }
65 
getRecordHelper()66     public RecordHelper<?> getRecordHelper() {
67         return mRecordHelper;
68     }
69 
setRecordHelper(RecordHelper<?> recordHelper)70     public ReadTableRequest setRecordHelper(RecordHelper<?> recordHelper) {
71         mRecordHelper = recordHelper;
72         return this;
73     }
74 
setColumnNames(@onNull List<String> columnNames)75     public ReadTableRequest setColumnNames(@NonNull List<String> columnNames) {
76         Objects.requireNonNull(columnNames);
77 
78         mColumnNames = columnNames;
79         return this;
80     }
81 
setWhereClause(WhereClauses whereClauses)82     public ReadTableRequest setWhereClause(WhereClauses whereClauses) {
83         mWhereClauses = whereClauses;
84         return this;
85     }
86 
87     /** Used to set Join Clause for the read query */
88     @NonNull
setJoinClause(SqlJoin joinClause)89     public ReadTableRequest setJoinClause(SqlJoin joinClause) {
90         mJoinClause = joinClause;
91         return this;
92     }
93 
94     /**
95      * Use this method to enable the Distinct clause in the read command.
96      *
97      * <p><b>NOTE: make sure to use the {@link ReadTableRequest#setColumnNames(List)} to set the
98      * column names to be used as the selection args.</b>
99      */
100     @NonNull
setDistinctClause(boolean isDistinctValuesRequired)101     public ReadTableRequest setDistinctClause(boolean isDistinctValuesRequired) {
102         mDistinct = isDistinctValuesRequired;
103         return this;
104     }
105 
106     /** Returns SQL statement to perform read operation. */
107     @NonNull
getReadCommand()108     public String getReadCommand() {
109         StringBuilder builder = new StringBuilder("SELECT ");
110         if (mDistinct) {
111             builder.append("DISTINCT ");
112             builder.append(getColumnsToFetch());
113         } else {
114             builder.append(getColumnsToFetch());
115         }
116         builder.append(" FROM ");
117         builder.append(mTableName);
118 
119         builder.append(mWhereClauses.get(/* withWhereKeyword */ true));
120         builder.append(mOrderByClause.getOrderBy());
121         builder.append(mLimitClause);
122 
123         String readQuery = builder.toString();
124         if (mJoinClause != null) {
125             readQuery = mJoinClause.getJoinWithQueryCommand(readQuery);
126         }
127 
128         if (Constants.DEBUG) {
129             Slog.d(TAG, "read query: " + readQuery);
130         }
131 
132         if (mUnionReadRequests != null && !mUnionReadRequests.isEmpty()) {
133             builder = new StringBuilder();
134             for (ReadTableRequest unionReadRequest : mUnionReadRequests) {
135                 builder.append("SELECT * FROM (");
136                 builder.append(unionReadRequest.getReadCommand());
137                 builder.append(")");
138                 builder.append(UNION_ALL);
139             }
140 
141             builder.append(readQuery);
142 
143             return builder.toString();
144         }
145 
146         return readQuery;
147     }
148 
149     /** Get requests for populating extra data */
150     @Nullable
getExtraReadRequests()151     public List<ReadTableRequest> getExtraReadRequests() {
152         return mExtraReadRequests;
153     }
154 
155     /** Sets requests to populate extra data */
setExtraReadRequests(List<ReadTableRequest> extraDataReadRequests)156     public ReadTableRequest setExtraReadRequests(List<ReadTableRequest> extraDataReadRequests) {
157         mExtraReadRequests = new ArrayList<>(extraDataReadRequests);
158         return this;
159     }
160 
161     /** Get table name of the request */
getTableName()162     public String getTableName() {
163         return mTableName;
164     }
165 
166     /** Sets order by clause for the read query */
167     @NonNull
setOrderBy(OrderByClause orderBy)168     public ReadTableRequest setOrderBy(OrderByClause orderBy) {
169         mOrderByClause = orderBy;
170         return this;
171     }
172 
173     /** Sets LIMIT size for the read query */
174     @NonNull
setLimit(int pageSize)175     public ReadTableRequest setLimit(int pageSize) {
176         mPageSize = pageSize;
177         // We set limit size to requested pageSize + 1,so that if number of records queried is more
178         // than pageSize we know there are more records available to return for the next read.
179         pageSize += 1;
180         mLimitClause = LIMIT_SIZE + pageSize;
181         return this;
182     }
183 
184     /** Returns page size of the read request */
getPageSize()185     public int getPageSize() {
186         return mPageSize;
187     }
188 
getColumnsToFetch()189     private String getColumnsToFetch() {
190         if (mColumnNames == null || mColumnNames.isEmpty()) {
191             return "*";
192         }
193 
194         return String.join(DELIMITER, mColumnNames);
195     }
196 
setUnionReadRequests( @ullable List<ReadTableRequest> unionReadRequests)197     public ReadTableRequest setUnionReadRequests(
198             @Nullable List<ReadTableRequest> unionReadRequests) {
199         mUnionReadRequests = unionReadRequests;
200 
201         return this;
202     }
203 }
204