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.server.healthconnect.storage.request;
18 
19 import android.annotation.NonNull;
20 import android.util.Pair;
21 import android.util.Slog;
22 
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 
27 /**
28  * Creates a alter table request and alter statements for it.
29  *
30  * @hide
31  */
32 public final class AlterTableRequest {
33     public static final String TAG = "HealthConnectAlter";
34     private static final String ALTER_TABLE_COMMAND = "ALTER TABLE ";
35     private static final String ADD_COLUMN_COMMAND = " ADD COLUMN ";
36     private final String mTableName;
37     private final List<Pair<String, String>> mColumnInfo;
38 
39     private final Map<String, Pair<String, String>> mForeignKeyConstraints = new HashMap<>();
40 
AlterTableRequest(String tableName, List<Pair<String, String>> columnInfo)41     public AlterTableRequest(String tableName, List<Pair<String, String>> columnInfo) {
42         mTableName = tableName;
43         mColumnInfo = columnInfo;
44     }
45 
46     /**
47      * Adds a foreign key constraint between one column and another. Deletion behavior is to set
48      * dangling references to null.
49      */
50     @NonNull
addForeignKeyConstraint( String column, String referencedTable, String referencedColumn)51     public AlterTableRequest addForeignKeyConstraint(
52             String column, String referencedTable, String referencedColumn) {
53         mForeignKeyConstraints.put(column, new Pair<>(referencedTable, referencedColumn));
54         return this;
55     }
56 
57     /** Returns command for alter table request to add new columns */
getAlterTableAddColumnsCommand()58     public String getAlterTableAddColumnsCommand() {
59         final StringBuilder builder = new StringBuilder(ALTER_TABLE_COMMAND);
60         builder.append(mTableName);
61         for (int i = 0; i < mColumnInfo.size(); i++) {
62             String columnName = mColumnInfo.get(i).first;
63             String columnType = mColumnInfo.get(i).second;
64             builder.append(ADD_COLUMN_COMMAND).append(columnName).append(" ").append(columnType);
65             if (mForeignKeyConstraints.containsKey(columnName)) {
66                 builder.append(" ");
67                 builder.append("REFERENCES ");
68                 builder.append(mForeignKeyConstraints.get(columnName).first);
69                 builder.append("(");
70                 builder.append(mForeignKeyConstraints.get(columnName).second);
71                 builder.append(")");
72                 builder.append(" ON DELETE SET NULL");
73             }
74             builder.append(", ");
75         }
76         builder.setLength(builder.length() - 2); // Remove the last 2 char i.e. ", "
77         Slog.d(TAG, "Alter table: " + builder);
78 
79         return builder.toString();
80     }
81 
getAlterTableCommandToAddGeneratedColumn( String tableName, CreateTableRequest.GeneratedColumnInfo generatedColumnInfo)82     public static String getAlterTableCommandToAddGeneratedColumn(
83             String tableName, CreateTableRequest.GeneratedColumnInfo generatedColumnInfo) {
84         String request =
85                 ALTER_TABLE_COMMAND
86                         + tableName
87                         + ADD_COLUMN_COMMAND
88                         + generatedColumnInfo.getColumnName()
89                         + " "
90                         + generatedColumnInfo.getColumnType()
91                         + " GENERATED ALWAYS AS ("
92                         + generatedColumnInfo.getExpression()
93                         + ")";
94 
95         Slog.d(TAG, "Alter table generated: " + request);
96         return request;
97     }
98 }
99