Skip to content

Commit

Permalink
Fixed hazelcast#135.
Browse files Browse the repository at this point in the history
Fixed indexing of date fields.
  • Loading branch information
mdogan committed Apr 26, 2012
1 parent 4b57e3e commit c35c08c
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 53 deletions.
96 changes: 96 additions & 0 deletions hazelcast/src/main/java/com/hazelcast/query/DateHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2008-2012, Hazel Bilisim Ltd. All Rights Reserved.
*
* 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 com.hazelcast.query;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
* @mdogan 4/26/12
*/
final class DateHelper {

static final String timestampFormat = "yyyy-MM-dd hh:mm:ss.SSS";
static final String dateFormat = "EEE MMM dd HH:mm:ss zzz yyyy";
static final String sqlDateFormat = "yyyy-mm-dd";

static Date parseDate(final String value) {
try {
return getUtilDateFormat().parse(value);
} catch (ParseException e) {
return throwRuntimeParseException(value, e);
}
}

static Timestamp parseTimeStamp(final String value) {
try {
return new Timestamp(getTimestampFormat().parse(value).getTime());
} catch (ParseException e) {
return throwRuntimeParseException(value, e);
}
}

static java.sql.Date parseSqlDate(final String value) {
try {
return new java.sql.Date(getSqlDateFormat().parse(value).getTime());
} catch (ParseException e) {
return throwRuntimeParseException(value, e);
}
}

static Date tryParse(final String value) {
try {
return getUtilDateFormat().parse(value);
} catch (Exception ignored) {
}

try {
return getTimestampFormat().parse(value);
} catch (Exception ignored) {
}

try {
return getSqlDateFormat().parse(value);
} catch (Exception ignored) {
}

return throwRuntimeParseException(value, null);
}

private static <T> T throwRuntimeParseException(String value, Exception e) {
throw new RuntimeException("Unable to parse date from value: '" + value
+ "' ! Valid formats are: '" + dateFormat + "', '" + timestampFormat
+ "' and '" + sqlDateFormat + "'.", e);
}

private static DateFormat getTimestampFormat() {
return new SimpleDateFormat(timestampFormat);
}

private static DateFormat getSqlDateFormat() {
return new SimpleDateFormat(sqlDateFormat);
}

private static DateFormat getUtilDateFormat() {
return new SimpleDateFormat(dateFormat);
}

private DateHelper() {}
}
16 changes: 12 additions & 4 deletions hazelcast/src/main/java/com/hazelcast/query/Index.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.hazelcast.core.MapEntry;
import com.hazelcast.impl.Record;

