com.abubusoft.kripton.processor.sqlite.InsertBeanHelper 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 static com.abubusoft.kripton.processor.core.reflect.TypeUtility.typeName;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.Modifier;
import com.abubusoft.kripton.android.annotation.BindSqlInsert;
import com.abubusoft.kripton.android.sqlite.ConflictAlgorithmType;
import com.abubusoft.kripton.android.sqlite.KriptonContentValues;
import com.abubusoft.kripton.android.sqlite.KriptonDatabaseWrapper;
import com.abubusoft.kripton.common.Pair;
import com.abubusoft.kripton.processor.BaseProcessor;
import com.abubusoft.kripton.processor.core.AnnotationAttributeType;
import com.abubusoft.kripton.processor.core.AssertKripton;
import com.abubusoft.kripton.processor.core.ModelAnnotation;
import com.abubusoft.kripton.processor.core.ModelProperty;
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.GenericSQLHelper.SubjectType;
import com.abubusoft.kripton.processor.sqlite.SqlInsertBuilder.InsertCodeGenerator;
import com.abubusoft.kripton.processor.sqlite.grammars.jql.JQLChecker;
import com.abubusoft.kripton.processor.sqlite.grammars.jql.JQLReplacerListenerImpl;
import com.abubusoft.kripton.processor.sqlite.model.SQLiteDaoDefinition;
import com.abubusoft.kripton.processor.sqlite.model.SQLiteEntity;
import com.abubusoft.kripton.processor.sqlite.model.SQLProperty;
import com.abubusoft.kripton.processor.sqlite.model.SQLiteModelMethod;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import android.database.sqlite.SQLiteStatement;
// TODO: Auto-generated Javadoc
/**
* The Class InsertBeanHelper.
*/
public class InsertBeanHelper implements InsertCodeGenerator {
/* (non-Javadoc)
* @see com.abubusoft.kripton.processor.sqlite.SqlInsertBuilder.InsertCodeGenerator#generate(com.squareup.javapoet.TypeSpec.Builder, com.squareup.javapoet.MethodSpec.Builder, boolean, com.abubusoft.kripton.processor.sqlite.model.SQLiteModelMethod, com.squareup.javapoet.TypeName)
*/
@Override
public void generate(TypeSpec.Builder classBuilder, MethodSpec.Builder methodBuilder, boolean mapFields, SQLiteModelMethod method, TypeName returnType) {
SQLiteDaoDefinition daoDefinition = method.getParent();
SQLiteEntity entity = daoDefinition.getEntity();
// String sqlInsert;
// retrieve content values
if (method.jql.hasDynamicParts() || method.jql.containsSelectOperation) {
methodBuilder.addStatement("$T _contentValues=contentValuesForUpdate()", KriptonContentValues.class);
} else {
String psName=method.buildPreparedStatementName();
classBuilder.addField(FieldSpec.builder(TypeName.get(SQLiteStatement.class), psName, Modifier.PRIVATE, Modifier.STATIC).build());
methodBuilder.beginControlFlow("if ($L==null)",psName);
SqlBuilderHelper.generateSQLForStaticQuery(method, methodBuilder);
methodBuilder.addStatement("$L = $T.compile(_context, _sql)", psName, KriptonDatabaseWrapper.class);
methodBuilder.endControlFlow();
methodBuilder.addStatement("$T _contentValues=contentValuesForUpdate($L)", KriptonContentValues.class, psName);
}
List listUsedProperty = CodeBuilderUtility.extractUsedProperties(methodBuilder, method, BindSqlInsert.class);
CodeBuilderUtility.generateContentValuesFromEntity(BaseProcessor.elementUtils, method, BindSqlInsert.class, methodBuilder, null);
ModelProperty primaryKey = entity.getPrimaryKey();
// generate javadoc and query
generateJavaDoc(methodBuilder, method, returnType, listUsedProperty, primaryKey);
SqlBuilderHelper.generateLog(method, methodBuilder);
methodBuilder.addComment("insert operation");
if (method.jql.hasDynamicParts() || method.jql.containsSelectOperation) {
// does not memorize compiled statement, it can vary every time
// generate SQL for insert
SqlBuilderHelper.generateSQLForInsertDynamic(method, methodBuilder);
methodBuilder.addStatement("long result = $T.insert(_context, _sql, _contentValues)", KriptonDatabaseWrapper.class);
} else {
String psName=method.buildPreparedStatementName();
methodBuilder.addStatement("long result = $T.insert($L, _contentValues)", KriptonDatabaseWrapper.class, psName);
}
if (method.getParent().getParent().generateRx) {
GenericSQLHelper.generateSubjectNext(methodBuilder, SubjectType.INSERT);
}
if (primaryKey != null) {
if (primaryKey.isPublicField()) {
methodBuilder.addCode("$L.$L=result;\n", method.getParameters().get(0).value0, primaryKey.getName());
} else {
methodBuilder.addCode("$L.$L(result);\n", method.getParameters().get(0).value0, PropertyUtility.setter(typeName(entity.getElement()), primaryKey));
}
}
// support for livedata
if (daoDefinition.hasLiveData()) {
methodBuilder.addComment("support for livedata");
methodBuilder.addStatement(BindDaoBuilder.METHOD_NAME_REGISTRY_EVENT+"(result>0?1:0)");
}
// define return value
if (returnType == TypeName.VOID) {
} else if (TypeUtility.isTypeIncludedIn(returnType, String.class)) {
methodBuilder.addCode("\n");
methodBuilder.addCode("return String.valueOf(result);\n");
} else if (TypeUtility.isTypeIncludedIn(returnType, Boolean.TYPE, Boolean.class)) {
methodBuilder.addCode("\n");
methodBuilder.addCode("return result!=-1;\n");
} else if (TypeUtility.isTypeIncludedIn(returnType, Long.TYPE, Long.class)) {
methodBuilder.addCode("\n");
methodBuilder.addCode("return result;\n");
} else if (TypeUtility.isTypeIncludedIn(returnType, Integer.TYPE, Integer.class)) {
methodBuilder.addCode("\n");
methodBuilder.addCode("return (int)result;\n");
} else if (TypeUtility.isEquals(returnType, entity)) {
methodBuilder.addCode("\n");
methodBuilder.addCode("return $L;\n", method.getParameters().get(0).value0);
} else {
// more than one listener found
throw (new InvalidMethodSignException(method, "invalid return type"));
}
}
/**
* Generate java doc.
*
* @param methodBuilder the method builder
* @param method the method
* @param returnType the return type
* @param listUsedProperty the list used property
* @param primaryKey the primary key
*/
public void generateJavaDoc(MethodSpec.Builder methodBuilder, final SQLiteModelMethod method, TypeName returnType, List listUsedProperty, ModelProperty primaryKey) {
// transform JQL to SQL
String sqlInsert = JQLChecker.getInstance().replace(method, method.jql, new JQLReplacerListenerImpl(method) {
@Override
public String onColumnName(String columnName) {
Set property = currentSchema.getPropertyBySimpleName(columnName);
SQLProperty tempProperty = property.iterator().next();
AssertKripton.assertTrueOrUnknownPropertyInJQLException(tempProperty != null, method, columnName);
return tempProperty.columnName;
}
@Override
public String onBindParameter(String bindParameterName) {
String resolvedParamName = method.findParameterNameByAlias(bindParameterName);
return "${" + resolvedParamName + "}";
}
});
// generate javadoc and result
{
String beanNameParameter = method.findParameterAliasByName(method.getParameters().get(0).value0);
methodBuilder.addJavadoc("SQL insert:
\n");
methodBuilder.addJavadoc("$L
\n\n", sqlInsert);
methodBuilder.addJavadoc("$L.$L
is automatically updated because it is the primary key
\n", beanNameParameter, primaryKey.getName());
methodBuilder.addJavadoc("\n");
// list of inserted fields
methodBuilder.addJavadoc("Inserted columns:
\n");
methodBuilder.addJavadoc("\n");
for (SQLProperty property : listUsedProperty) {
methodBuilder.addJavadoc("\t- $L
", property.columnName);
methodBuilder.addJavadoc("- is mapped to $L
\n",
"${" + method.findParameterAliasByName(method.getParameters().get(0).value0) + "." + method.findParameterNameByAlias(property.getName()) + "}");
}
methodBuilder.addJavadoc("
\n\n");
// update bean have only one parameter: the bean to update
for (Pair param : method.getParameters()) {
methodBuilder.addJavadoc("@param $L", param.value0);
methodBuilder.addJavadoc("\n\tis mapped to parameter $L\n", method.findParameterAliasByName(param.value0));
}
InsertRawHelper.generateJavaDocReturnType(methodBuilder, returnType);
}
}
/**
* Gets the conflict algorithm type.
*
* @param method the method
* @return the conflict algorithm type
*/
public static ConflictAlgorithmType getConflictAlgorithmType(SQLiteModelMethod method) {
ModelAnnotation annotation = method.getAnnotation(BindSqlInsert.class);
String value = annotation.getAttribute(AnnotationAttributeType.CONFLICT_ALGORITHM_TYPE);
if (value != null && value.indexOf(".") > -1) {
value = value.substring(value.lastIndexOf(".") + 1);
}
ConflictAlgorithmType conflictAlgorithmType = ConflictAlgorithmType.valueOf(value);
return conflictAlgorithmType;
}
}