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