/*
* Copyright 2012 SFB 632.
*
* 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 annis.sqlgen;
import annis.model.QueryAnnotation;
import annis.model.QueryNode;
import annis.model.QueryNode.TextMatching;
import static annis.sqlgen.TableAccessStrategy.NODE_ANNOTATION_TABLE;
import static annis.sqlgen.TableAccessStrategy.NODE_TABLE;
import com.google.common.base.Objects;
import com.google.common.escape.Escaper;
import com.google.common.escape.Escapers;
import java.util.Collection;
import java.util.Set;
/**
* Bundles behavior
* how to add annotation constraints to the generated SQL.
* @author Thomas Krause <krauseto@hu-berlin.de>
*/
public class AnnotationConditionProvider
{
public static final Escaper likeEscaper = Escapers.builder()
.addEscape('\'', "''")
.addEscape('%', "\\%")
.addEscape('_', "\\_")
.addEscape('\\', "\\\\")
.build();
public static final Escaper regexEscaper = Escapers.builder()
.addEscape('\'', "''")
.build();
/**
* Adds annotation conditions for a single node.
* @param conditions Condition list where the conditions should be added to
* @param index Index for a specific annotation
* @param annotation The annotation to add
* @param table Table to operate on
* @param tas {@link TableAccessStrategy} for the given node.
*/
public void addAnnotationConditions(Collection<String> conditions,
int index, QueryAnnotation annotation, String table,
TableAccessStrategy tas)
{
TextMatching tm = annotation.getTextMatching();
String column = annotation.getNamespace() == null
? "annotext" : "qannotext";
Escaper escaper = tm != null && tm.isRegex() ? regexEscaper : likeEscaper;
String val;
if (tm == null)
{
val = "%";
}
else
{
val = escaper.escape(annotation.getValue());
}
String prefix;
if (annotation.getNamespace() == null)
{
prefix = escaper.escape(annotation.getName()) + ":";
}
else
{
prefix = escaper.escape(annotation.getNamespace())
+ ":" + escaper.escape(annotation.getName()) + ":";
}
if (tm == null || tm == TextMatching.EXACT_EQUAL)
{
conditions.add(tas.aliasedColumn(table, column, index)
+ " LIKE '" + prefix + val + "'");
}
else if (tm == TextMatching.EXACT_NOT_EQUAL)
{
conditions.add(tas.aliasedColumn(table, column, index)
+ " LIKE '" + prefix + "%'");
conditions.add(tas.aliasedColumn(table, column, index)
+ " NOT LIKE '" + prefix + val + "'");
}
else if (tm == TextMatching.REGEXP_EQUAL)
{
conditions.add(tas.aliasedColumn(table, column, index)
+ " ~ '^(" + prefix + "(" + val + "))$'");
}
else if (tm == TextMatching.REGEXP_NOT_EQUAL)
{
conditions.add(tas.aliasedColumn(table, column, index)
+ " LIKE '" + prefix + "%'");
conditions.add(tas.aliasedColumn(table, column, index)
+ " !~ '^(" + prefix + "(" + val + "))$'");
}
}
public void addEqualValueConditions(Collection<String> conditions, QueryNode node,
QueryNode target, TableAccessStrategy tasNode, TableAccessStrategy tasTarget,
boolean equal)
{
String op = equal ? "=" : "<>";
if (node.isToken() && target.isToken())
{
// join on span
conditions.add(tasNode.aliasedColumn(NODE_TABLE, "span")
+ " " + op + " " + tasTarget.aliasedColumn(NODE_TABLE, "span"));
}
else if (haveSameNodeAnnotationDefinitions(
node.getNodeAnnotations(), target.getNodeAnnotations()))
{
// join on node_anno_ref
conditions.add(tasNode.aliasedColumn(NODE_ANNOTATION_TABLE, "qannotext")
+ " " + op + " " + tasTarget.aliasedColumn(NODE_ANNOTATION_TABLE, "qannotext"));
}
else
{
// most complex query, join on the actual value
String left;
if (node.isToken())
{
left = tasNode.aliasedColumn(NODE_TABLE, "span");
}
else
{
left = "(splitanno("
+ tasNode.aliasedColumn(NODE_ANNOTATION_TABLE, "qannotext")
+"))[3]";
}
String right;
if (target.isToken())
{
right = tasTarget.aliasedColumn(NODE_TABLE, "span");
}
else
{
right = "(splitanno("
+ tasTarget.aliasedColumn(NODE_ANNOTATION_TABLE, "qannotext")
+"))[3]";
}
conditions.add(left + " " + op + " " + right);
}
}
private boolean haveSameNodeAnnotationDefinitions(
Set<QueryAnnotation> sourceAnnos,
Set<QueryAnnotation> targetAnnos)
{
if (sourceAnnos != null && targetAnnos != null
&& sourceAnnos.size() == 1 && targetAnnos.size() == 1)
{
QueryAnnotation anno1 = sourceAnnos.iterator().next();
QueryAnnotation anno2 = targetAnnos.iterator().next();
if (Objects.equal(anno1.getNamespace(), anno2.getNamespace())
&& Objects.equal(anno1.getName(), anno2.getName()))
{
return true;
}
}
return false;
}
public String getNodeAnnoNamespaceSQL(TableAccessStrategy tas)
{
return tas.aliasedColumn("annotation_category", "namespace");
}
public String getNodeAnnoNameSQL(TableAccessStrategy tas)
{
return tas.aliasedColumn("annotation_category", "name");
}
}