All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.abubusoft.kripton.processor.sqlite.ModifyRawHelper Maven / Gradle / Ivy

There is a newer version: 8.2.0-rc.4
Show newest version
/*******************************************************************************
 * 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.isNullable;

import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.Modifier;

import com.abubusoft.kripton.android.sqlite.KriptonContentValues;
import com.abubusoft.kripton.android.sqlite.KriptonDatabaseWrapper;
import com.abubusoft.kripton.common.One;
import com.abubusoft.kripton.common.Pair;
import com.abubusoft.kripton.common.StringUtils;
import com.abubusoft.kripton.processor.core.AssertKripton;
import com.abubusoft.kripton.processor.core.reflect.TypeUtility;
import com.abubusoft.kripton.processor.exceptions.InvalidMethodSignException;
import com.abubusoft.kripton.processor.exceptions.PropertyNotFoundException;
import com.abubusoft.kripton.processor.sqlite.SqlModifyBuilder.ModifyCodeGenerator;
import com.abubusoft.kripton.processor.sqlite.grammars.jql.JQL.JQLDynamicStatementType;
import com.abubusoft.kripton.processor.sqlite.grammars.jql.JQLChecker;
import com.abubusoft.kripton.processor.sqlite.grammars.jql.JQLReplaceVariableStatementListenerImpl;
import com.abubusoft.kripton.processor.sqlite.grammars.jql.JQLReplacerListenerImpl;
import com.abubusoft.kripton.processor.sqlite.grammars.jsql.JqlParser.Where_stmtContext;
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.abubusoft.kripton.processor.sqlite.transform.SQLTransformer;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.MethodSpec.Builder;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import android.database.sqlite.SQLiteStatement;

// TODO: Auto-generated Javadoc
/**
 * The Class ModifyRawHelper.
 */
public class ModifyRawHelper implements ModifyCodeGenerator {

