1 /*
2  * Copyright 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 @file:JvmMultifileClass
18 @file:JvmName("RelationUtil")
19 
20 package androidx.room.util
21 
22 import androidx.annotation.RestrictTo
23 import androidx.collection.ArrayMap
24 import androidx.room.RoomDatabase
25 
26 /**
27  * Utility function used in generated code to recursively fetch relationships when the amount of
28  * keys exceed [RoomDatabase.MAX_BIND_PARAMETER_CNT].
29  *
30  * @param map - The map containing the relationship keys to fill-in.
31  * @param isRelationCollection - True if [V] is a [Collection] which means it is non null.
32  * @param fetchBlock - A lambda for calling the generated _fetchRelationship function.
33  */
34 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
recursiveFetchHashMapnull35 fun <K : Any, V> recursiveFetchHashMap(
36     map: HashMap<K, V>,
37     isRelationCollection: Boolean,
38     fetchBlock: (HashMap<K, V>) -> Unit
39 ) {
40     val tmpMap = HashMap<K, V>(RoomDatabase.MAX_BIND_PARAMETER_CNT)
41     var count = 0
42     for (key in map.keys) {
43         // Safe because `V` is a nullable type arg when isRelationCollection == false and vice versa
44         @Suppress("UNCHECKED_CAST")
45         if (isRelationCollection) {
46             tmpMap[key] = map[key] as V
47         } else {
48             tmpMap[key] = null as V
49         }
50         count++
51         if (count == RoomDatabase.MAX_BIND_PARAMETER_CNT) {
52             // recursively load that batch
53             fetchBlock(tmpMap)
54             // for non collection relation, put the loaded batch in the original map,
55             // not needed when dealing with collections since references are passed
56             if (!isRelationCollection) {
57                 map.putAll(tmpMap)
58             }
59             tmpMap.clear()
60             count = 0
61         }
62     }
63     if (count > 0) {
64         // load the last batch
65         fetchBlock(tmpMap)
66         // for non collection relation, put the last batch in the original map
67         if (!isRelationCollection) {
68             map.putAll(tmpMap)
69         }
70     }
71 }
72 
73 /** Same as [recursiveFetchHashMap] but for [ArrayMap]. */
74 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
recursiveFetchArrayMapnull75 fun <K : Any, V> recursiveFetchArrayMap(
76     map: ArrayMap<K, V>,
77     isRelationCollection: Boolean,
78     fetchBlock: (ArrayMap<K, V>) -> Unit
79 ) {
80     val tmpMap = ArrayMap<K, V>(RoomDatabase.MAX_BIND_PARAMETER_CNT)
81     var count = 0
82     var mapIndex = 0
83     val limit = map.size
84     while (mapIndex < limit) {
85         if (isRelationCollection) {
86             tmpMap[map.keyAt(mapIndex)] = map.valueAt(mapIndex)
87         } else {
88             tmpMap[map.keyAt(mapIndex)] = null
89         }
90         mapIndex++
91         count++
92         if (count == RoomDatabase.MAX_BIND_PARAMETER_CNT) {
93             fetchBlock(tmpMap)
94             if (!isRelationCollection) {
95                 // Cast needed to disambiguate from putAll(SimpleArrayMap)
96                 map.putAll(tmpMap as Map<K, V>)
97             }
98             tmpMap.clear()
99             count = 0
100         }
101     }
102     if (count > 0) {
103         fetchBlock(tmpMap)
104         if (!isRelationCollection) {
105             // Cast needed to disambiguate from putAll(SimpleArrayMap)
106             map.putAll(tmpMap as Map<K, V>)
107         }
108     }
109 }
110