com.abubusoft.kripton.processor.sqlite.AbstractSelectCodeGenerator Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2015, 2017 Francesco Benincasa ([email protected]).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.abubusoft.kripton.processor.sqlite;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.Modifier;
import com.abubusoft.kripton.android.Logger;
import com.abubusoft.kripton.android.annotation.BindSqlSelect;
import com.abubusoft.kripton.android.sqlite.KriptonContentValues;
import com.abubusoft.kripton.android.sqlite.OnReadBeanListener;
import com.abubusoft.kripton.android.sqlite.OnReadCursorListener;
import com.abubusoft.kripton.common.CaseFormat;
import com.abubusoft.kripton.common.One;
import com.abubusoft.kripton.common.Pair;
import com.abubusoft.kripton.common.Triple;
import com.abubusoft.kripton.processor.BaseProcessor;
import com.abubusoft.kripton.processor.KriptonLiveDataManager;
import com.abubusoft.kripton.processor.core.AssertKripton;
import com.abubusoft.kripton.processor.core.ImmutableUtility;
import com.abubusoft.kripton.processor.core.ModelAnnotation;
import com.abubusoft.kripton.processor.core.reflect.PropertyUtility;
import com.abubusoft.kripton.processor.core.reflect.TypeUtility;
import com.abubusoft.kripton.processor.exceptions.InvalidMethodSignException;
import com.abubusoft.kripton.processor.sqlite.SelectBuilderUtility.SelectCodeGenerator;
import com.abubusoft.kripton.processor.sqlite.SelectBuilderUtility.SelectType;
import com.abubusoft.kripton.processor.sqlite.SqlSelectBuilder.SplittedSql;
import com.abubusoft.kripton.processor.sqlite.core.JavadocUtility;
import com.abubusoft.kripton.processor.sqlite.grammars.jql.JQLChecker;
import com.abubusoft.kripton.processor.sqlite.grammars.jql.JQLProjection;
import com.abubusoft.kripton.processor.sqlite.grammars.jql.JQLReplaceVariableStatementListenerImpl;
import com.abubusoft.kripton.processor.sqlite.model.SQLProperty;
import com.abubusoft.kripton.processor.sqlite.model.SQLiteDaoDefinition;
import com.abubusoft.kripton.processor.sqlite.model.SQLiteEntity;
import com.abubusoft.kripton.processor.sqlite.model.SQLiteModelMethod;
import com.abubusoft.kripton.processor.sqlite.transform.SQLTransformer;
import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.MethodSpec.Builder;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
/**
* The Class AbstractSelectCodeGenerator.
*/
public abstract class AbstractSelectCodeGenerator implements SelectCodeGenerator {
/** The Constant LIVE_DATA_PREFIX. */
public static final String LIVE_DATA_PREFIX = "ForLiveData";
/**
* The Enum JavadocPartType.
*/
public enum JavadocPartType {
/** The add parameter. */
ADD_PARAMETER,
/** The return. */
RETURN
}
/**
* generate code for sub queries
*
* @param methodBuilder
* @param method
*/
protected void generateSubQueries(Builder methodBuilder, SQLiteModelMethod method) {
SQLiteEntity entity = method.getEntity();
for (Triple item : method.childrenSelects) {
TypeName entityTypeName = TypeUtility.typeName(entity.getElement());
String setter;
if (entity.isImmutablePojo()) {
String idGetter = ImmutableUtility.IMMUTABLE_PREFIX + entity.getPrimaryKey().getName();
setter = ImmutableUtility.IMMUTABLE_PREFIX + entity.findRelationByParentProperty(item.value0).value0.getName() + "="
+ String.format("this.daoFactory.get%s().%s(%s)", item.value2.getParent().getName(), item.value2.getName(), idGetter);
} else {
String idGetter = PropertyUtility.getter("resultBean", entityTypeName, entity.getPrimaryKey());
setter = PropertyUtility.setter(entityTypeName, "resultBean", entity.findRelationByParentProperty(item.value0).value0,
String.format("this.daoFactory.get%s().%s(%s)", item.value2.getParent().getName(), item.value2.getName(), idGetter));
}
methodBuilder.addComment("sub query: $L", setter);
methodBuilder.addStatement("$L", setter);
}
}
/**
* The Class JavadocPart.
*/
public static class JavadocPart {
/** The javadoc part type. */
public final JavadocPartType javadocPartType;
/** The name. */
public final String name;
/** The description. */
public final String description;
/**
* Instantiates a new javadoc part.
*
* @param javadocPartType
* the javadoc part type
* @param name
* the name
* @param description
* the description
*/
JavadocPart(JavadocPartType javadocPartType, String name, String description) {
this.javadocPartType = javadocPartType;
this.name = name;
this.description = description;
}
/**
* Builds the.
*
* @param javadocPartType
* the javadoc part type
* @param name
* the name
* @param description
* the description
* @return the javadoc part
*/
public static JavadocPart build(JavadocPartType javadocPartType, String name, String description) {
return new JavadocPart(javadocPartType, name, description);
}
}
/**
* The Enum GenerationType.
*/
public enum GenerationType {
/** The all. */
ALL(true, true, true),
/** The no close cursor. */
NO_CLOSE_CURSOR(true, true, false),
/** The no method sign. */
NO_METHOD_SIGN(false, true, true),
/** The no content. */
NO_CONTENT(true, false, true);
/**
* Instantiates a new generation type.
*
* @param generateMethodSign
* the generate method sign
* @param generateMethodContent
* the generate method content
* @param generateCloseableCursor
* the generate closeable cursor
*/
GenerationType(boolean generateMethodSign, boolean generateMethodContent, boolean generateCloseableCursor) {
this.generateMethodSign = generateMethodSign;
this.generateMethodContent = generateMethodContent;
this.generateCloseableCursor = generateCloseableCursor;
}
/** The generate method sign. */
public final boolean generateMethodSign;
/** The generate method content. */
public final boolean generateMethodContent;
/** The generate closeable cursor. */
public final boolean generateCloseableCursor;
}
/** The select type. */
SelectType selectType;
/*
* (non-Javadoc)
*
* @see com.abubusoft.kripton.processor.sqlite.SelectBuilderUtility.
* SelectCodeGenerator#generate(com.squareup.javapoet.TypeSpec.Builder,
* boolean, com.abubusoft.kripton.processor.sqlite.model.SQLiteModelMethod)
*/
@Override
public void generate(TypeSpec.Builder classBuilder, boolean mapFields, SQLiteModelMethod method) {
Set fieldList = JQLChecker.getInstance().extractProjections(method, method.jql.value, method.getEntity());
// generate method code
MethodSpec.Builder methodBuilder = generateMethodBuilder(method);
generateCommonPart(method, classBuilder, methodBuilder, fieldList, true);
methodBuilder.addComment("Specialized part - $L - BEGIN", this.getClass().getSimpleName());
generateSpecializedPart(method, classBuilder, methodBuilder, fieldList, selectType.isMapFields());
methodBuilder.addComment("Specialized part - $L - END", this.getClass().getSimpleName());
if (!method.isPagedLiveData()) {
// method ForLiveData do not have to be generated for paged live
// data
classBuilder.addMethod(methodBuilder.build());
}
}
/**
* generate live data method.
*
* @param classBuilder
* the class builder
* @param method
* the method
*/
@Override
public void generateLiveData(TypeSpec.Builder classBuilder, SQLiteModelMethod method) {
SQLiteDaoDefinition daoDefinition = method.getParent();
Set fieldList = JQLChecker.getInstance().extractProjections(method, method.jql.value, method.getEntity());
// generate method code
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(method.getName().replaceAll(LIVE_DATA_PREFIX, "")).addAnnotation(Override.class).addModifiers(Modifier.PUBLIC);
methodBuilder.addJavadoc("Live data
\n");
methodBuilder.addJavadoc("This method open a connection internally.
\n\n");
generateCommonPart(method, classBuilder, methodBuilder, fieldList, GenerationType.NO_CONTENT, method.liveDataReturnClass, true, false);
boolean pagedLiveData = method.isPagedLiveData();
if (pagedLiveData) {
SelectType.PAGED_RESULT.generate(classBuilder, method);
String pageResultName = SelectPaginatedResultHelper.getCurrentPagedResultClass();
SelectPaginatedResultHelper.createPagedResult(method, pageResultName, methodBuilder);
}
ClassName dataSourceClazz = BindDataSourceBuilder.generateDataSourceName(daoDefinition.getParent());
ClassName daoFactoryClazz = TypeUtility.className(BindDaoFactoryBuilder.generateDaoFactoryName(daoDefinition.getParent()));
ClassName batchClazz = TypeUtility.mergeTypeNameWithSuffix(dataSourceClazz, ".Batch");
List> methodParameters = method.getParameters();
StringBuilder buffer = new StringBuilder();
String separator = "";
for (Pair item : methodParameters) {
buffer.append(separator + item.value0);
separator = ", ";
}
ClassName handlerClass = KriptonLiveDataManager.getInstance().getLiveDataHandlerClazz();
if (pagedLiveData) {
handlerClass = KriptonLiveDataManager.getInstance().getPagedLiveDataHandlerClazz();
TypeSpec batchBuilder = TypeSpec.anonymousClassBuilder("").addSuperinterface(ParameterizedTypeName.get(batchClazz, method.getReturnClass()))
.addMethod(
MethodSpec.methodBuilder("onExecute").addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).addParameter(ParameterSpec.builder(daoFactoryClazz, "daoFactory").build())
.returns(method.getReturnClass()).addStatement("return paginatedResult.execute(daoFactory)").build())
.build();
// return
TypeSpec.Builder liveDataBuilderBuilder = TypeSpec.anonymousClassBuilder("paginatedResult")
.addSuperinterface(ParameterizedTypeName.get(handlerClass, method.getReturnClass())).addMethod(MethodSpec.methodBuilder("compute").addAnnotation(Override.class)
.addModifiers(Modifier.PROTECTED).returns(method.getReturnClass()).addStatement("return $T.getInstance().executeBatch($L)", dataSourceClazz, batchBuilder).build());
TypeSpec liveDataBuilder = liveDataBuilderBuilder.build();
methodBuilder.addStatement("final $T builder=$L", ParameterizedTypeName.get(handlerClass, method.getReturnClass()), liveDataBuilder);
} else {
TypeSpec batchBuilder = TypeSpec.anonymousClassBuilder("").addSuperinterface(ParameterizedTypeName.get(batchClazz, method.getReturnClass()))
.addMethod(MethodSpec.methodBuilder("onExecute").addAnnotation(Override.class).addModifiers(Modifier.PUBLIC)
.addParameter(ParameterSpec.builder(daoFactoryClazz, "daoFactory").build()).returns(method.getReturnClass())
.addStatement("return daoFactory.get$L().$L($L)", daoDefinition.getName(), method.getName() + LIVE_DATA_PREFIX, buffer.toString()).build())
.build();
TypeSpec.Builder liveDataBuilderBuilder = TypeSpec.anonymousClassBuilder("").addSuperinterface(ParameterizedTypeName.get(handlerClass, method.getReturnClass()))
.addMethod(MethodSpec.methodBuilder("compute").addAnnotation(Override.class).addModifiers(Modifier.PROTECTED).returns(method.getReturnClass())
.addStatement("return $T.getInstance().executeBatch($L)", dataSourceClazz, batchBuilder).build());
TypeSpec liveDataBuilder = liveDataBuilderBuilder.build();
methodBuilder.addStatement("final $T builder=$L", ParameterizedTypeName.get(handlerClass, method.getReturnClass()), liveDataBuilder);
}
methodBuilder.addStatement("registryLiveData(builder)");
methodBuilder.addStatement("return builder.getLiveData()");
classBuilder.addMethod(methodBuilder.build());
}
/**
* Generate common part.
*
* @param method
* the method
* @param classBuilder
* the class builder
* @param methodBuilder
* the method builder
* @param fieldList
* the field list
* @param mapFields
* the map fields
*/
public void generateCommonPart(SQLiteModelMethod method, TypeSpec.Builder classBuilder, MethodSpec.Builder methodBuilder, Set fieldList, boolean generateSqlField) {
generateCommonPart(method, classBuilder, methodBuilder, fieldList, GenerationType.ALL, null, generateSqlField, false);
}
/**
* @param method
* @param classBuilder
* @param methodBuilder
* @param fieldList
* @param generationType
* @param forcedReturnType
* @param generateSqlField
* if true, it will generate
* @param countQuery
* if true, the query is a total count query
* @param javadocParts
*/
public void generateCommonPart(SQLiteModelMethod method, TypeSpec.Builder classBuilder, MethodSpec.Builder methodBuilder, Set fieldList, GenerationType generationType,
TypeName forcedReturnType, boolean generateSqlField, boolean countQuery, JavadocPart... javadocParts) {
SQLiteDaoDefinition daoDefinition = method.getParent();
SQLiteEntity entity = method.getEntity();
// if true, field must be associate to ben attributes
// TypeName returnType = method.getReturnClass();
TypeName returnTypeName = forcedReturnType;
if (returnTypeName == null) {
returnTypeName = method.getReturnClass();
}
ModelAnnotation annotation = method.getAnnotation(BindSqlSelect.class);
// parameters
List paramNames = new ArrayList();
List paramGetters = new ArrayList();
List paramTypeNames = new ArrayList();
List usedBeanPropertyNames = new ArrayList<>();
// used method parameters
Set usedMethodParameters = new HashSet();
final One whereJQL = new One<>("");
final One havingJQL = new One<>("");
final One groupJQL = new One<>("");
final One orderJQL = new One<>("");
// extract parts of jql statement
JQLChecker.getInstance().replaceVariableStatements(method, method.jql.value, new JQLReplaceVariableStatementListenerImpl() {
@Override
public String onWhere(String statement) {
whereJQL.value0 = statement;
return null;
}
@Override
public String onOrderBy(String statement) {
orderJQL.value0 = statement;
return null;
}
@Override
public String onHaving(String statement) {
havingJQL.value0 = statement;
return null;
}
@Override
public String onGroup(String statement) {
groupJQL.value0 = statement;
return null;
}
});
SqlAnalyzer analyzer = new SqlAnalyzer();
// String whereSQL =
// annotation.getAttribute(AnnotationAttributeType.WHERE);
analyzer.execute(BaseProcessor.elementUtils, method, whereJQL.value0);
paramGetters.addAll(analyzer.getParamGetters());
paramNames.addAll(analyzer.getParamNames());
paramTypeNames.addAll(analyzer.getParamTypeNames());
usedBeanPropertyNames.addAll(analyzer.getUsedBeanPropertyNames());
usedMethodParameters.addAll(analyzer.getUsedMethodParameters());
// String havingSQL =
// annotation.getAttribute(AnnotationAttributeType.HAVING);
analyzer.execute(BaseProcessor.elementUtils, method, havingJQL.value0);
paramGetters.addAll(analyzer.getParamGetters());
paramNames.addAll(analyzer.getParamNames());
paramTypeNames.addAll(analyzer.getParamTypeNames());
usedBeanPropertyNames.addAll(analyzer.getUsedBeanPropertyNames());
usedMethodParameters.addAll(analyzer.getUsedMethodParameters());
// String groupBySQL =
// annotation.getAttribute(AnnotationAttributeType.GROUP_BY);
analyzer.execute(BaseProcessor.elementUtils, method, groupJQL.value0);
paramGetters.addAll(analyzer.getParamGetters());
paramNames.addAll(analyzer.getParamNames());
paramTypeNames.addAll(analyzer.getParamTypeNames());
usedBeanPropertyNames.addAll(analyzer.getUsedBeanPropertyNames());
usedMethodParameters.addAll(analyzer.getUsedMethodParameters());
// String orderBySQL =
// annotation.getAttribute(AnnotationAttributeType.ORDER_BY);
analyzer.execute(BaseProcessor.elementUtils, method, orderJQL.value0);
paramGetters.addAll(analyzer.getParamGetters());
paramNames.addAll(analyzer.getParamNames());
paramTypeNames.addAll(analyzer.getParamTypeNames());
usedBeanPropertyNames.addAll(analyzer.getUsedBeanPropertyNames());
usedMethodParameters.addAll(analyzer.getUsedMethodParameters());
// add as used parameter dynamic components too
if (method.hasDynamicWhereConditions()) {
AssertKripton.assertTrueOrInvalidMethodSignException(!usedMethodParameters.contains(method.dynamicWhereParameterName), method,
" parameter %s is used like SQL parameter and dynamic WHERE condition.", method.dynamicOrderByParameterName);
usedMethodParameters.add(method.dynamicWhereParameterName);
if (method.hasDynamicWhereArgs()) {
AssertKripton.assertTrueOrInvalidMethodSignException(!usedMethodParameters.contains(method.dynamicWhereArgsParameterName), method,
" parameter %s is used like SQL parameter and dynamic WHERE ARGS condition.", method.dynamicWhereArgsParameterName);
usedMethodParameters.add(method.dynamicWhereArgsParameterName);
}
}
if (method.hasDynamicOrderByConditions()) {
AssertKripton.assertTrueOrInvalidMethodSignException(!usedMethodParameters.contains(method.dynamicOrderByParameterName), method,
" parameter %s is used like SQL parameter and dynamic ORDER BY condition.", method.dynamicOrderByParameterName);
usedMethodParameters.add(method.dynamicOrderByParameterName);
}
if (method.hasDynamicPageSizeConditions()) {
AssertKripton.assertTrueOrInvalidMethodSignException(!usedMethodParameters.contains(method.dynamicPageSizeName), method,
" parameter %s is used like SQL parameter and dynamic page size of LIMIT condition.", method.dynamicPageSizeName);
usedMethodParameters.add(method.dynamicPageSizeName);
}
// generate method signature
if (generationType.generateMethodSign) {
generateMethodSignature(method, methodBuilder, returnTypeName);
}
if (!countQuery) {
// generate javadoc
JavadocUtility.generateJavaDocForSelect(methodBuilder, paramNames, method, annotation, fieldList, selectType, javadocParts);
}
methodBuilder.addComment("common part generation - BEGIN");
if (generationType.generateMethodContent) {
SplittedSql splittedSql = SqlSelectBuilder.generateSQL(method, methodBuilder, countQuery);
if (countQuery) {
// if count query
splittedSql.sqlBasic = String.format(splittedSql.sqlBasic, "count(*)");
}
// retrieve content values
methodBuilder.addStatement("$T _contentValues=contentValues()", KriptonContentValues.class);
if (method.hasDynamicParts()) {
generateSQLBuild(method, methodBuilder, splittedSql, countQuery);
methodBuilder.addStatement("String _sql=_sqlBuilder.toString()");
} else {
String sqlName = "";
sqlName=CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, method.buildSQLName());
if (countQuery) {
String sql = SqlSelectBuilder.convertJQL2SQL(method, true);
sql="SELECT COUNT(*) FROM ("+sql+")";
// add static sql definition
classBuilder.addField(FieldSpec.builder(String.class, sqlName, Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL).initializer("$S", sql)
.addJavadoc("SQL definition for method $L\n", method.getName()).build());
} else if (generateSqlField) {
//sqlName = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, method.buildSQLName());
String sql = SqlSelectBuilder.convertJQL2SQL(method, true);
// add static sql definition
classBuilder.addField(FieldSpec.builder(String.class, sqlName, Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL).initializer("$S", sql)
.addJavadoc("SQL definition for method $L\n", method.getName()).build());
} else {
sqlName = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, method.buildSQLNameWithCurrentCounter());
}
methodBuilder.addComment("query SQL is statically defined");
methodBuilder.addStatement("String _sql=$L", sqlName);
}
// build where condition (common for every type of select)
StringBuilder logArgsBuffer = new StringBuilder();
methodBuilder.addComment("add where arguments");
{
String separator = "";
TypeName paramTypeName;
// String paramName;
boolean nullable;
int i = 0;
boolean rawParameters;
String beanName = null;
beanName = method.findEntityProperty();
for (String methodParam : paramGetters) {
rawParameters = paramNames.get(i).indexOf(".") == -1;
if (method.jql.spreadParams.contains(method.findParameterAliasByName(methodParam))) {
// paramTypeName = paramTypeNames.get(i);
String sizeMethod = "";
String elementMethod = "";
TypeName paramCollTypeName = paramTypeNames.get(i);
if (paramCollTypeName instanceof ArrayTypeName) {
sizeMethod = "length";
elementMethod = "[_i]";
paramTypeName = ((ArrayTypeName) paramCollTypeName).componentType;
} else if (paramCollTypeName instanceof ParameterizedTypeName) {
sizeMethod = "size()";
elementMethod = ".get(_i)";
paramTypeName = ((ParameterizedTypeName) paramCollTypeName).typeArguments.get(0);
} else {
paramTypeName = TypeName.get(String.class);
}
methodBuilder.beginControlFlow("if ($L!=null)", methodParam);
methodBuilder.addComment("$L is managed as spread param", methodParam);
methodBuilder.beginControlFlow("for (int _i=0; _i<$L.$L;_i++)", methodParam, sizeMethod);
methodBuilder.addCode(" _contentValues.addWhereArgs(");
generateRawWhereArg(method, methodBuilder, paramTypeName, TypeUtility.isNullable(paramTypeName), methodParam, methodParam + elementMethod);
methodBuilder.addCode(");\n");
methodBuilder.endControlFlow();
methodBuilder.endControlFlow();
} else {
paramTypeName = paramTypeNames.get(i);
methodBuilder.addCode("_contentValues.addWhereArgs(");
logArgsBuffer.append(separator + "%s");
// code for query arguments
nullable = TypeUtility.isNullable(paramTypeName);
if (rawParameters) {
generateRawWhereArg(method, methodBuilder, paramTypeName, nullable, methodParam);
} else {
// eventually we take associated property
SQLProperty property = usedBeanPropertyNames.get(i) == null ? null : entity.get(usedBeanPropertyNames.get(i));
if (nullable && !(property != null) && !method.hasAdapterForParam(methodParam)) {
methodBuilder.addCode("($L==null?\"\":", methodParam);
}
// check for string conversion
TypeUtility.beginStringConversion(methodBuilder, paramTypeName);
// if (property != null) {
// SQLTransformer.javaProperty2WhereCondition(methodBuilder,
// method, item, paramTypeName, property);
// } else {
SQLTransformer.javaProperty2WhereCondition(methodBuilder, method, beanName, paramTypeName, property);
// }
// check for string conversion
TypeUtility.endStringConversion(methodBuilder, paramTypeName);
if (nullable && !(property != null) && !method.hasAdapterForParam(methodParam)) {
methodBuilder.addCode(")");
}
}
methodBuilder.addCode(");\n");
}
separator = ", ";
i++;
}
}
methodBuilder.addStatement("String[] _sqlArgs=_contentValues.whereArgsAsArray()");
if (daoDefinition.isLogEnabled()) {
// generate log section - BEGIN
methodBuilder.addComment("log section for select BEGIN");
methodBuilder.beginControlFlow("if (_context.isLogEnabled())");
// manage log
methodBuilder.addComment("manage log");
methodBuilder.addStatement("$T.info(_sql)", Logger.class);
// log for where parames
SqlBuilderHelper.generateLogForWhereParameters(method, methodBuilder);
// generate log section - END
methodBuilder.endControlFlow();
methodBuilder.addComment("log section for select END");
}
ClassName cursorClass=ClassName.bestGuess("android.database.Cursor");
if (generationType.generateCloseableCursor) {
methodBuilder.beginControlFlow("try ($T _cursor = database().rawQuery(_sql, _sqlArgs))", cursorClass);
} else {
methodBuilder.addStatement("$T _cursor = database().rawQuery(_sql, _sqlArgs)", cursorClass);
}
if (daoDefinition.isLogEnabled()) {
// generate log section - BEGIN
methodBuilder.addComment("log section BEGIN");
methodBuilder.beginControlFlow("if (_context.isLogEnabled())");
methodBuilder.addCode("$T.info(\"Rows found: %s\",_cursor.getCount());\n", Logger.class);
// generate log section - END
methodBuilder.endControlFlow();
methodBuilder.addComment("log section END");
}
switch (selectType) {
case LISTENER_CURSOR: {
ClassName readCursorListenerToExclude = ClassName.get(OnReadCursorListener.class);
checkUnusedParameters(method, usedMethodParameters, readCursorListenerToExclude);
}
break;
case LISTENER_BEAN: {
ParameterizedTypeName readBeanListenerToExclude = ParameterizedTypeName.get(ClassName.get(OnReadBeanListener.class), TypeName.get(entity.getElement().asType()));
checkUnusedParameters(method, usedMethodParameters, readBeanListenerToExclude);
}
break;
default:
checkUnusedParameters(method, usedMethodParameters, null);
break;
}
}
methodBuilder.addComment("common part generation - END");
}
private void generateRawWhereArg(SQLiteModelMethod method, MethodSpec.Builder methodBuilder, TypeName paramTypeName, boolean nullable, String item) {
generateRawWhereArg(method, methodBuilder, paramTypeName, nullable, item, item);
}
/**
* @param method
* @param methodBuilder
* @param paramTypeName
* @param nullable
* @param methodItem
* is the name of method's parameter
* @param item
* is the name of used parameter
*/
private void generateRawWhereArg(SQLiteModelMethod method, MethodSpec.Builder methodBuilder, TypeName paramTypeName, boolean nullable, String methodItem, String item) {
if (nullable && !method.hasAdapterForParam(methodItem)) {
methodBuilder.addCode("($L==null?\"\":", item);
}
// check for string conversion
TypeUtility.beginStringConversion(methodBuilder, paramTypeName);
SQLTransformer.javaMethodParam2WhereConditions(methodBuilder, method, methodItem, item, paramTypeName);
// check for string conversion
TypeUtility.endStringConversion(methodBuilder, paramTypeName);
if (nullable && !method.hasAdapterForParam(methodItem)) {
methodBuilder.addCode(")");
}
}
/**
* Generate method builder.
*
* @param method
* the method
* @return the method spec. builder
*/
protected MethodSpec.Builder generateMethodBuilder(SQLiteModelMethod method) {
MethodSpec.Builder methodBuilder;
if (method.hasLiveData()) {
methodBuilder = MethodSpec.methodBuilder(method.getName() + LIVE_DATA_PREFIX).addModifiers(Modifier.PROTECTED);
} else {
methodBuilder = MethodSpec.methodBuilder(method.getName()).addAnnotation(Override.class).addModifiers(Modifier.PUBLIC);
}
return methodBuilder;
}
/**
* Generate method signature.
*
* @param method
* the method
* @param methodBuilder
* the method builder
* @param returnTypeName
* the return type name
* @param additionalParameterSpec
* the additional parameter spec
*/
protected void generateMethodSignature(SQLiteModelMethod method, MethodSpec.Builder methodBuilder, TypeName returnTypeName, ParameterSpec... additionalParameterSpec) {
boolean finalParameter = false;
if (method.hasLiveData() && returnTypeName.equals(method.liveDataReturnClass)) {
finalParameter = true;
}
// add parameter for method
for (Pair item : method.getParameters()) {
ParameterSpec.Builder builder = ParameterSpec.builder(item.value1, item.value0);
if (finalParameter) {
builder.addModifiers(Modifier.FINAL);
}
methodBuilder.addParameter(builder.build());
}
// add additional params
for (ParameterSpec item : additionalParameterSpec) {
methodBuilder.addParameter(item);
}
// add return type
methodBuilder.returns(returnTypeName);
}
/**
* Generate specialized part.
*
* @param method
* the method
* @param classBuilder
* the class builder
* @param methodBuilder
* the method builder
* @param fieldList
* the field list
* @param mapFields
* the map fields
*/
public abstract void generateSpecializedPart(SQLiteModelMethod method, TypeSpec.Builder classBuilder, MethodSpec.Builder methodBuilder, Set fieldList, boolean mapFields);
/*
* (non-Javadoc)
*
* @see com.abubusoft.kripton.processor.sqlite.SelectBuilderUtility.
* SelectCodeGenerator#setSelectResultTye(com.abubusoft.kripton.processor.
* sqlite.SelectBuilderUtility.SelectType)
*/
@Override
public void setSelectResultTye(SelectType value) {
this.selectType = value;
}
/**
* Check if there are unused method parameters. In this case an exception
* was throws.
*
* @param method
* the method
* @param usedMethodParameters
* the used method parameters
* @param excludedClasses
* the excluded classes
*/
public static void checkUnusedParameters(SQLiteModelMethod method, Set usedMethodParameters, TypeName excludedClasses) {
int paramsCount = method.getParameters().size();
int usedCount = usedMethodParameters.size();
if (paramsCount > usedCount) {
StringBuilder sb = new StringBuilder();
String separator = "";
for (Pair item : method.getParameters()) {
if (excludedClasses != null && item.value1.equals(excludedClasses)) {
usedCount++;
} else {
if (!usedMethodParameters.contains(item.value0)) {
sb.append(separator + "'" + item.value0 + "'");
separator = ", ";
}
}
}
if (paramsCount > usedCount) {
throw (new InvalidMethodSignException(method, "unused parameter(s) " + sb.toString()));
}
}
}
/**
* Generate SQL build.
*
* @param method
* the method
* @param methodBuilder
* the method builder
* @param splittedSql
* the splitted sql
* @param countQuery
* is true, the query manage the count query for paged result
*/
private static void generateSQLBuild(SQLiteModelMethod method, MethodSpec.Builder methodBuilder, SplittedSql splittedSql, boolean countQuery) {
methodBuilder.addStatement("$T _sqlBuilder=sqlBuilder()", StringBuilder.class);
methodBuilder.addStatement("_sqlBuilder.append($S)", splittedSql.sqlBasic.trim());
SqlModifyBuilder.generateInitForDynamicWhereVariables(method, methodBuilder, method.dynamicWhereParameterName, method.dynamicWhereArgsParameterName);
if (method.jql.isOrderBy()) {
methodBuilder.addStatement("String _sortOrder=$L", method.jql.paramOrderBy);
}
SqlBuilderHelper.generateWhereCondition(methodBuilder, method, false);
SqlSelectBuilder.generateDynamicPartOfQuery(method, methodBuilder, splittedSql, countQuery);
}
}