Parcourir la source

add support for like_any operator

tags/2.0.1
Jonathan Cobb il y a 4 ans
Parent
révision
a00cf9c832
5 fichiers modifiés avec 101 ajouts et 48 suppressions
  1. +20
    -18
      wizard-common/src/main/java/org/cobbzilla/wizard/model/SqlDefaultSearchField.java
  2. +47
    -29
      wizard-common/src/main/java/org/cobbzilla/wizard/model/entityconfig/EntityFieldType.java
  3. +2
    -0
      wizard-common/src/main/java/org/cobbzilla/wizard/model/entityconfig/annotations/ECSearchable.java
  4. +20
    -1
      wizard-common/src/main/java/org/cobbzilla/wizard/model/search/SearchBoundComparison.java
  5. +12
    -0
      wizard-common/src/main/java/org/cobbzilla/wizard/model/search/SearchBoundSqlFunction.java

+ 20
- 18
wizard-common/src/main/java/org/cobbzilla/wizard/model/SqlDefaultSearchField.java Voir le fichier

@@ -6,9 +6,7 @@ import org.cobbzilla.wizard.model.entityconfig.EntityFieldType;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECField;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECForeignKey;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECSearchable;
import org.cobbzilla.wizard.model.search.SearchBound;
import org.cobbzilla.wizard.model.search.SearchBoundBuilder;
import org.cobbzilla.wizard.model.search.SearchField;
import org.cobbzilla.wizard.model.search.*;

import java.lang.reflect.Field;
import java.util.ArrayList;
@@ -51,22 +49,26 @@ public class SqlDefaultSearchField implements SearchField {
@Override public SearchBound[] getBounds() {
final List<SearchBound> bounds = new ArrayList<>();
EntityFieldType fieldType = search.type();
if (fieldType == none_set) {
if (!empty(search.bounds())) {
try {
final SearchBoundBuilder builder = instantiate(search.bounds());
return builder.build(bound, value, params, locale);
} catch (Exception e) {
return die("getBounds(" + bound + "): error invoking custom SearchBoundBuilder: " + search.bounds() + ": " + e);
}
if (!empty(search.bounds())) {
try {
final SearchBoundBuilder builder = instantiate(search.bounds());
return builder.build(bound, value, params, locale);
} catch (Exception e) {
return die("getBounds(" + bound + "): error invoking custom SearchBoundBuilder: " + search.bounds() + ": " + e);
}

} else if (!empty(search.operators())) {
for (SearchBoundComparison op : search.operators()) {
bounds.add(op.bind(name(), SearchFieldType.string));
}

} else if (fieldType == none_set) {
final ECField ecField = f.getAnnotation(ECField.class);
final ECForeignKey ecForeignKey = f.getAnnotation(ECForeignKey.class);
if (ecForeignKey != null) {
fieldType = reference;
} else {
final ECField ecField = f.getAnnotation(ECField.class);
final ECForeignKey ecForeignKey = f.getAnnotation(ECForeignKey.class);
if (ecForeignKey != null) {
fieldType = reference;
} else {
fieldType = ecField != null && ecField.type() != none_set ? ecField.type() : guessFieldType(f);
}
fieldType = ecField != null && ecField.type() != none_set ? ecField.type() : guessFieldType(f);
}
}
if (fieldType != null) {


+ 47
- 29
wizard-common/src/main/java/org/cobbzilla/wizard/model/entityconfig/EntityFieldType.java Voir le fichier

@@ -2,8 +2,10 @@ package org.cobbzilla.wizard.model.entityconfig;

import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.wizard.model.entityconfig.validation.*;
import org.cobbzilla.wizard.model.search.SearchFieldType;
import org.cobbzilla.wizard.validation.ValidationResult;
import org.cobbzilla.wizard.validation.Validator;

@@ -40,94 +42,94 @@ public enum EntityFieldType {
email (new EntityConfigFieldValidator_email()),

/** an integer-valued number */
integer (new EntityConfigFieldValidator_integer()),
integer (SearchFieldType.integer, new EntityConfigFieldValidator_integer()),

/** a real number */
decimal (new EntityConfigFieldValidator_decimal()),
decimal (SearchFieldType.decimal, new EntityConfigFieldValidator_decimal()),

/** an integer-valued monetary amount */
money_integer (null),
money_integer (SearchFieldType.integer),

/** a real-valued monetary amount */
money_decimal (null),
money_decimal (SearchFieldType.decimal),

/** a boolean value */
flag (new EntityConfigFieldValidator_boolean()),
flag (SearchFieldType.flag, new EntityConfigFieldValidator_boolean()),

/** a date value */
date (null),
date (SearchFieldType.integer),

/** a date value in the past (before current date) */
date_past (null),
date_past (SearchFieldType.integer),

/** a date value in the future (or current date) */
date_future (null),
date_future (SearchFieldType.integer),

/** a field for age */
age (null),
age (SearchFieldType.integer),

/** a 4-digit year field */
year (null),
year (SearchFieldType.integer),

/** a 4-digit year field that starts with the current year and goes into the past */
year_past (null),
year_past (SearchFieldType.integer),

/** a 4-digit year field that starts with the current year and goes into the future */
year_future (null),
year_future (SearchFieldType.integer),

/** a 4-digit year and 2-digit month field (YYYY-MM) */
year_and_month (null),
year_and_month (SearchFieldType.integer),

/** a 4-digit year and 2-digit month field (YYYY-MM) field that starts with the current year and goes into the past */
year_and_month_past (null),
year_and_month_past (SearchFieldType.integer),

/** a 4-digit year and 2-digit month field (YYYY-MM) field that starts with the current year and goes into the future */
year_and_month_future (null),
year_and_month_future (SearchFieldType.integer),

/** a date or date/time value, represented as milliseconds since 1/1/1970 */
epoch_time (new EntityConfigFieldValidator_integer()),
epoch_time (SearchFieldType.integer, new EntityConfigFieldValidator_integer()),

/** a date or date/time value, represented as milliseconds since 1/1/1970 */
expiration_time (new EntityConfigFieldValidator_integer()),
expiration_time (SearchFieldType.integer, new EntityConfigFieldValidator_integer()),

/** millisecond value for a time duration */
time_duration (new EntityConfigFieldValidator_integer()),
time_duration (SearchFieldType.integer, new EntityConfigFieldValidator_integer()),

/** a time-zone (for example America/New York) */
time_zone (null),
time_zone (),

/** a locale (for example en_US) */
locale (null),
locale (),

/** a 3-letter currency code (for example USD) */
currency (null),
currency (),

/** an IPv4 address */
ip4 (null),
ip4 (),

/** an IPv6 address */
ip6 (null),
ip6 (),

/** a hostname */
hostname (null),
hostname (),

/** a fully-qualified domain name */
fqdn (null),
fqdn (),

/** a 2-letter US state abbreviation */
us_state (null),
us_state (),

/** a US ZIP code */
us_zip (null),
us_zip (),

/** HTTP URL */
http_url (new EntityConfigFieldValidator_httpUrl()),

/** a reference to another EntityConfig instance */
reference (null),
reference (),

/** a base64-encoded PNG image */
base64_png (null),
base64_png (),

/** an embedded sub-object */
embedded (new EntityConfigFieldValidator_embedded()),
@@ -135,8 +137,24 @@ public enum EntityFieldType {
/** a US phone number */
us_phone (new EntityConfigFieldValidator_USPhone());

@Getter private SearchFieldType searchFieldType;
private EntityConfigFieldValidator fieldValidator;

EntityFieldType (EntityConfigFieldValidator validator) {
this.searchFieldType = SearchFieldType.string;
this.fieldValidator = validator;
}

EntityFieldType (SearchFieldType searchFieldType) {
this.searchFieldType = searchFieldType;
this.fieldValidator = null;
}

EntityFieldType () {
this.searchFieldType = SearchFieldType.string;
this.fieldValidator = null;
}

/** Jackson-hook to create a new instance based on a string, case-insensitively */
@JsonCreator public static EntityFieldType fromString(String val) { return valueOf(val.toLowerCase()); }



+ 2
- 0
wizard-common/src/main/java/org/cobbzilla/wizard/model/entityconfig/annotations/ECSearchable.java Voir le fichier

@@ -1,6 +1,7 @@
package org.cobbzilla.wizard.model.entityconfig.annotations;

import org.cobbzilla.wizard.model.entityconfig.EntityFieldType;
import org.cobbzilla.wizard.model.search.SearchBoundComparison;
import org.cobbzilla.wizard.model.search.SqlViewFieldSetter;
import org.jasypt.hibernate4.encryptor.HibernatePBEStringEncryptor;

@@ -20,6 +21,7 @@ public @interface ECSearchable {
String sortField() default "";
EntityFieldType type() default EntityFieldType.none_set;
String bounds() default "";
SearchBoundComparison[] operators() default {};
String entity() default "";
ECForeignKeySearchDepth fkDepth() default ECForeignKeySearchDepth.inherit;



+ 20
- 1
wizard-common/src/main/java/org/cobbzilla/wizard/model/search/SearchBoundComparison.java Voir le fichier

@@ -6,6 +6,8 @@ import org.cobbzilla.util.collection.ComparisonOperator;
import org.cobbzilla.util.time.TimePeriodType;
import org.cobbzilla.util.time.TimeUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@@ -27,7 +29,20 @@ public enum SearchBoundComparison {
lt (sqlCompare(ComparisonOperator.lt.sql, SearchBoundComparison::parseCompareArgument)),
le (sqlCompare(ComparisonOperator.le.sql, SearchBoundComparison::parseCompareArgument)),

like (sqlCompare( "ilike", SearchBoundComparison::parseLikeArgument)),
like (sqlCompare(Constants.ILIKE, SearchBoundComparison::parseLikeArgument)),

like_any((bound, params, value, locale) -> {
final String[] values = value.split(Constants.ILIKE_SEP);
final List<Object> valueList = Arrays.asList(values);
final String[] operators = new String[values.length];
Arrays.fill(operators, Constants.ILIKE);
final SearchBoundValueFunction[] valueFuncs = new SearchBoundValueFunction[values.length];
Arrays.fill(valueFuncs, (SearchBoundValueFunction) (bound1, value1, locale1) -> value1);
for (int i=0; i<values.length; i++) {
params.add(valueFuncs[i].paramValue(bound, values[i], locale));
}
return sqlOrCompare(operators, valueFuncs, values).generateSqlAndAddParams(bound, new ArrayList<>(valueList), null, locale);
}),

is_null (sqlNullCompare(true)),
not_null(sqlNullCompare(false)),
@@ -126,4 +141,8 @@ public enum SearchBoundComparison {

public static String customPrefix(String op) { return SearchBoundComparison.custom.name() + OP_SEP + op + OP_SEP; }

public static class Constants {
public static final String ILIKE = "ilike";
public static final String ILIKE_SEP = ",";
}
}

+ 12
- 0
wizard-common/src/main/java/org/cobbzilla/wizard/model/search/SearchBoundSqlFunction.java Voir le fichier

@@ -38,6 +38,18 @@ public interface SearchBoundSqlFunction {
};
}

static SearchBoundSqlFunction sqlOrCompare(String[] operators, SearchBoundValueFunction[] valueFunctions, String[] values) {
return (bound, params, value, locale) -> {
final StringBuilder b = new StringBuilder();
for (int i = 0; i < operators.length; i++) {
if (b.length() > 0) b.append(") OR (");
b.append(bound.getName()).append(" ").append(operators[i]).append(" ?");
params.add(valueFunctions[i].paramValue(bound, values[i], locale));
}
return b.insert(0, "(").append(")").toString();
};
}

static SearchBoundSqlFunction sqlNullCompare(boolean isNull) {
return (bound, params, value, locale) -> bound.getName() + " IS " + (!isNull ? "NOT " : "") + " NULL";
}


Chargement…
Annuler
Enregistrer