	/* (non-Javadoc)
	 * @see com.abubusoft.kripton.processor.sqlite.SqlModifyBuilder.ModifyCodeGenerator#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 updateMode, SQLiteModelMethod method, TypeName returnType) {
		SQLiteDaoDefinition daoDefinition = method.getParent();
		SQLiteEntity entity = daoDefinition.getEntity();

		// separate params used for update bean and params used in
		// whereCondition
		// analyze whereCondition
		String whereCondition = extractWhereConditions(updateMode, method);
		
		// this method is invoked to check if every parameter is binded to an method param
		SqlUtility.extractParametersFromString(method.jql.value, method, entity);

		Pair>> where = SqlUtility.extractParametersFromString(whereCondition, method, entity);

		// defines which parameter is used like update field and which is used
		// in where condition.
		List> methodParams = method.getParameters();
		List> updateableParams = new ArrayList>();
		List> whereParams = new ArrayList>();

		String name;

		for (Pair param : methodParams) {
			name = method.findParameterAliasByName(param.value0);

			if (method.isThisDynamicWhereConditionsName(name)) {
				// skip for dynamic where
				continue;
			}

			if (method.isThisDynamicWhereArgsName(name)) {
				// skip for dynamic where
				continue;
			}

			if (where.value1.contains(new Pair<>(name, param.value1))) {
				whereParams.add(param);
			} else {
				updateableParams.add(param);
			}
		}

		// clear contentValues
		if (method.jql.hasDynamicParts() || method.jql.containsSelectOperation) {
			methodBuilder.addStatement("$T _contentValues=contentValuesForUpdate()", KriptonContentValues.class);			
		} else {
			String psName=method.buildPreparedStatementName();
			// generate SQL for insert
			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);			
		}

		
		if (method.jql.containsSelectOperation) {
			generateJavaDoc(method, methodBuilder, updateMode);

			GenericSQLHelper.generateGenericExecSQL(methodBuilder, method);						
		} else {
			// generate javadoc
			generateJavaDoc(method, methodBuilder, updateMode, whereCondition, where, methodParams);
			
			if (updateMode) {
				AssertKripton.assertTrueOrInvalidMethodSignException(updateableParams.size() > 0, method, "no column was selected for update");
				
				// order item for content values
				updateableParams=SqlBuilderHelper.orderContentValues(method, updateableParams);
				
				for (Pair item : updateableParams) {
					String resolvedParamName = method.findParameterAliasByName(item.value0);
					SQLProperty property = entity.get(resolvedParamName);
					if (property == null)
						throw (new PropertyNotFoundException(method, resolvedParamName, item.value1));

					// check same type
					TypeUtility.checkTypeCompatibility(method, item, property);
//					boolean nullable=TypeUtility.isNullable(method, item, property) && !property.hasTypeAdapter();
//
//					if (nullable) {
//						methodBuilder.beginControlFlow("if ($L!=null)", item.value0);
//					}

					// here it needed raw parameter typeName
					if (method.isLogEnabled()) {
						methodBuilder.addCode("_contentValues.put($S, ", property.columnName);
					} else {
						methodBuilder.addCode("_contentValues.put(");
					}

					SQLTransformer.javaMethodParam2ContentValues(methodBuilder, method, item.value0, TypeUtility.typeName(property.getElement()), property);

					methodBuilder.addCode(");\n");

//					if (nullable) {
//						methodBuilder.nextControlFlow("else");
//						
//						if (method.isLogEnabled()) {
//							methodBuilder.addStatement("_contentValues.putNull($S)", property.columnName);
//						} else {
//							methodBuilder.addStatement("_contentValues.putNull()");
//						}
//												
//						methodBuilder.endControlFlow();
//					}
				}

				methodBuilder.addCode("\n");

			} else {
				if (updateableParams.size() > 0) {
					String separator = "";
					StringBuilder buffer = new StringBuilder();
					for (Pair item : updateableParams) {
						String resolvedParamName = method.findParameterAliasByName(item.value0);
						buffer.append(separator + resolvedParamName);
						separator = ", ";
					}
					// in DELETE can not be updated fields
					if (updateableParams.size() > 1) {
						throw (new InvalidMethodSignException(method, " parameters " + buffer.toString() + " are not used in where conditions"));
					} else {
						throw (new InvalidMethodSignException(method, " parameter " + buffer.toString() + " is not used in where conditions"));
					}
				}
			}
			
			// build where condition
			generateWhereCondition(methodBuilder, method, where);
			methodBuilder.addCode("\n");

			ModifyBeanHelper.generateModifyQueryCommonPart(method, classBuilder, methodBuilder);
			
			// support for livedata
			if (daoDefinition.hasLiveData()) {
				methodBuilder.addComment("support for livedata");
				methodBuilder.addStatement(BindDaoBuilder.METHOD_NAME_REGISTRY_EVENT+"(result)");
			}

			// return management
			// if true, field must be associate to ben attributes
			if (returnType == TypeName.VOID) {

			} else {
				if (isIn(returnType, Boolean.TYPE, Boolean.class)) {
					methodBuilder.addStatement("return result!=0");
				} else if (isIn(returnType, Long.TYPE, Long.class, Integer.TYPE, Integer.class, Short.TYPE, Short.class)) {
					methodBuilder.addStatement("return result");
				} else {
					// more than one listener found
					throw (new InvalidMethodSignException(method, "invalid return type"));
				}
			}

		}

	}

	/**
	 * Generate java doc.
	 *
	 * @param method the method
	 * @param methodBuilder the method builder
	 * @param updateMode the update mode
	 */
	private void generateJavaDoc(final SQLiteModelMethod method, Builder methodBuilder, boolean updateMode) {
		List> methodParams = method.getParameters();
		
		final List updatedProperties = new ArrayList<>();
		final List> methodParamsUsedAsParameter = new ArrayList<>();

		// new
		String sqlModify = JQLChecker.getInstance().replace(method, method.jql, new JQLReplacerListenerImpl(method) {

			@Override
			public String onColumnNameToUpdate(String columnName) {
				SQLProperty tempProperty = currentEntity.get(columnName);
				AssertKripton.assertTrueOrUnknownPropertyInJQLException(tempProperty != null, method, columnName);

				updatedProperties.add(tempProperty);

				return tempProperty.columnName;
			}

			@Override
			public String onColumnName(String columnName) {
				SQLProperty tempProperty = currentEntity.get(columnName);
				AssertKripton.assertTrueOrUnknownPropertyInJQLException(tempProperty != null, method, columnName);

				return tempProperty.columnName;
			}

			@Override
			public String onBindParameter(String bindParameterName) {
				String resolvedParamName = method.findParameterNameByAlias(bindParameterName);
				AssertKripton.assertTrueOrUnknownParamInJQLException(resolvedParamName != null, method, bindParameterName);

				methodParamsUsedAsParameter.add(new Pair<>(resolvedParamName, method.findParameterType(resolvedParamName)));

				return "${" + bindParameterName + "}";
			}

		});

		if (updateMode) {
			methodBuilder.addJavadoc("

SQL update

\n"); methodBuilder.addJavadoc("
$L
\n", sqlModify); methodBuilder.addJavadoc("\n"); // list of updated fields methodBuilder.addJavadoc("

Updated columns:

\n"); methodBuilder.addJavadoc("
    \n"); for (SQLProperty property : updatedProperties) { methodBuilder.addJavadoc("\t
  • $L
  • \n", property.columnName); } methodBuilder.addJavadoc("
"); methodBuilder.addJavadoc("\n\n"); } else { methodBuilder.addJavadoc("

SQL delete

\n"); methodBuilder.addJavadoc("
$L
\n", sqlModify); methodBuilder.addJavadoc("\n\n"); } // list of where parameter methodBuilder.addJavadoc("

Parameters:

\n"); methodBuilder.addJavadoc("
\n"); for (Pair property : methodParamsUsedAsParameter) { String rawName = method.findParameterNameByAlias(property.value0); methodBuilder.addJavadoc("\t
$L
", "${" + property.value0 + "}"); methodBuilder.addJavadoc("
is mapped to method's parameter $L
\n", rawName); } methodBuilder.addJavadoc("
"); methodBuilder.addJavadoc("\n\n"); if (method.hasDynamicWhereConditions()) { methodBuilder.addJavadoc("
\n"); methodBuilder.addJavadoc("
$L
is part of where conditions resolved at runtime. In above SQL it is displayed as #{$L}
", method.dynamicWhereParameterName, JQLDynamicStatementType.DYNAMIC_WHERE); methodBuilder.addJavadoc("\n
"); methodBuilder.addJavadoc("\n\n"); } // dynamic conditions if (method.hasDynamicWhereConditions()) { methodBuilder.addJavadoc("

Method's parameters and associated dynamic parts:

\n"); methodBuilder.addJavadoc("
\n"); if (method.hasDynamicWhereConditions()) { methodBuilder.addJavadoc("
$L
is part of where conditions resolved at runtime. In above SQL it is displayed as #{$L}
", method.dynamicWhereParameterName, JQLDynamicStatementType.DYNAMIC_WHERE); } methodBuilder.addJavadoc("
"); methodBuilder.addJavadoc("\n\n"); } // method parameters if (methodParams.size() > 0) { for (Pair param : methodParams) { String resolvedName = method.findParameterAliasByName(param.value0); methodBuilder.addJavadoc("@param $L", param.value0); if (method.isThisDynamicWhereConditionsName(param.value0)) { methodBuilder.addJavadoc("\n\tis used as dynamic where conditions\n"); } else { methodBuilder.addJavadoc("\n\tis used as for parameter $L\n", resolvedName); } } } // if true, field must be associate to ben attributes TypeName returnType = method.getReturnClass(); // define return value if (returnType == TypeName.VOID) { } else { methodBuilder.addJavadoc("\n"); if (isIn(returnType, Boolean.TYPE, Boolean.class)) { if (updateMode) { methodBuilder.addJavadoc("@return true if record is updated, false otherwise"); } else { methodBuilder.addJavadoc("@return true if record is deleted, false otherwise"); } methodBuilder.addCode("return result!=0;\n"); } else if (isIn(returnType, Long.TYPE, Long.class, Integer.TYPE, Integer.class, Short.TYPE, Short.class)) { if (updateMode) { methodBuilder.addJavadoc("@return number of updated records"); } else { methodBuilder.addJavadoc("@return number of deleted records"); } // methodBuilder.addCode("return result;\n"); } else { // more than one listener found throw (new InvalidMethodSignException(method, "invalid return type")); } methodBuilder.addJavadoc("\n"); } } /** * Extract where conditions. * * @param updateMode the update mode * @param method the method * @return the string */ static String extractWhereConditions(boolean updateMode, SQLiteModelMethod method) { final One whereCondition = new One(""); final One found = new One(null); JQLChecker.getInstance().replaceVariableStatements(method, method.jql.value, new JQLReplaceVariableStatementListenerImpl() { @Override public String onWhere(String statement) { if (found.value0 == null) { whereCondition.value0 = statement; found.value0 = true; } return null; } }); return StringUtils.ifNotEmptyAppend(whereCondition.value0, " "); } /** * Generate java doc. * * @param method the method * @param methodBuilder the method builder * @param updateMode the update mode * @param whereCondition the where condition * @param where the where * @param methodParams the method params */ private void generateJavaDoc(final SQLiteModelMethod method, MethodSpec.Builder methodBuilder, boolean updateMode, String whereCondition, Pair>> where, List> methodParams) { final List updatedProperties = new ArrayList<>(); final One onWhereStatement = new One(false); String sqlModify = JQLChecker.getInstance().replace(method, method.jql, new JQLReplacerListenerImpl(method) { @Override public void onWhereStatementBegin(Where_stmtContext ctx) { onWhereStatement.value0 = true; } @Override public void onWhereStatementEnd(Where_stmtContext ctx) { onWhereStatement.value0 = false; } @Override public String onColumnNameToUpdate(String columnName) { SQLProperty tempProperty = currentEntity.get(columnName); AssertKripton.assertTrueOrUnknownPropertyInJQLException(tempProperty != null, method, columnName); updatedProperties.add(tempProperty); return tempProperty.columnName; } @Override public String onColumnName(String columnName) { SQLProperty tempProperty = currentEntity.get(columnName); AssertKripton.assertTrueOrUnknownPropertyInJQLException(tempProperty != null, method, columnName); return tempProperty.columnName; } @Override public String onBindParameter(String bindParameterName) { String resolvedParamName = method.findParameterNameByAlias(bindParameterName); AssertKripton.assertTrueOrUnknownParamInJQLException(resolvedParamName != null, method, bindParameterName); if (onWhereStatement.value0) { return "${" + bindParameterName + "}"; } else { return ":" + bindParameterName; } } }); if (updateMode) { methodBuilder.addJavadoc("

SQL update

\n"); methodBuilder.addJavadoc("
$L
\n", sqlModify); methodBuilder.addJavadoc("\n"); // list of updated fields methodBuilder.addJavadoc("

Updated columns:

\n"); methodBuilder.addJavadoc("
    \n"); for (SQLProperty property : updatedProperties) { methodBuilder.addJavadoc("\t
  • $L
  • \n", property.columnName); // methodBuilder.addJavadoc("
    is binded to query's parameter // $L and method's parameter // $L
    \n", "${" + resolvedName + "}", // property.value0); } methodBuilder.addJavadoc("
"); methodBuilder.addJavadoc("\n\n"); } else { methodBuilder.addJavadoc("

SQL delete

\n"); methodBuilder.addJavadoc("
$L
\n", sqlModify); methodBuilder.addJavadoc("\n\n"); } // list of where parameter methodBuilder.addJavadoc("

Where parameters:

\n"); methodBuilder.addJavadoc("
\n"); for (Pair property : where.value1) { String rawName = method.findParameterNameByAlias(property.value0); methodBuilder.addJavadoc("\t
$L
", "${" + property.value0 + "}"); methodBuilder.addJavadoc("
is mapped to method's parameter $L
\n", rawName); } methodBuilder.addJavadoc("
"); methodBuilder.addJavadoc("\n\n"); if (method.hasDynamicWhereConditions()) { methodBuilder.addJavadoc("
\n"); methodBuilder.addJavadoc("
$L
is part of where conditions resolved at runtime. In above SQL it is displayed as #{$L}
", method.dynamicWhereParameterName, JQLDynamicStatementType.DYNAMIC_WHERE); methodBuilder.addJavadoc("\n
"); methodBuilder.addJavadoc("\n\n"); } // dynamic conditions if (method.hasDynamicWhereConditions()) { methodBuilder.addJavadoc("

Method's parameters and associated dynamic parts:

\n"); methodBuilder.addJavadoc("
\n"); if (method.hasDynamicWhereConditions()) { methodBuilder.addJavadoc("
$L
is part of where conditions resolved at runtime. In above SQL it is displayed as #{$L}
", method.dynamicWhereParameterName, JQLDynamicStatementType.DYNAMIC_WHERE); } methodBuilder.addJavadoc("
"); methodBuilder.addJavadoc("\n\n"); } // method parameters if (methodParams.size() > 0) { for (Pair param : methodParams) { String resolvedName = method.findParameterAliasByName(param.value0); methodBuilder.addJavadoc("@param $L", param.value0); if (method.isThisDynamicWhereConditionsName(param.value0)) { methodBuilder.addJavadoc("\n\tis used as dynamic where conditions\n"); } else if (where.value1.contains(new Pair<>(resolvedName, param.value1))) { methodBuilder.addJavadoc("\n\tis used as where parameter $L\n", "${" + resolvedName + "}"); } else { methodBuilder.addJavadoc("\n\tis used as updated field $L\n", resolvedName); } } } // if true, field must be associate to ben attributes TypeName returnType = method.getReturnClass(); // define return value if (returnType == TypeName.VOID) { } else { methodBuilder.addJavadoc("\n"); if (isIn(returnType, Boolean.TYPE, Boolean.class)) { if (updateMode) { methodBuilder.addJavadoc("@return true if record is updated, false otherwise"); } else { methodBuilder.addJavadoc("@return true if record is deleted, false otherwise"); } // methodBuilder.addCode("return result!=0;\n"); } else if (isIn(returnType, Long.TYPE, Long.class, Integer.TYPE, Integer.class, Short.TYPE, Short.class)) { if (updateMode) { methodBuilder.addJavadoc("@return number of updated records"); } else { methodBuilder.addJavadoc("@return number of deleted records"); } // methodBuilder.addCode("return result;\n"); } else { // more than one listener found throw (new InvalidMethodSignException(method, "invalid return type")); } methodBuilder.addJavadoc("\n"); } } /** * Generate where condition. * * @param methodBuilder the method builder * @param method the method * @param where the where */ public static void generateWhereCondition(MethodSpec.Builder methodBuilder, SQLiteModelMethod method, Pair>> where) { boolean nullable; //methodBuilder.addStatement("$T _sqlWhereParams=getWhereParamsArray()", ArrayList.class); for (Pair item : where.value1) { String resolvedParamName = method.findParameterNameByAlias(item.value0); //methodBuilder.addCode("_sqlWhereParams.add("); methodBuilder.addCode("_contentValues.addWhereArgs("); nullable = isNullable(item.value1); if (nullable && !method.hasAdapterForParam(item.value0)) { // transform null in "" methodBuilder.addCode("($L==null?\"\":", resolvedParamName); } // check for string conversion TypeUtility.beginStringConversion(methodBuilder, item.value1); SQLTransformer.javaMethodParam2WhereConditions(methodBuilder, method, resolvedParamName, item.value1); // check for string conversion TypeUtility.endStringConversion(methodBuilder, item.value1); if (nullable && !method.hasAdapterForParam(item.value0)) { methodBuilder.addCode(")"); } methodBuilder.addCode(");\n"); } } /** * Checks if is in. * * @param value the value * @param classes the classes * @return true, if is in */ static boolean isIn(TypeName value, Class... classes) { for (Class item : classes) { if (value.toString().equals(TypeName.get(item).toString())) { return true; } } return false; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy