You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2014/11/27 08:12:02 UTC
[19/39] cayenne git commit: CAY-1971 Variants of Property.like(..) :
contains(..), startsWith(..), endsWith(..)
CAY-1971 Variants of Property.like(..) : contains(..), startsWith(..), endsWith(..)
* implementing escaping
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/7aeba71b
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/7aeba71b
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/7aeba71b
Branch: refs/heads/CAY-1946_1
Commit: 7aeba71b31bc513fda6b3678d81a4b9393aa772c
Parents: 9587d04
Author: aadamchik <aa...@apache.org>
Authored: Sat Nov 22 14:46:31 2014 +0300
Committer: aadamchik <aa...@apache.org>
Committed: Sat Nov 22 17:31:22 2014 +0300
----------------------------------------------------------------------
.../cayenne/exp/LikeExpressionHelper.java | 88 ++++-
.../org/apache/cayenne/exp/PropertyTest.java | 383 ++++++++++---------
2 files changed, 285 insertions(+), 186 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/7aeba71b/cayenne-server/src/main/java/org/apache/cayenne/exp/LikeExpressionHelper.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/LikeExpressionHelper.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/LikeExpressionHelper.java
index 7725dc9..31ec1f2 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/LikeExpressionHelper.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/LikeExpressionHelper.java
@@ -18,6 +18,7 @@
****************************************************************/
package org.apache.cayenne.exp;
+import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.exp.parser.PatternMatchNode;
/**
@@ -25,11 +26,22 @@ import org.apache.cayenne.exp.parser.PatternMatchNode;
*/
class LikeExpressionHelper {
- // presumably only "?" can't be an escape char
- private static final char[] ESCAPE_ALPHABET = new char[] { '\\', '|', '/', ' ' };
+ private static final char WILDCARD_SEQUENCE = '%';
+ private static final char WILDCARD_ONE = '_';
+ private static final boolean[] ESCAPE_ALPHABET;
+ private static final int ESCAPE_ALPHABET_START = '!';
- private static final String WILDCARD_SEQUENCE = "%";
- private static final String WILDCARD_ONE = "_";
+ static {
+
+ ESCAPE_ALPHABET = new boolean[Byte.MAX_VALUE];
+ // exclude certain chars, such as unprintable ones, and ?
+ for (int i = ESCAPE_ALPHABET_START; i < Byte.MAX_VALUE; i++) {
+
+ if (i != '?' && i != '\"' && i != '\'' && i != WILDCARD_SEQUENCE && i != WILDCARD_ONE) {
+ ESCAPE_ALPHABET[i] = true;
+ }
+ }
+ }
static void toContains(PatternMatchNode exp) {
escape(exp);
@@ -47,10 +59,76 @@ class LikeExpressionHelper {
}
static void escape(PatternMatchNode exp) {
+ Object pattern = exp.getOperand(1);
+ if (pattern instanceof String) {
+ // find _ or % and then attempt to escape...
+
+ String pString = pattern.toString();
+
+ int len = pString.length();
+ for (int i = 0; i < len; i++) {
+
+ char c = pString.charAt(i);
+ if (c == WILDCARD_SEQUENCE || c == WILDCARD_ONE) {
+ exp.setOperand(1, escapeFrom(exp, pString, i, len));
+ break;
+ }
+ }
+ }
+ }
+
+ private static String escapeFrom(PatternMatchNode exp, String pattern, int firstWildcard, int len) {
+
+ boolean[] mutableEscapeAlphabet = new boolean[Byte.MAX_VALUE];
+ System.arraycopy(ESCAPE_ALPHABET, ESCAPE_ALPHABET_START, mutableEscapeAlphabet, ESCAPE_ALPHABET_START,
+ Byte.MAX_VALUE - ESCAPE_ALPHABET_START);
+
+ // can't use chars already in the pattern, so exclude the ones already
+ // taken
+ for (int i = 0; i < len; i++) {
+ char c = pattern.charAt(i);
+ if (c < Byte.MAX_VALUE) {
+ mutableEscapeAlphabet[c] = false;
+ }
+ }
+
+ // find the first available char
+ char escapeChar = 0;
+ for (int i = ESCAPE_ALPHABET_START; i < Byte.MAX_VALUE; i++) {
+ if (mutableEscapeAlphabet[i]) {
+ escapeChar = (char) i;
+ break;
+ }
+ }
+
+ if (escapeChar == 0) {
+ // if we start seeing this this error in the wild, I guess we'll
+ // need to extend escape char set beyond ASCII
+ throw new CayenneRuntimeException("Could not properly escape pattern: " + pattern);
+ }
+
+ exp.setEscapeChar(escapeChar);
+
+ // build escaped pattern
+ StringBuilder buffer = new StringBuilder(len + 1);
+ buffer.append(pattern.substring(0, firstWildcard));
+ buffer.append(escapeChar).append(pattern.charAt(firstWildcard));
+
+ for (int i = firstWildcard + 1; i < len; i++) {
+
+ char c = pattern.charAt(i);
+ if (c == WILDCARD_SEQUENCE || c == WILDCARD_ONE) {
+ buffer.append(escapeChar);
+ break;
+ }
+
+ buffer.append(c);
+ }
+ return buffer.toString();
}
- static void wrap(PatternMatchNode exp, boolean start, boolean end) {
+ private static void wrap(PatternMatchNode exp, boolean start, boolean end) {
Object pattern = exp.getOperand(1);
if (pattern instanceof String) {
http://git-wip-us.apache.org/repos/asf/cayenne/blob/7aeba71b/cayenne-server/src/test/java/org/apache/cayenne/exp/PropertyTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/PropertyTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/PropertyTest.java
index 70fd3ce..538fc0b 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/PropertyTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/PropertyTest.java
@@ -18,6 +18,7 @@
****************************************************************/
package org.apache.cayenne.exp;
+import org.apache.cayenne.exp.parser.PatternMatchNode;
import org.apache.cayenne.reflect.TstJavaBean;
import org.apache.cayenne.reflect.UnresolvablePathException;
import org.apache.cayenne.util.Util;
@@ -32,185 +33,205 @@ import static org.junit.Assert.fail;
public class PropertyTest {
- @Test
- public void testIn() {
- Property<String> p = new Property<String>("x.y");
-
- Expression e1 = p.in("a");
- assertEquals("x.y in (\"a\")", e1.toString());
-
- Expression e2 = p.in("a", "b");
- assertEquals("x.y in (\"a\", \"b\")", e2.toString());
-
- Expression e3 = p.in(Arrays.asList("a", "b"));
- assertEquals("x.y in (\"a\", \"b\")", e3.toString());
- }
-
- @Test
- public void testGetFrom() {
- TstJavaBean bean = new TstJavaBean();
- bean.setIntField(7);
- final Property<Integer> INT_FIELD = new Property<Integer>("intField");
- assertEquals(Integer.valueOf(7), INT_FIELD.getFrom(bean));
- }
-
- @Test
- public void testGetFromNestedProperty() {
- TstJavaBean bean = new TstJavaBean();
- TstJavaBean nestedBean = new TstJavaBean();
- nestedBean.setIntField(7);
- bean.setObjectField(nestedBean);
- final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
- assertEquals(Integer.valueOf(7), OBJECT_FIELD_INT_FIELD.getFrom(bean));
- }
-
- @Test
- public void testGetFromNestedNull() {
- TstJavaBean bean = new TstJavaBean();
- bean.setObjectField(null);
- final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
- try {
- OBJECT_FIELD_INT_FIELD.getFrom(bean);
- fail();
- } catch (Exception e) {
- Throwable rootException = Util.unwindException(e);
- if (!(rootException instanceof UnresolvablePathException)) {
- fail();
- }
- }
- }
-
- @Test
- public void testGetFromAll() {
- TstJavaBean bean = new TstJavaBean();
- bean.setIntField(7);
-
- TstJavaBean bean2 = new TstJavaBean();
- bean2.setIntField(8);
-
- List<TstJavaBean> beans = Arrays.asList(bean, bean2);
-
- final Property<Integer> INT_FIELD = new Property<Integer>("intField");
- assertEquals(Arrays.asList(7, 8), INT_FIELD.getFromAll(beans));
- }
-
- @Test
- public void testSetIn() {
- TstJavaBean bean = new TstJavaBean();
- final Property<Integer> INT_FIELD = new Property<Integer>("intField");
- INT_FIELD.setIn(bean, 7);
- assertEquals(7, bean.getIntField());
- }
-
- @Test
- public void testSetInNestedProperty() {
- TstJavaBean bean = new TstJavaBean();
- bean.setObjectField(new TstJavaBean());
-
- final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
-
- OBJECT_FIELD_INT_FIELD.setIn(bean, 7);
- assertEquals(7, ((TstJavaBean)bean.getObjectField()).getIntField());
- }
-
- @Test
- public void testSetInNestedNull() {
- TstJavaBean bean = new TstJavaBean();
- bean.setObjectField(null);
- final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
- try {
- OBJECT_FIELD_INT_FIELD.setIn(bean, 7);
- fail();
- } catch (Exception e) {
- Throwable rootException = Util.unwindException(e);
- if (!(rootException instanceof UnresolvablePathException)) {
- fail();
- }
- }
- }
-
- @Test
- public void testSetInAll() {
- TstJavaBean bean = new TstJavaBean();
- TstJavaBean bean2 = new TstJavaBean();
- List<TstJavaBean> beans = Arrays.asList(bean, bean2);
-
- final Property<Integer> INT_FIELD = new Property<Integer>("intField");
- INT_FIELD.setInAll(beans, 7);
- assertEquals(7, bean.getIntField());
- assertEquals(7, bean2.getIntField());
- }
-
- @Test
- public void testEquals() {
- final Property<Integer> INT_FIELD = new Property<Integer>("intField");
- final Property<Integer> INT_FIELD2 = new Property<Integer>("intField");
-
- assertTrue(INT_FIELD != INT_FIELD2);
- assertTrue(INT_FIELD.equals(INT_FIELD2));
- }
-
- @Test
- public void testHashCode() {
- final Property<Integer> INT_FIELD = new Property<Integer>("intField");
- final Property<Integer> INT_FIELD2 = new Property<Integer>("intField");
- final Property<Long> LONG_FIELD = new Property<Long>("longField");
-
- assertTrue(INT_FIELD.hashCode() == INT_FIELD2.hashCode());
- assertTrue(INT_FIELD.hashCode() != LONG_FIELD.hashCode());
- }
-
- @Test
- public void testOuter() {
- Property<String> inner = new Property<String>("xyz");
- assertEquals("xyz+", inner.outer().getName());
-
- Property<String> inner1 = new Property<String>("xyz.xxx");
- assertEquals("xyz.xxx+", inner1.outer().getName());
-
- Property<String> outer = new Property<String>("xyz+");
- assertEquals("xyz+", outer.outer().getName());
- }
-
- @Test
- public void testLike() {
- Property<String> p = new Property<String>("prop");
- Expression e = p.like("abc");
- assertEquals("prop like \"abc\"", e.toString());
- }
-
- @Test
- public void testLikeIgnoreCase() {
- Property<String> p = new Property<String>("prop");
- Expression e = p.likeInsensitive("abc");
- assertEquals("prop likeIgnoreCase \"abc\"", e.toString());
- }
-
- @Test
- public void testLike_NoEscape() {
- Property<String> p = new Property<String>("prop");
- Expression e = p.like("ab%c");
- assertEquals("prop like \"ab%c\"", e.toString());
- }
-
- @Test
- public void testContains() {
- Property<String> p = new Property<String>("prop");
- Expression e = p.contains("abc");
- assertEquals("prop like \"%abc%\"", e.toString());
- }
-
- @Test
- public void testStartsWith() {
- Property<String> p = new Property<String>("prop");
- Expression e = p.startsWith("abc");
- assertEquals("prop like \"abc%\"", e.toString());
- }
-
- @Test
- public void testEndsWith() {
- Property<String> p = new Property<String>("prop");
- Expression e = p.endsWith("abc");
- assertEquals("prop like \"%abc\"", e.toString());
- }
+ @Test
+ public void testIn() {
+ Property<String> p = new Property<String>("x.y");
+
+ Expression e1 = p.in("a");
+ assertEquals("x.y in (\"a\")", e1.toString());
+
+ Expression e2 = p.in("a", "b");
+ assertEquals("x.y in (\"a\", \"b\")", e2.toString());
+
+ Expression e3 = p.in(Arrays.asList("a", "b"));
+ assertEquals("x.y in (\"a\", \"b\")", e3.toString());
+ }
+
+ @Test
+ public void testGetFrom() {
+ TstJavaBean bean = new TstJavaBean();
+ bean.setIntField(7);
+ final Property<Integer> INT_FIELD = new Property<Integer>("intField");
+ assertEquals(Integer.valueOf(7), INT_FIELD.getFrom(bean));
+ }
+
+ @Test
+ public void testGetFromNestedProperty() {
+ TstJavaBean bean = new TstJavaBean();
+ TstJavaBean nestedBean = new TstJavaBean();
+ nestedBean.setIntField(7);
+ bean.setObjectField(nestedBean);
+ final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
+ assertEquals(Integer.valueOf(7), OBJECT_FIELD_INT_FIELD.getFrom(bean));
+ }
+
+ @Test
+ public void testGetFromNestedNull() {
+ TstJavaBean bean = new TstJavaBean();
+ bean.setObjectField(null);
+ final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
+ try {
+ OBJECT_FIELD_INT_FIELD.getFrom(bean);
+ fail();
+ } catch (Exception e) {
+ Throwable rootException = Util.unwindException(e);
+ if (!(rootException instanceof UnresolvablePathException)) {
+ fail();
+ }
+ }
+ }
+
+ @Test
+ public void testGetFromAll() {
+ TstJavaBean bean = new TstJavaBean();
+ bean.setIntField(7);
+
+ TstJavaBean bean2 = new TstJavaBean();
+ bean2.setIntField(8);
+
+ List<TstJavaBean> beans = Arrays.asList(bean, bean2);
+
+ final Property<Integer> INT_FIELD = new Property<Integer>("intField");
+ assertEquals(Arrays.asList(7, 8), INT_FIELD.getFromAll(beans));
+ }
+
+ @Test
+ public void testSetIn() {
+ TstJavaBean bean = new TstJavaBean();
+ final Property<Integer> INT_FIELD = new Property<Integer>("intField");
+ INT_FIELD.setIn(bean, 7);
+ assertEquals(7, bean.getIntField());
+ }
+
+ @Test
+ public void testSetInNestedProperty() {
+ TstJavaBean bean = new TstJavaBean();
+ bean.setObjectField(new TstJavaBean());
+
+ final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
+
+ OBJECT_FIELD_INT_FIELD.setIn(bean, 7);
+ assertEquals(7, ((TstJavaBean) bean.getObjectField()).getIntField());
+ }
+
+ @Test
+ public void testSetInNestedNull() {
+ TstJavaBean bean = new TstJavaBean();
+ bean.setObjectField(null);
+ final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
+ try {
+ OBJECT_FIELD_INT_FIELD.setIn(bean, 7);
+ fail();
+ } catch (Exception e) {
+ Throwable rootException = Util.unwindException(e);
+ if (!(rootException instanceof UnresolvablePathException)) {
+ fail();
+ }
+ }
+ }
+
+ @Test
+ public void testSetInAll() {
+ TstJavaBean bean = new TstJavaBean();
+ TstJavaBean bean2 = new TstJavaBean();
+ List<TstJavaBean> beans = Arrays.asList(bean, bean2);
+
+ final Property<Integer> INT_FIELD = new Property<Integer>("intField");
+ INT_FIELD.setInAll(beans, 7);
+ assertEquals(7, bean.getIntField());
+ assertEquals(7, bean2.getIntField());
+ }
+
+ @Test
+ public void testEquals() {
+ final Property<Integer> INT_FIELD = new Property<Integer>("intField");
+ final Property<Integer> INT_FIELD2 = new Property<Integer>("intField");
+
+ assertTrue(INT_FIELD != INT_FIELD2);
+ assertTrue(INT_FIELD.equals(INT_FIELD2));
+ }
+
+ @Test
+ public void testHashCode() {
+ final Property<Integer> INT_FIELD = new Property<Integer>("intField");
+ final Property<Integer> INT_FIELD2 = new Property<Integer>("intField");
+ final Property<Long> LONG_FIELD = new Property<Long>("longField");
+
+ assertTrue(INT_FIELD.hashCode() == INT_FIELD2.hashCode());
+ assertTrue(INT_FIELD.hashCode() != LONG_FIELD.hashCode());
+ }
+
+ @Test
+ public void testOuter() {
+ Property<String> inner = new Property<String>("xyz");
+ assertEquals("xyz+", inner.outer().getName());
+
+ Property<String> inner1 = new Property<String>("xyz.xxx");
+ assertEquals("xyz.xxx+", inner1.outer().getName());
+
+ Property<String> outer = new Property<String>("xyz+");
+ assertEquals("xyz+", outer.outer().getName());
+ }
+
+ @Test
+ public void testLike() {
+ Property<String> p = new Property<String>("prop");
+ Expression e = p.like("abc");
+ assertEquals("prop like \"abc\"", e.toString());
+ }
+
+ @Test
+ public void testLikeIgnoreCase() {
+ Property<String> p = new Property<String>("prop");
+ Expression e = p.likeInsensitive("abc");
+ assertEquals("prop likeIgnoreCase \"abc\"", e.toString());
+ }
+
+ @Test
+ public void testLike_NoEscape() {
+ Property<String> p = new Property<String>("prop");
+ Expression e = p.like("ab%c");
+ assertEquals("prop like \"ab%c\"", e.toString());
+ assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
+ }
+
+ @Test
+ public void testContains() {
+ Property<String> p = new Property<String>("prop");
+ Expression e = p.contains("abc");
+ assertEquals("prop like \"%abc%\"", e.toString());
+ assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
+ }
+
+ @Test
+ public void testStartsWith() {
+ Property<String> p = new Property<String>("prop");
+ Expression e = p.startsWith("abc");
+ assertEquals("prop like \"abc%\"", e.toString());
+ assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
+ }
+
+ @Test
+ public void testEndsWith() {
+ Property<String> p = new Property<String>("prop");
+ Expression e = p.endsWith("abc");
+ assertEquals("prop like \"%abc\"", e.toString());
+ assertEquals(0, ((PatternMatchNode) e).getEscapeChar());
+ }
+
+ @Test
+ public void testContains_Escape1() {
+ Property<String> p = new Property<String>("prop");
+ Expression e = p.contains("a%bc");
+ assertEquals("prop like \"%a!%bc%\"", e.toString());
+ assertEquals('!', ((PatternMatchNode) e).getEscapeChar());
+ }
+
+ @Test
+ public void testContains_Escape2() {
+ Property<String> p = new Property<String>("prop");
+ Expression e = p.contains("a_!bc");
+ assertEquals("prop like \"%a#_!bc%\"", e.toString());
+ assertEquals('#', ((PatternMatchNode) e).getEscapeChar());
+ }
}