1846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar/*
2846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar * Copyright (C) 2017 The Android Open Source Project
3846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar *
4846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar * you may not use this file except in compliance with the License.
6846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar * You may obtain a copy of the License at
7846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar *
8846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar *
10846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar * See the License for the specific language governing permissions and
14846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar * limitations under the License.
15846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar */
16846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar
17bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viverettepackage androidx.room.solver.query.result
18846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar
19bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.annotation.NonNull
20bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.ext.L
21bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.ext.LifecyclesTypeNames
22bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.ext.N
23bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.ext.RoomTypeNames
24bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.ext.RoomTypeNames.INVALIDATION_OBSERVER
25bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.ext.typeName
26bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.solver.CodeGenScope
27846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyarimport com.squareup.javapoet.FieldSpec
28846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyarimport com.squareup.javapoet.MethodSpec
292ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Arakiimport com.squareup.javapoet.ParameterSpec
30846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyarimport com.squareup.javapoet.ParameterizedTypeName
31846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyarimport com.squareup.javapoet.TypeName
32846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyarimport com.squareup.javapoet.TypeSpec
33846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyarimport javax.lang.model.element.Modifier
34846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyarimport javax.lang.model.type.TypeMirror
35846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar
36846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar/**
37846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar * Converts the query into a LiveData and returns it. No query is run until necessary.
38846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar */
392c56b466fc39da8bc5cb82dc494e534768e65eabshepshapardclass LiveDataQueryResultBinder(val typeArg: TypeMirror, val tableNames: Set<String>,
40846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar                                adapter: QueryResultAdapter?)
413c592c4ccbc6052b11443b0fa575052c08fefa55Yigit Boyar    : BaseObservableQueryResultBinder(adapter) {
42092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    @Suppress("JoinDeclarationAndAssignment")
436f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    override fun convertAndReturn(
446f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            roomSQLiteQueryVar: String,
45de23b91b2c982ef5c93349b16415654ae3fe5ac9Yigit Boyar            canReleaseQuery: Boolean,
466f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            dbField: FieldSpec,
476f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            inTransaction: Boolean,
486f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            scope: CodeGenScope
496f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    ) {
50846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar        val typeName = typeArg.typeName()
51846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar
52846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar        val liveDataImpl = TypeSpec.anonymousClassBuilder("").apply {
53846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            superclass(ParameterizedTypeName.get(LifecyclesTypeNames.COMPUTABLE_LIVE_DATA,
54846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar                    typeName))
55b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            val observerField = FieldSpec.builder(RoomTypeNames.INVALIDATION_OBSERVER,
56b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    scope.getTmpVar("_observer"), Modifier.PRIVATE).build()
57b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            addField(observerField)
58846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            addMethod(createComputeMethod(
59b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    observerField = observerField,
60846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar                    typeName = typeName,
61b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    roomSQLiteQueryVar = roomSQLiteQueryVar,
62846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar                    dbField = dbField,
6325b465c796ebee5bd7d304becbcf6a42fed53056Yigit Boyar                    inTransaction = inTransaction,
64846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar                    scope = scope
65846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            ))
66de23b91b2c982ef5c93349b16415654ae3fe5ac9Yigit Boyar            if (canReleaseQuery) {
67de23b91b2c982ef5c93349b16415654ae3fe5ac9Yigit Boyar                addMethod(createFinalizeMethod(roomSQLiteQueryVar))
68de23b91b2c982ef5c93349b16415654ae3fe5ac9Yigit Boyar            }
69846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar        }.build()
70846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar        scope.builder().apply {
71f59164365fb6de9f148b597af5a6e19b3b7c8c2eYigit Boyar            addStatement("return $L.getLiveData()", liveDataImpl)
72846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar        }
73846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar    }
74846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar
756f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    private fun createComputeMethod(
766f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            roomSQLiteQueryVar: String,
776f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            typeName: TypeName,
786f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            observerField: FieldSpec,
796f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            dbField: FieldSpec,
806f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            inTransaction: Boolean,
816f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas            scope: CodeGenScope
826f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    ): MethodSpec {
83846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar        return MethodSpec.methodBuilder("compute").apply {
84846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            addAnnotation(Override::class.java)
85846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            addModifiers(Modifier.PROTECTED)
86846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            returns(typeName)
87846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar
88b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            beginControlFlow("if ($N == null)", observerField).apply {
89b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                addStatement("$N = $L", observerField, createAnonymousObserver())
90b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                addStatement("$N.getInvalidationTracker().addWeakObserver($N)",
91b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                        dbField, observerField)
92846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            }
93846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            endControlFlow()
94846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar
9525b465c796ebee5bd7d304becbcf6a42fed53056Yigit Boyar            createRunQueryAndReturnStatements(builder = this,
9625b465c796ebee5bd7d304becbcf6a42fed53056Yigit Boyar                    roomSQLiteQueryVar = roomSQLiteQueryVar,
9725b465c796ebee5bd7d304becbcf6a42fed53056Yigit Boyar                    dbField = dbField,
9825b465c796ebee5bd7d304becbcf6a42fed53056Yigit Boyar                    inTransaction = inTransaction,
9925b465c796ebee5bd7d304becbcf6a42fed53056Yigit Boyar                    scope = scope)
100846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar        }.build()
101846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar    }
102846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar
103846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar    private fun createAnonymousObserver(): TypeSpec {
104092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        val tableNamesList = tableNames.joinToString(",") { "\"$it\"" }
105846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar        return TypeSpec.anonymousClassBuilder(tableNamesList).apply {
106846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            superclass(INVALIDATION_OBSERVER)
107846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            addMethod(MethodSpec.methodBuilder("onInvalidated").apply {
108846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar                returns(TypeName.VOID)
109846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar                addAnnotation(Override::class.java)
1102ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki                addParameter(ParameterSpec.builder(
1112ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki                        ParameterizedTypeName.get(Set::class.java, String::class.java), "tables")
1122ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki                        .addAnnotation(NonNull::class.java)
1132ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki                        .build())
114846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar                addModifiers(Modifier.PUBLIC)
115846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar                addStatement("invalidate()")
116846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            }.build())
117846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar        }.build()
118846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar    }
119846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar}
120