/*******************************************************************************
* Copyright (c) 2012, 2015 Spring IDE Developers
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.data.jdt.core;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.util.Assert;
/**
* A candidate for a Spring Data query method. Allows to lookup {@link QueryMethodPart}s at a given position inside the
* method name.
*
* @author Oliver Gierke
*/
class QueryMethodCandidate {
private final Pattern pattern = Pattern.compile("^(find|read|get)(\\p{Upper}.*?)??By");
private final Pattern CONCATENATOR_PATERN = Pattern.compile(".*(And|Or)(?=\\p{Upper}.*?)?");
private final String name;
private final int prefixLength;
private final Class<?> entityClass;
/**
* Creates a new {@link QueryMethodCandidate} with the given name based on the given entity type.
*
* @param name must not be {@literal null}. or empty.
* @param entityType must not be {@literal null}.
*/
public QueryMethodCandidate(String name, Class<?> entityType) {
Assert.hasText(name, "Method name must not be null or empty!");
Assert.notNull(entityType, "Entity type must not be null!");
Matcher matcher = pattern.matcher(name);
boolean prefixFound = matcher.find();
this.prefixLength = prefixFound ? matcher.end() : 0;
this.name = prefixFound ? name.substring(matcher.end()) : name;
this.entityClass = entityType;
}
/**
* Returns the {@link QueryMethodPart} for the given cursor position within the method name. Will inspect the name for
* concatenators ({@literal And}, {@literal Or}) and inspect the part between the concatenator and the cursor
* position.
*
* @param i the current position within the method name.
* @return the {@link QueryMethodPart} in case a reasonable proposal can be given or {@literal null} in case this is
* not the case.
*/
public QueryMethodPart getPartAtPosition(int i) {
// Don't provide propsals for request in prefix or after method
if (i < prefixLength || i > prefixLength + name.length()) {
return null;
}
Matcher matcher = CONCATENATOR_PATERN.matcher(name);
int startIndex = matcher.find() ? matcher.end() : 0;
int endIndex = i - prefixLength > name.length() ? name.length() : i - prefixLength;
if (startIndex < 0 || endIndex < 0 || startIndex > endIndex) {
return null;
}
String subName = startIndex >= name.length() ? "" : name.substring(startIndex, endIndex);
return new QueryMethodPart(subName, entityClass);
}
}