Full text index support from Zell, also a fix for deletion.

This commit is contained in:
Michael Bayne
2007-07-31 21:36:02 +00:00
parent ddf40eb5c4
commit 8eb5d24be9
13 changed files with 393 additions and 110 deletions
@@ -44,7 +44,7 @@ import com.samskivert.jdbc.depot.expression.SQLExpression;
import com.samskivert.jdbc.depot.expression.ValueExp;
import com.samskivert.jdbc.depot.operator.Conditionals.In;
import com.samskivert.jdbc.depot.operator.Conditionals.IsNull;
import com.samskivert.jdbc.depot.operator.Conditionals.Match;
import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch;
import com.samskivert.jdbc.depot.operator.Logic.Not;
import com.samskivert.jdbc.depot.operator.SQLOperator.BinaryOperator;
import com.samskivert.jdbc.depot.operator.SQLOperator.MultiOperator;
@@ -128,7 +128,7 @@ public class BindVisitor implements ExpressionVisitor
}
}
public void visit (Match match) throws Exception
public void visit (FullTextMatch match) throws Exception
{
// we never get here
}
@@ -46,7 +46,7 @@ import com.samskivert.jdbc.depot.expression.SQLExpression;
import com.samskivert.jdbc.depot.expression.ValueExp;
import com.samskivert.jdbc.depot.operator.Conditionals.In;
import com.samskivert.jdbc.depot.operator.Conditionals.IsNull;
import com.samskivert.jdbc.depot.operator.Conditionals.Match;
import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch;
import com.samskivert.jdbc.depot.operator.Logic.Not;
import com.samskivert.jdbc.depot.operator.SQLOperator.BinaryOperator;
import com.samskivert.jdbc.depot.operator.SQLOperator.MultiOperator;
@@ -197,11 +197,8 @@ public abstract class BuildVisitor implements ExpressionVisitor
_builder.append(")");
}
public void visit (Match match)
throws Exception
{
throw new IllegalArgumentException("Match() is MySQL-specific.");
}
public abstract void visit (FullTextMatch match)
throws Exception;
public void visit (ColumnExp columnExp)
throws Exception
@@ -456,6 +453,8 @@ public abstract class BuildVisitor implements ExpressionVisitor
{
_builder.append("delete from ");
appendTableName(deleteClause.getPersistentClass());
_builder.append(" as ");
appendTableAbbreviation(deleteClause.getPersistentClass());
_builder.append(" ");
deleteClause.getWhereClause().accept(this);
}
@@ -40,6 +40,7 @@ import java.util.logging.Level;
import com.samskivert.io.PersistenceException;
import com.samskivert.jdbc.depot.annotation.Computed;
import com.samskivert.jdbc.depot.annotation.Entity;
import com.samskivert.jdbc.depot.annotation.FullTextIndex;
import com.samskivert.jdbc.depot.annotation.GeneratedValue;
import com.samskivert.jdbc.depot.annotation.Id;
import com.samskivert.jdbc.depot.annotation.Index;
@@ -95,6 +96,14 @@ public class DepotMarshaller<T extends PersistentRecord>
context.tableGenerators.put(generator.name(), generator);
}
// if there are FTS indexes in the Table, map those out here for future use
Table table = pclass.getAnnotation(Table.class);
if (table != null) {
for (FullTextIndex fts : table.fullTextIndexes()) {
_fullTextIndexes.put(fts.name(), fts);
}
}
// introspect on the class and create marshallers for persistent fields
ArrayList<String> fields = new ArrayList<String>();
for (Field field : _pclass.getFields()) {
@@ -195,6 +204,14 @@ public class DepotMarshaller<T extends PersistentRecord>
_allFields = fields.toArray(new String[fields.size()]);
}
/**
* Returns the persistent class this is object is a marshaller for.
*/
public Class<T> getPersistentClass ()
{
return _pclass;
}
/**
* Returns the name of the table in which persistent instances of our class are stored. By
* default this is the classname of the persistent object without the package.
@@ -220,6 +237,14 @@ public class DepotMarshaller<T extends PersistentRecord>
return _columnFields;
}
/**
* Return the {@link FullTextIndex} registered under the given name, or null if none.
*/
public FullTextIndex getFullTextIndex (String name)
{
return _fullTextIndexes.get(name);
}
/**
* Returns the {@link FieldMarshaller} for a named field on our persistent class.
*/
@@ -448,17 +473,17 @@ public class DepotMarshaller<T extends PersistentRecord>
* be created. If the schema version specified by the persistent object is newer than the
* database schema, it will be migrated.
*/
protected void init (PersistenceContext ctx)
protected void init (final PersistenceContext ctx)
throws PersistenceException
{
SQLBuilder builder = ctx.getSQLBuilder(DepotTypes.TRIVIAL);
if (_initialized) { // sanity check
throw new IllegalStateException(
"Cannot re-initialize marshaller [type=" + _pclass + "].");
}
_initialized = true;
final SQLBuilder builder = ctx.getSQLBuilder(new DepotTypes(ctx, _pclass));
// perform the context-sensitive initialization of the field marshallers
for (FieldMarshaller fm : _fields.values()) {
fm.init(builder);
@@ -494,7 +519,7 @@ public class DepotMarshaller<T extends PersistentRecord>
UniqueConstraint[] uCons = table.uniqueConstraints();
uniqueConstraintColumns = new String[uCons.length][];
for (int kk = 0; kk < uCons.length; kk ++) {
String[] columns = uCons[kk].columnNames();
String[] columns = uCons[kk].fieldNames();
for (int ii = 0; ii < columns.length; ii ++) {
FieldMarshaller fm = getFieldMarshaller(columns[ii]);
if (fm == null) {
@@ -542,8 +567,13 @@ public class DepotMarshaller<T extends PersistentRecord>
primaryKeyColumns[ii] = _pkColumns.get(ii).getColumnName();
}
}
liaison.createTableIfMissing(conn, getTableName(), columns, fDeclarations,
fUniqueConstraintColumns, primaryKeyColumns);
if (liaison.createTableIfMissing(conn, getTableName(), columns, fDeclarations,
fUniqueConstraintColumns, primaryKeyColumns)) {
for (FullTextIndex fti : _fullTextIndexes.values()) {
builder.addFullTextSearch(conn, DepotMarshaller.this, fti);
}
}
updateVersion(conn, liaison, _schemaVersion);
return 0;
}
@@ -863,6 +893,9 @@ public class DepotMarshaller<T extends PersistentRecord>
/** The fields of our object with directly corresponding table columns. */
protected String[] _columnFields;
/** A mapping of all of the full text index annotations for our persistent record. */
protected Map<String, FullTextIndex> _fullTextIndexes = new HashMap<String, FullTextIndex>();
/** The version of our persistent object schema as specified in the class definition. */
protected int _schemaVersion = -1;
@@ -24,7 +24,6 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -22,11 +22,10 @@ package com.samskivert.jdbc.depot;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -69,41 +68,11 @@ public class DepotTypes
return new DepotTypes(ctx, classSet);
}
public String getTableName (Class<? extends PersistentRecord> cl)
{
return _classMap.get(cl).getTableName();
}
public String getTableAbbreviation (Class<? extends PersistentRecord> cl)
{
int ix = _classList.indexOf(cl);
if (ix < 0) {
throw new IllegalArgumentException("Unknown persistence class: " + cl);
}
return "T" + (ix+1);
}
public String getColumnName (Class<? extends PersistentRecord> cl, String field)
{
return getMarshaller(cl).getFieldMarshaller(field).getColumnName();
}
public DepotMarshaller getMarshaller (Class cl)
{
return _classMap.get(cl);
}
public void addClass (PersistenceContext ctx, Class <? extends PersistentRecord> type)
throws PersistenceException
{
if (_classMap.containsKey(type)) {
return;
}
_classList.add(type);
_classMap.put(type, ctx.getMarshaller(type));
}
protected DepotTypes (PersistenceContext ctx, Set<Class<? extends PersistentRecord>> others)
/**
* Create a new DepotTypes with the given {@link PersistenceContext} and a collection of
* persistent record classes.
*/
public DepotTypes (PersistenceContext ctx, Collection<Class<? extends PersistentRecord>> others)
throws PersistenceException
{
for (Class<? extends PersistentRecord> c : others) {
@@ -111,14 +80,114 @@ public class DepotTypes
}
}
/**
* Create a new DepotTypes with the given {@link PersistenceContext} and the given
* persistent record.
*/
public DepotTypes (PersistenceContext ctx, Class<? extends PersistentRecord> pClass)
throws PersistenceException
{
addClass(ctx, pClass);
}
/**
* Return the full table name of the given persistent class, which must have been previously
* registered with this object.
*/
public String getTableName (Class<? extends PersistentRecord> cl)
{
return _classMap.get(cl).getTableName();
}
/**
* Return the current abbreviation by which we refer to the table associated with the given
* persistent record -- which must have been previously registered with this object. If the
* useTableAbbreviations flag is false, we return the full table name instead.
*/
public String getTableAbbreviation (Class<? extends PersistentRecord> cl)
{
if (_useTableAbbreviations) {
Integer ix = _classIx.get(cl);
if (ix == null) {
throw new IllegalArgumentException("Unknown persistence class: " + cl);
}
return "T" + (ix+1);
}
return getTableName(cl);
}
/**
* Return the associated database column of the given field of the given persistent class,
* or null if there is no associated marshaller, or if the field is unknown on the class, or
* if the field does not directly associate with a column.
*/
public String getColumnName (Class<? extends PersistentRecord> cl, String field)
{
DepotMarshaller dm = getMarshaller(cl);
if (dm != null) {
FieldMarshaller<?> fm = dm.getFieldMarshaller(field);
if (fm != null) {
return fm.getColumnName();
}
}
return null;
}
/**
* Return the {@link DepotMarshaller} associated with the given persistent class, or null
* if the class has not been previously registered with this object.
*/
public DepotMarshaller getMarshaller (Class<? extends PersistentRecord> cl)
{
return _classMap.get(cl);
}
/**
* Register a new persistent class with this object.
*/
public void addClass (PersistenceContext ctx, Class <? extends PersistentRecord> type)
throws PersistenceException
{
if (_classMap.containsKey(type)) {
return;
}
_classMap.put(type, ctx.getMarshaller(type));
_classIx.put(type, _classIx.size());
}
/**
* Return the value of the useTableAbbreviations flag, which governs the behaviour when
* referencing columns during SQL construction. Normally, this flag is on, and tables are
* referenced as e.g. T1.itemId, but there are cases of weak/broken SQL where abbreviations
* may not be brought into play. In these cases we prepend the full table name.
*/
public boolean getUseTableAbbreviations ()
{
return _useTableAbbreviations;
}
/**
* Sets the value of the useTableAbbreviations flag, which governs the behaviour when
* referencing columns during SQL construction. Normally, this flag is on, and tables are
* referenced as e.g. T1.itemId, but there are cases of weak/broken SQL where abbreviations
* may not be brought into play. In these cases we prepend the full table name.
*/
public void setUseTableAbbreviations (boolean doUse)
{
_useTableAbbreviations = doUse;
}
// constructor used to create TRIVIAL
protected DepotTypes ()
{
}
/** A list of referenced classes, used to generate table abbreviations. */
protected List<Class<? extends PersistentRecord>> _classList =
new ArrayList<Class<? extends PersistentRecord>>();
/** Classes mapped to integers, used for table abbreviation indexing. */
protected Map<Class, Integer> _classIx = new HashMap<Class, Integer>();
/** Classes mapped to marshallers, used for table names and field lists. */
protected Map<Class, DepotMarshaller> _classMap = new HashMap<Class, DepotMarshaller>();
/** When false, override the normal table abbreviations and return full table names instead. */
protected boolean _useTableAbbreviations = true;
}
@@ -22,11 +22,14 @@ package com.samskivert.jdbc.depot;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import com.samskivert.jdbc.JDBCUtil;
import com.samskivert.jdbc.depot.FieldMarshaller.BooleanMarshaller;
import com.samskivert.jdbc.depot.FieldMarshaller.ByteArrayMarshaller;
import com.samskivert.jdbc.depot.FieldMarshaller.ByteEnumMarshaller;
@@ -38,44 +41,54 @@ import com.samskivert.jdbc.depot.FieldMarshaller.IntMarshaller;
import com.samskivert.jdbc.depot.FieldMarshaller.LongMarshaller;
import com.samskivert.jdbc.depot.FieldMarshaller.ObjectMarshaller;
import com.samskivert.jdbc.depot.FieldMarshaller.ShortMarshaller;
import com.samskivert.jdbc.depot.annotation.FullTextIndex;
import com.samskivert.jdbc.depot.clause.DeleteClause;
import com.samskivert.jdbc.depot.expression.ColumnExp;
import com.samskivert.jdbc.depot.operator.Conditionals.Match;
import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch;
public class MySQLBuilder
extends SQLBuilder
{
public class MSBuildVisitor extends BuildVisitor
{
protected MSBuildVisitor (DepotTypes types)
{
super(types);
}
@Override
public void visit (Match match)
public void visit (FullTextMatch match)
throws Exception
{
_builder.append("match(");
ColumnExp[] columns = match.getColumns();
for (int ii = 0; ii < columns.length; ii ++) {
Class<? extends PersistentRecord> pClass = match.getPersistentRecord();
FullTextIndex fts = _types.getMarshaller(pClass).getFullTextIndex(match.getName());
String[] fields = fts.fieldNames();
for (int ii = 0; ii < fields.length; ii ++) {
if (ii > 0) {
_builder.append(", ");
}
columns[ii].accept(this);
new ColumnExp(pClass, fields[ii]).accept(this);
}
_builder.append(") against (?");
switch (match.getMode()) {
case BOOLEAN:
_builder.append(" in boolean mode");
break;
case NATURAL_LANGUAGE:
_builder.append(" in natural language mode");
break;
_builder.append(") against (? in boolean mode)");
}
@Override
public void visit (DeleteClause<? extends PersistentRecord> deleteClause)
throws Exception
{
_builder.append("delete from ");
appendTableName(deleteClause.getPersistentClass());
_builder.append(" ");
// MySQL can't do DELETE FROM SomeTable AS T1, so we turn off abbreviations briefly.
boolean savedFlag = _types.getUseTableAbbreviations();
_types.setUseTableAbbreviations(false);
try {
deleteClause.getWhereClause().accept(this);
} finally {
_types.setUseTableAbbreviations(savedFlag);
}
if (match.isQueryExpansion()) {
_builder.append(" with query expansion");
}
_builder.append(")");
}
protected MSBuildVisitor (DepotTypes types)
{
super(types);
}
protected void appendTableName (Class<? extends PersistentRecord> type)
@@ -107,7 +120,7 @@ public class MySQLBuilder
}
@Override
public void visit (Match match)
public void visit (FullTextMatch match)
throws Exception
{
_stmt.setString(_argIdx ++, match.getQuery());
@@ -119,6 +132,34 @@ public class MySQLBuilder
super(types);
}
@Override
public <T extends PersistentRecord> boolean addFullTextSearch (
Connection conn, DepotMarshaller<T> marshaller, FullTextIndex fts)
throws SQLException
{
Class<T> pClass = marshaller.getPersistentClass();
StringBuilder update = new StringBuilder("ALTER TABLE ").
append(marshaller.getTableName()).append(" ADD FULLTEXT INDEX ftsIx_").
append(fts.name()).append(" (");
String[] fields = fts.fieldNames();
for (int ii = 0; ii < fields.length; ii ++) {
if (ii > 0) {
update.append(", ");
}
update.append(_types.getColumnName(pClass, fields[ii]));
}
update.append(")");
PreparedStatement stmt = null;
try {
stmt = conn.prepareStatement(update.toString());
stmt.executeUpdate();
} finally {
JDBCUtil.close(stmt);
}
return true;
}
@Override
protected BuildVisitor getBuildVisitor ()
{
@@ -22,11 +22,17 @@ package com.samskivert.jdbc.depot;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import com.samskivert.jdbc.DatabaseLiaison;
import com.samskivert.jdbc.JDBCUtil;
import com.samskivert.jdbc.LiaisonRegistry;
import com.samskivert.jdbc.depot.FieldMarshaller.BooleanMarshaller;
import com.samskivert.jdbc.depot.FieldMarshaller.ByteArrayMarshaller;
import com.samskivert.jdbc.depot.FieldMarshaller.ByteEnumMarshaller;
@@ -38,12 +44,24 @@ import com.samskivert.jdbc.depot.FieldMarshaller.IntMarshaller;
import com.samskivert.jdbc.depot.FieldMarshaller.LongMarshaller;
import com.samskivert.jdbc.depot.FieldMarshaller.ObjectMarshaller;
import com.samskivert.jdbc.depot.FieldMarshaller.ShortMarshaller;
import com.samskivert.jdbc.depot.annotation.FullTextIndex;
import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch;
import com.samskivert.Log;
public class PostgreSQLBuilder
extends SQLBuilder
{
public class PGBuildVisitor extends BuildVisitor
{
@Override
public void visit (FullTextMatch match)
throws Exception
{
appendField("ftsCol_" + match.getName());
_builder.append(" @@ TO_TSQUERY('default', ?)");
}
protected PGBuildVisitor (DepotTypes types)
{
super(types);
@@ -72,6 +90,13 @@ public class PostgreSQLBuilder
public class PGBindVisitor extends BindVisitor
{
@Override
public void visit (FullTextMatch match)
throws Exception
{
_stmt.setString(_argIdx ++, match.getQuery());
}
protected PGBindVisitor (DepotTypes types, PreparedStatement stmt)
{
super(types, stmt);
@@ -83,6 +108,71 @@ public class PostgreSQLBuilder
super(types);
}
@Override
public <T extends PersistentRecord> boolean addFullTextSearch (
Connection conn, DepotMarshaller<T> marshaller, FullTextIndex fts)
throws SQLException
{
Class<T> pClass = marshaller.getPersistentClass();
DatabaseLiaison liaison = LiaisonRegistry.getLiaison(conn);
String[] fields = fts.fieldNames();
String table = marshaller.getTableName();
String column = "ftsCol_" + fts.name();
String index = "ftsIx_" + fts.name();
String trigger = "ftsTrig_" + fts.name();
// build the UPDATE
StringBuilder initColumn = new StringBuilder("UPDATE ").
append(liaison.tableSQL(table)).append(" SET ").append(liaison.columnSQL(column)).
append(" = TO_TSVECTOR('default', ");
for (int ii = 0; ii < fields.length; ii ++) {
if (ii > 0) {
initColumn.append(" || ' ' || ");
}
initColumn.append("COALESCE(").
append(liaison.columnSQL(_types.getColumnName(pClass, fields[ii]))).
append(", '')");
}
initColumn.append(")");
// build the CREATE TRIGGER
StringBuilder createTrigger = new StringBuilder("CREATE TRIGGER ").
append(liaison.columnSQL(trigger)).append(" BEFORE UPDATE OR INSERT ON ").
append(liaison.tableSQL(table)).append(" FOR EACH ROW EXECUTE PROCEDURE tsearch2(").
append(liaison.columnSQL(column)).append(", ");
for (int ii = 0; ii < fields.length; ii ++) {
if (ii > 0) {
createTrigger.append(", ");
}
createTrigger.append(liaison.columnSQL(_types.getColumnName(pClass, fields[ii])));
}
createTrigger.append(")");
// build the CREATE INDEX
StringBuilder createIndex = new StringBuilder("CREATE INDEX ").
append(liaison.columnSQL(index)).append(" ON " ).append(liaison.tableSQL(table)).
append(" USING GIST(").append(liaison.columnSQL(column)).append(")");
Statement stmt = conn.createStatement();
try {
Log.info(
"Adding full-text search column, index and trigger: " + column + ", " +
index + ", " + trigger);
liaison.addColumn(conn, table, column, "TSVECTOR", true);
stmt.executeUpdate(initColumn.toString());
stmt.executeUpdate(createIndex.toString());
stmt.executeUpdate(createTrigger.toString());
} finally {
JDBCUtil.close(stmt);
}
return true;
}
@Override
protected BuildVisitor getBuildVisitor ()
{
@@ -26,8 +26,10 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.samskivert.jdbc.depot.annotation.Column;
import com.samskivert.jdbc.depot.annotation.FullTextIndex;
import com.samskivert.jdbc.depot.annotation.GeneratedValue;
import com.samskivert.jdbc.depot.clause.QueryClause;
import com.samskivert.jdbc.depot.operator.Conditionals;
/**
* At the heart of Depot's SQL generation, this object constructs two {@link ExpressionVisitor}
@@ -171,6 +173,17 @@ public abstract class SQLBuilder
return builder.toString();
}
/**
* Add full-text search capabilities, as defined by the provided {@link FullTextIndex}, on
* the table associated with the given {@link DepotMarshaller}. This is a highly database
* specific operation and must thus be implemented by each dialect subclass.
*
* {@see Conditionals.FullTextIndex}
*/
public abstract <T extends PersistentRecord> boolean addFullTextSearch (
Connection conn, DepotMarshaller<T> marshaller, FullTextIndex fts)
throws SQLException;
/**
* Overridden by subclasses to create a dialect-specific {@link BuildVisitor}.
*/
@@ -0,0 +1,44 @@
//
// $Id$
//
// samskivert library - useful routines for java programs
// Copyright (C) 2007 Michael Bayne, Pär Winzell
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.jdbc.depot.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to specify that a full text index is to be included in the generated DDL
* for a table.
*/
@Target(value={})
@Retention(value=RetentionPolicy.RUNTIME)
public @interface FullTextIndex
{
/**
* An identifier for this index, unique with the scope of the record.
*/
public String name ();
/**
* An array of the field names that should be indexed.
*/
public String[] fieldNames ();
}
@@ -40,4 +40,9 @@ public @interface Table
* Defaults to no additional constraints.
*/
public UniqueConstraint[] uniqueConstraints () default {};
/**
* Full-text search indexes defined on this entity, if any. Defaults to none.
*/
public FullTextIndex[] fullTextIndexes () default {};
}
@@ -33,7 +33,7 @@ import java.lang.annotation.Target;
public @interface UniqueConstraint
{
/**
* An array of the column names that make up the constraint
* An array of the field names that make up the constraint
*/
public String[] columnNames () default {};
public String[] fieldNames () default {};
}
@@ -40,7 +40,7 @@ import com.samskivert.jdbc.depot.clause.Where;
import com.samskivert.jdbc.depot.operator.Conditionals.In;
import com.samskivert.jdbc.depot.operator.Conditionals.IsNull;
import com.samskivert.jdbc.depot.operator.Conditionals.Match;
import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch;
import com.samskivert.jdbc.depot.operator.Logic.Not;
import com.samskivert.jdbc.depot.operator.SQLOperator.BinaryOperator;
import com.samskivert.jdbc.depot.operator.SQLOperator.MultiOperator;
@@ -70,7 +70,7 @@ public interface ExpressionVisitor
throws Exception;
public void visit (In in)
throws Exception;
public void visit (Match match)
public void visit (FullTextMatch match)
throws Exception;
public void visit (ColumnExp columnExp)
throws Exception;
@@ -247,39 +247,33 @@ public abstract class Conditionals
}
}
/** The MySQL 'match (...) against (...)' operator. */
@Deprecated
public static class Match
/**
* An attempt at a dialect-agnostic full-text search condition, such as MySQL's MATCH() and
* PostgreSQL's @@ TO_TSQUERY(...) abilities.
*/
public static class FullTextMatch
implements SQLOperator
{
public enum Mode { DEFAULT, BOOLEAN, NATURAL_LANGUAGE };
public Match (String query, Mode mode, boolean queryExpansion, ColumnExp... columns)
public FullTextMatch (Class<? extends PersistentRecord> pClass, String name, String query)
{
_pClass = pClass;
_name = name;
_query = query;
_queryExpansion = queryExpansion;
_mode = mode;
_columns = columns;
}
public Class<? extends PersistentRecord> getPersistentRecord ()
{
return _pClass;
}
public String getQuery ()
{
return _query;
}
public Mode getMode ()
public String getName ()
{
return _mode;
}
public boolean isQueryExpansion ()
{
return _queryExpansion;
}
public ColumnExp[] getColumns ()
{
return _columns;
return _name;
}
// from SQLExpression
@@ -291,14 +285,10 @@ public abstract class Conditionals
// from SQLExpression
public void addClasses (Collection<Class<? extends PersistentRecord>> classSet)
{
for (ColumnExp column : _columns) {
column.addClasses(classSet);
}
}
protected Class<? extends PersistentRecord> _pClass;
protected String _name;
protected String _query;
protected Mode _mode;
protected boolean _queryExpansion;
protected ColumnExp[] _columns;
}
}