1 /*
2  * Copyright (C) 2017 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 android.inputmethodservice.cts.db;
18 
19 import android.database.Cursor;
20 import android.provider.BaseColumns;
21 
22 import androidx.annotation.NonNull;
23 
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 
29 /**
30  * Abstraction of SQLite database row.
31  * @param <E> type of entities.
32  */
33 public final class Entity<E> {
34 
35     private final List<Field> mFields;
36     private final Map<String, Field> mFieldMap;
37 
Entity(Builder<E> builder)38     private Entity(Builder<E> builder) {
39         mFields = builder.mFields;
40         mFieldMap = builder.mFieldMap;
41     }
42 
43     /**
44      * Returns SQL statement to create this entity/row, such that
45      * "(_id INTEGER PRIMARY KEY AUTOINCREMENT, column2_name column2_type, ...)".
46      */
createEntitySql()47     String createEntitySql() {
48         final StringBuilder sb = new StringBuilder("(");
49         for (Field field : mFields) {
50             if (field.mPos > 0) sb.append(", ");
51             sb.append(field.mName).append(" ").append(field.mSqLiteType);
52             if (field.mName.equals(BaseColumns._ID)) {
53                 sb.append(" PRIMARY KEY AUTOINCREMENT");
54             }
55         }
56         return sb.append(")").toString();
57     }
58 
getField(String fieldName)59     Field getField(String fieldName) {
60         return mFieldMap.get(fieldName);
61     }
62 
63     /**
64      * {@link Entity} builder.
65      * @param <E> type of entities.
66      */
67     public static final class Builder<E> {
68         private final List<Field> mFields = new ArrayList<>();
69         private final Map<String, Field> mFieldMap = new HashMap<>();
70         private int mPos = 0;
71 
72         /**
73          * Constructor or {@link Builder}.
74          */
Builder()75         public Builder() {
76             addFieldInternal(BaseColumns._ID, Cursor.FIELD_TYPE_INTEGER);
77         }
78 
79         /**
80          * Add a new field with given name and type.
81          *
82          * @param name name of the field
83          * @param fieldType type enum of the field
84          * @return this builder, useful for chaining
85          */
addField(@onNull String name, int fieldType)86         public Builder<E> addField(@NonNull String name, int fieldType) {
87             addFieldInternal(name, fieldType);
88             return this;
89         }
90 
91         /**
92          * Build {@link Entity}.
93          *
94          * @return a new instance of {@link Entity} built from this builder.
95          */
build()96         public Entity<E> build() {
97             return new Entity<>(this);
98         }
99 
addFieldInternal(String name, int fieldType)100         private void addFieldInternal(String name, int fieldType) {
101             if (mFieldMap.containsKey(name)) {
102                 throw new IllegalArgumentException("Field " + name + " already exists at "
103                         + mFieldMap.get(name).mPos);
104             }
105             final Field field = Field.newInstance(mPos++, name, fieldType);
106             mFields.add(field);
107             mFieldMap.put(field.mName, field);
108         }
109     }
110 }
111