import java.util.Date;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
Expand All @@ -42,8 +43,9 @@ public class Index {
private static final int TYPE_DOUBLE = 105;
private static final int TYPE_FLOAT = 106;
private static final int TYPE_BYTE = 107;
private static final int TYPE_CLASS = 108;
private static final int TYPE_UNKNOWN = 109;
private static final int TYPE_CHAR = 108;
private static final int TYPE_DATE = 109;
private static final int TYPE_UNKNOWN = Byte.MAX_VALUE;

Index(Expression expression, boolean ordered, int attributeIndex) {
this.expression = expression;
Expand Down Expand Up @@ -171,7 +173,9 @@ public static byte getIndexType(Class klass) {
} else if (klass == byte.class || klass == Byte.class) {
return TYPE_BYTE;
} else if (klass == char.class || klass == Character.class) {
return TYPE_CLASS;
return TYPE_CHAR;
} else if (Date.class.isAssignableFrom(klass)) { // util.Date, sql.Timestamp, sql.Date
return TYPE_DATE;
} else {
return TYPE_UNKNOWN;
}
Expand All @@ -189,6 +193,8 @@ private static long getLongValueByType(Object value) {
return (Boolean.TRUE.equals(value)) ? 1 : -1;
} else if (value instanceof String) {
return getLongValueForString((String) value);
} else if (value instanceof Date) {
return ((Date) value).getTime();
} else {
return value.hashCode();
}
Expand All @@ -212,8 +218,10 @@ long getLongValue(Object value) {
value = Float.valueOf(str);
} else if (returnType == TYPE_BYTE) {
value = Byte.valueOf(str);
} else if (returnType == TYPE_CLASS) {
} else if (returnType == TYPE_CHAR) {
value = str.hashCode();
} else if (returnType == TYPE_DATE) {
value = DateHelper.tryParse(str);
}
}
}
Expand Down
37 changes: 3 additions & 34 deletions hazelcast/src/main/java/com/hazelcast/query/Predicates.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,12 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class Predicates {

private static final String timestampFormat = "yyyy-MM-dd hh:mm:ss.SSS";
private static final String dateFormat = "EEE MMM dd HH:mm:ss zzz yyyy";
private static final String sqlDateFormat = "yyyy-mm-dd";

public static class GreaterLessPredicate extends EqualPredicate {
boolean equal = false;
boolean less = false;
Expand Down Expand Up @@ -577,31 +570,19 @@ public static Object getRealObject(Object type, Object value) {
if (value instanceof Date) { // one of java.util.Date or java.sql.Date
result = value;
} else {
try {
result = new Timestamp(getTimestampFormat().parse(valueString).getTime());
} catch (ParseException e) {
Util.throwUncheckedException(e);
}
result = DateHelper.parseTimeStamp(valueString);
}
} else if (type instanceof java.sql.Date) {
if (value instanceof Date) { // one of java.util.Date or java.sql.Timestamp
result = value;
} else {
try {
result = getSqlDateFormat().parse(valueString);
} catch (ParseException e) {
Util.throwUncheckedException(e);
}
result = DateHelper.parseSqlDate(valueString);
}
} else if (type instanceof Date) {
if (value instanceof Date) { // one of java.sql.Date or java.sql.Timestamp
result = value;
} else {
try {
result = getUtilDateFormat().parse(valueString);
} catch (ParseException e) {
Util.throwUncheckedException(e);
}
result = DateHelper.parseDate(valueString);
}
} else if (type.getClass().isEnum()) {
try {
Expand Down Expand Up @@ -1076,16 +1057,4 @@ public String toString() {
return input;
}
}

private static DateFormat getTimestampFormat() {
return new SimpleDateFormat(timestampFormat);
}

private static DateFormat getSqlDateFormat() {
return new SimpleDateFormat(sqlDateFormat);
}

private static DateFormat getUtilDateFormat() {
return new SimpleDateFormat(dateFormat);
}
}
66 changes: 51 additions & 15 deletions hazelcast/src/test/java/com/hazelcast/query/QueryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,6 @@ public void testPredicateWithEntryKeyObject() {
assertEquals(1, map.values(predicate).size());
predicate = new PredicateBuilder().getEntryObject().key().in("2", "3");
assertEquals(2, map.keySet(predicate).size());
Hazelcast.shutdownAll();
}

/**
Expand All @@ -817,20 +816,7 @@ public void testPredicateWithEntryKeyObject() {
@Test
public void testPredicateStringAttribute() {
IMap map = Hazelcast.getMap("testPredicateStringWithString");
map.put(1, new Value("abc"));
map.put(2, new Value("xyz"));
map.put(3, new Value("aaa"));
map.put(4, new Value("zzz"));
map.put(5, new Value("klm"));
map.put(6, new Value("prs"));
map.put(7, new Value("prs"));
map.put(8, new Value("def"));
map.put(9, new Value("qwx"));

assertEquals(8, map.values(new SqlPredicate("name > 'aac'")).size());
assertEquals(9, map.values(new SqlPredicate("name between 'aaa' and 'zzz'")).size());
assertEquals(7, map.values(new SqlPredicate("name < 't'")).size());
assertEquals(6, map.values(new SqlPredicate("name >= 'gh'")).size());
testPredicateStringAttribute(map);
}

/**
Expand All @@ -840,6 +826,10 @@ public void testPredicateStringAttribute() {
public void testPredicateStringAttributesWithIndex() {
IMap map = Hazelcast.getMap("testPredicateStringWithStringIndex");
map.addIndex("name", false);
testPredicateStringAttribute(map);
}

private void testPredicateStringAttribute(IMap map) {
map.put(1, new Value("abc"));
map.put(2, new Value("xyz"));
map.put(3, new Value("aaa"));
Expand All @@ -855,6 +845,52 @@ public void testPredicateStringAttributesWithIndex() {
assertEquals(7, map.values(new SqlPredicate("name < 't'")).size());
assertEquals(6, map.values(new SqlPredicate("name >= 'gh'")).size());

assertEquals(8, map.values(new PredicateBuilder().getEntryObject().get("name").greaterThan("aac")).size());
assertEquals(9, map.values(new PredicateBuilder().getEntryObject().get("name").between("aaa", "zzz")).size());
assertEquals(7, map.values(new PredicateBuilder().getEntryObject().get("name").lessThan("t")).size());
assertEquals(6, map.values(new PredicateBuilder().getEntryObject().get("name").greaterEqual("gh")).size());
}

@Test
public void testPredicateDateAttribute() {
IMap map = Hazelcast.getMap("testPredicateDateAttribute");
testPredicateDateAttribute(map);
}

@Test
public void testPredicateDateAttributeWithIndex() {
IMap map = Hazelcast.getMap("testPredicateDateAttribute");
map.addIndex("this", true);
testPredicateDateAttribute(map);
}

private void testPredicateDateAttribute(IMap map) {
Calendar cal = Calendar.getInstance();
cal.set(2012, 5, 5);
map.put(1, cal.getTime());
cal.set(2011, 10, 10);
map.put(2, cal.getTime());
cal.set(2011, 1, 1);
map.put(3, cal.getTime());
cal.set(2010, 8, 5);
map.put(4, cal.getTime());
cal.set(2000, 5, 5);
map.put(5, cal.getTime());

cal.set(2011, 0, 1);
assertEquals(3, map.values(new PredicateBuilder().getEntryObject().get("this").greaterThan(cal.getTime())).size());
assertEquals(3, map.values(new SqlPredicate("this > 'Sat Jan 01 11:43:05 EET 2011'")).size());

assertEquals(2, map.values(new PredicateBuilder().getEntryObject().get("this").lessThan(cal.getTime())).size());
assertEquals(2, map.values(new SqlPredicate("this < 'Sat Jan 01 11:43:05 EET 2011'")).size());

cal.set(2003, 10, 10);
Date d1 = cal.getTime();
cal.set(2012, 1, 10);
Date d2 = cal.getTime();
assertEquals(3, map.values(new PredicateBuilder().getEntryObject().get("this").between(d1, d2)).size());
assertEquals(3, map.values(new SqlPredicate("this between 'Mon Nov 10 11:43:05 EET 2003'" +
" and 'Fri Feb 10 11:43:05 EET 2012'")).size());
}

public void doFunctionalSQLQueryTest(IMap imap) {
Expand Down

0 comments on commit c35c08c

Please sign in to comment.