Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Genesys PGR
Genesys Backend
Commits
6d810d65
Commit
6d810d65
authored
Nov 20, 2014
by
Matija Obreza
Browse files
Added support for inverse (excluding) filters
parent
4ede2380
Changes
8
Hide whitespace changes
Inline
Side-by-side
src/main/java/org/genesys2/server/service/impl/DirectMysqlQuery.java
View file @
6d810d65
...
...
@@ -226,17 +226,25 @@ public class DirectMysqlQuery {
}
else
{
sb
.
append
(
" and "
);
}
// Opening
if
(
appliedFilter
.
isInverse
())
{
sb
.
append
(
" NOT "
);
}
sb
.
append
(
" ( "
);
// A filter value can be (a) explicit value or (b) an operation
int
toHandle
=
filterValues
.
size
();
if
(
appliedFilter
.
getWithNull
())
{
toHandle
++;
}
// (a) explicit values are handled by =? or by IN (?,?,..)
int
handledCount
=
handleExplicitValues
(
sb
,
dbName
,
filterValues
,
params
);
// do we have more?
if
(
handledCount
>
0
&&
filterValues
.
size
()
>
handledCount
)
{
if
(
handledCount
>
0
&&
toHandle
>
handledCount
)
{
sb
.
append
(
" OR "
);
}
...
...
@@ -244,7 +252,7 @@ public class DirectMysqlQuery {
handledCount
+=
handledCountNull
;
// do we have more?
if
(
handledCountNull
>
0
&&
handledCount
>
0
&&
filterValues
.
size
()
>
handledCount
)
{
if
(
handledCountNull
>
0
&&
handledCount
>
0
&&
toHandle
>
handledCount
)
{
sb
.
append
(
" OR "
);
}
...
...
src/main/java/org/genesys2/server/service/impl/ElasticsearchSearchServiceImpl.java
View file @
6d810d65
...
...
@@ -255,7 +255,11 @@ public class ElasticsearchSearchServiceImpl implements ElasticService, Initializ
}
}
filterBuilder
.
add
(
orFilter
);
if
(
appliedFilter
.
isInverse
())
{
filterBuilder
.
add
(
FilterBuilders
.
notFilter
(
orFilter
));
}
else
{
filterBuilder
.
add
(
orFilter
);
}
}
return
filterBuilder
;
...
...
src/main/java/org/genesys2/server/service/impl/FilterHandler.java
View file @
6d810d65
...
...
@@ -194,7 +194,7 @@ public class FilterHandler {
public
void
serialize
(
AppliedFilters
filters
,
JsonGenerator
jgen
,
SerializerProvider
provider
)
throws
IOException
,
JsonProcessingException
{
jgen
.
writeStartObject
();
for
(
AppliedFilter
filter
:
filters
)
{
jgen
.
writeArrayFieldStart
(
filter
.
get
FilterName
());
jgen
.
writeArrayFieldStart
(
filter
.
get
Key
());
for
(
FilterValue
fv
:
filter
.
getValues
())
jgen
.
writeObject
(
fv
);
if
(
filter
.
withNull
)
...
...
@@ -225,7 +225,12 @@ public class FilterHandler {
while
(
jp
.
getCurrentToken
()
==
JsonToken
.
FIELD_NAME
)
{
AppliedFilter
af
=
new
AppliedFilter
();
appliedFilters
.
add
(
af
);
af
.
setFilterName
(
jp
.
getCurrentName
());
String
name
=
jp
.
getCurrentName
();
if
(
name
.
startsWith
(
"-"
))
{
af
.
setInverse
(
true
);
name
=
name
.
substring
(
1
);
}
af
.
setFilterName
(
name
);
jp
.
nextToken
();
if
(
jp
.
getCurrentToken
()
==
JsonToken
.
START_ARRAY
)
{
...
...
@@ -391,6 +396,7 @@ public class FilterHandler {
private
Set
<
FilterValue
>
values
=
new
HashSet
<
FilterValue
>();
private
boolean
withNull
=
false
;
private
String
filterName
;
private
boolean
inverse
=
false
;
public
String
getFilterName
()
{
return
this
.
filterName
;
...
...
@@ -411,6 +417,29 @@ public class FilterHandler {
return
this
;
}
/**
* When inverse, selected values are excluded instead of included
*/
public
boolean
isInverse
()
{
return
inverse
;
}
/**
* When inverse, selected values are excluded instead of included
*/
public
boolean
getInverse
()
{
return
isInverse
();
}
/**
* Set the filter to be inverse (i.e. excluding) selected values
*
* @param inverse
*/
public
void
setInverse
(
boolean
inverse
)
{
this
.
inverse
=
inverse
;
}
public
boolean
getWithNull
()
{
return
this
.
withNull
;
}
...
...
@@ -424,6 +453,7 @@ public class FilterHandler {
final
int
prime
=
31
;
int
result
=
1
;
result
=
prime
*
result
+
((
filterName
==
null
)
?
0
:
filterName
.
hashCode
());
result
=
prime
*
result
+
(
inverse
?
1231
:
1237
);
result
=
prime
*
result
+
((
values
==
null
)
?
0
:
values
.
hashCode
());
result
=
prime
*
result
+
(
withNull
?
1231
:
1237
);
return
result
;
...
...
@@ -443,6 +473,8 @@ public class FilterHandler {
return
false
;
}
else
if
(!
filterName
.
equals
(
other
.
filterName
))
return
false
;
if
(
inverse
!=
other
.
inverse
)
return
false
;
if
(
values
==
null
)
{
if
(
other
.
values
!=
null
)
return
false
;
...
...
@@ -456,6 +488,18 @@ public class FilterHandler {
public
int
size
()
{
return
values
.
size
();
}
/**
* Return the filter key used in JSON
*
* @return "filterName" or "-filterName" for negative filters
*/
public
String
getKey
()
{
if
(
inverse
)
{
return
"-"
+
this
.
filterName
;
}
return
this
.
filterName
;
}
}
@JsonSerialize
(
using
=
LiteralValueFilter
.
Serializer
.
class
)
...
...
src/main/java/org/genesys2/server/servlet/controller/ExplorerController.java
View file @
6d810d65
...
...
@@ -180,6 +180,7 @@ public class ExplorerController extends BaseController {
model
.
addAttribute
(
"crops"
,
cropService
.
list
(
getLocale
()));
model
.
addAttribute
(
"pagedData"
,
accessions
);
model
.
addAttribute
(
"appliedFilters"
,
appliedFilters
);
model
.
addAttribute
(
"currentFilters"
,
currentFilters
);
model
.
addAttribute
(
"availableFilters"
,
availableFilters
);
...
...
@@ -221,7 +222,7 @@ public class ExplorerController extends BaseController {
model
.
addAttribute
(
"crop"
,
crop
);
// JSP works with JsonObject
// JSP works with JsonObject
// TODO Handle -filter.key!!
final
Map
<?,
?>
filters
=
mapper
.
readValue
(
appliedFilters
.
toString
(),
Map
.
class
);
model
.
addAttribute
(
"filters"
,
filters
);
...
...
@@ -239,6 +240,7 @@ public class ExplorerController extends BaseController {
model
.
addAttribute
(
"crops"
,
cropService
.
list
(
getLocale
()));
model
.
addAttribute
(
"pagedData"
,
accessions
);
model
.
addAttribute
(
"appliedFilters"
,
appliedFilters
);
model
.
addAttribute
(
"currentFilters"
,
currentFilters
);
model
.
addAttribute
(
"availableFilters"
,
availableFilters
);
...
...
@@ -447,6 +449,7 @@ public class ExplorerController extends BaseController {
AppliedFilters
appliedFilters
=
mapper
.
readValue
(
jsonFilter
,
AppliedFilters
.
class
);
String
[]
selectedFilters
=
appliedFilters
.
getFilterNames
();
final
List
<
GenesysFilter
>
currentFilters
=
filterHandler
.
selectFilters
(
selectedFilters
);
model
.
addAttribute
(
"appliedFilters"
,
appliedFilters
);
model
.
addAttribute
(
"currentFilters"
,
currentFilters
);
// JSP works with JsonObject
...
...
src/main/resources/content/language.properties
View file @
6d810d65
...
...
@@ -367,6 +367,8 @@ filter.coll.collMissId=Collecting mission ID
filter.storage
=
Type of Germplasm storage
filter.string.equals
=
Equals
filter.string.like
=
Starts with
filter.inverse
=
Excluding
filter.set-inverse
=
Exclude selected values
search.page.title
=
Full-text Search
...
...
src/main/webapp/WEB-INF/jsp/accession/explore.jsp
View file @
6d810d65
...
...
@@ -90,6 +90,7 @@
<c:forEach
items=
"
${
currentFilters
}
"
var=
"filter"
>
<c:set
var=
"normalizedKey"
value=
"
${
filter
.
key
.
replace
(
'.'
,
'-'
).
replace
(
':'
,
'_'
)
}
"
/>
<c:set
var=
"appliedFilter"
value=
"
${
appliedFilters
.
get
(
filter
.
key
)
}
"
/>
<div
class=
"clearfix filter-block"
id=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
_filter"
norm-key=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
>
<div
class=
"col-lg-3 edit-fil"
>
...
...
@@ -109,7 +110,7 @@
<c:forEach
items=
"
${
filter
.
options
}
"
var=
"option"
>
<div>
<label>
<input
class=
"filter-list"
id=
"
<c:out
value=
"
${
normalizedKey
}${
option
.
value
}
"
/>
_input"
${
fn:contains
(
filters
[
f
ilter.key
],
option.value
)?'
checked
'
:
''}
norm-key=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
type=
"checkbox"
value=
"${option.value}"
/>
<input
class=
"filter-list"
id=
"
<c:out
value=
"
${
normalizedKey
}${
option
.
value
}
"
/>
_input"
${
fn:contains
(
filters
[
appliedF
ilter.key
],
option.value
)?'
checked
'
:
''}
norm-key=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
type=
"checkbox"
value=
"${option.value}"
/>
<spring:message
code=
"
${
option
.
name
}
"
/>
</label>
</div>
...
...
@@ -121,7 +122,7 @@
<c:forEach
items=
"
${
filter
.
options
}
"
var=
"option"
>
<div>
<label>
<input
class=
"filter-list"
id=
"
<c:out
value=
"
${
normalizedKey
}${
option
.
value
}
"
/>
_input"
${
fn:contains
(
filters
[
f
ilter.key
],
option.value
)?'
checked
'
:
''}
norm-key=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
type=
"checkbox"
value=
"${option.value}"
/>
<input
class=
"filter-list"
id=
"
<c:out
value=
"
${
normalizedKey
}${
option
.
value
}
"
/>
_input"
${
fn:contains
(
filters
[
appliedF
ilter.key
],
option.value
)?'
checked
'
:
''}
norm-key=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
type=
"checkbox"
value=
"${option.value}"
/>
<spring:message
code=
"
${
option
.
name
}
"
/>
</label>
</div>
...
...
@@ -149,9 +150,9 @@
</c:when>
<c:when
test=
"
${
filter
.
dataType
==
'BOOLEAN'
}
"
>
<div
class=
""
>
<div><label><input
type=
"checkbox"
${
fn:contains
(
filters
[
f
ilter.key
],
'
true
')?'
checked
'
:
''}
class=
"filter-bool"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
id=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
value=
"true"
><spring:message
code=
"boolean.true"
/></label></div>
<div><label><input
type=
"checkbox"
${
fn:contains
(
filters
[
f
ilter.key
],
'
false
')?'
checked
'
:
''}
class=
"filter-bool"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
id=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
value=
"false"
><spring:message
code=
"boolean.false"
/></label></div>
<div><label><input
type=
"checkbox"
${
fn:contains
(
filters
[
f
ilter.key
],
'
null
')?'
checked
'
:
''}
class=
"filter-bool"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
id=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
value=
"null"
><spring:message
code=
"boolean.null"
/></label></div>
<div><label><input
type=
"checkbox"
${
fn:contains
(
filters
[
appliedF
ilter.key
],
'
true
')?'
checked
'
:
''}
class=
"filter-bool"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
id=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
value=
"true"
><spring:message
code=
"boolean.true"
/></label></div>
<div><label><input
type=
"checkbox"
${
fn:contains
(
filters
[
appliedF
ilter.key
],
'
false
')?'
checked
'
:
''}
class=
"filter-bool"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
id=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
value=
"false"
><spring:message
code=
"boolean.false"
/></label></div>
<div><label><input
type=
"checkbox"
${
fn:contains
(
filters
[
appliedF
ilter.key
],
'
null
')?'
checked
'
:
''}
class=
"filter-bool"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
id=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
value=
"null"
><spring:message
code=
"boolean.null"
/></label></div>
</div>
</c:when>
<c:when
test=
"
${
filter
.
key
==
'crops'
}
"
>
...
...
@@ -184,7 +185,10 @@
</div>
<div
class=
"col-lg-9"
>
<div
class=
"filter-values"
id=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
_value"
>
<c:forEach
items=
"
${
filters
[
filter
.
key
]
}
"
var=
"value"
>
<c:if
test=
"
${
appliedFilter
.
inverse
}
"
>
<spring:message
code=
"filter.inverse"
/>
</c:if>
<c:forEach
items=
"
${
filters
[
appliedFilter
.
key
]
}
"
var=
"value"
>
<c:set
var=
"string"
value=
"
${
value
}
"
/>
<c:if
test=
"
${
fn:
contains
(
value
,
'range'
)
}
"
>
<c:set
var=
"string"
value=
"
${
fn:
replace
(
value
,
'{range=['
,
'Between '
)
}
"
/>
...
...
src/main/webapp/WEB-INF/jsp/accession/overview.jsp
View file @
6d810d65
...
...
@@ -29,6 +29,7 @@
<c:forEach
items=
"
${
currentFilters
}
"
var=
"filter"
>
<c:set
var=
"normalizedKey"
value=
"
${
filter
.
key
.
replace
(
'.'
,
'-'
).
replace
(
':'
,
'_'
)
}
"
/>
<c:set
var=
"appliedFilter"
value=
"
${
appliedFilters
.
get
(
filter
.
key
)
}
"
/>
<div
class=
"clearfix filter-block"
id=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
_filter"
norm-key=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
"
i-key=
"
<c:out
value=
"
${
filter
.
key
}
"
/>
"
>
<div
class=
"col-lg-3 edit-fil"
>
...
...
@@ -43,7 +44,10 @@
</div>
<div
class=
"col-lg-9"
>
<div
class=
"filter-values"
id=
"
<c:out
value=
"
${
normalizedKey
}
"
/>
_value"
>
<c:forEach
items=
"
${
filters
[
filter
.
key
]
}
"
var=
"value"
>
<c:if
test=
"
${
appliedFilter
.
inverse
}
"
>
<spring:message
code=
"filter.inverse"
/>
</c:if>
<c:forEach
items=
"
${
filters
[
appliedFilter
.
key
]
}
"
var=
"value"
>
<c:set
var=
"string"
value=
"
${
value
}
"
/>
<c:if
test=
"
${
fn:
contains
(
value
,
'range'
)
}
"
>
<c:set
var=
"string"
value=
"
${
fn:
replace
(
value
,
'{range=['
,
'Between '
)
}
"
/>
...
...
src/test/java/org/genesys2/server/model/filters/InverseFiltersTest.java
0 → 100644
View file @
6d810d65
package
org.genesys2.server.model.filters
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
java.io.IOException
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.genesys2.server.service.impl.FilterHandler.AppliedFilters
;
import
org.genesys2.server.test.PropertyPlacholderInitializer
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.test.context.ActiveProfiles
;
import
org.springframework.test.context.ContextConfiguration
;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
;
import
com.fasterxml.jackson.core.JsonParseException
;
import
com.fasterxml.jackson.databind.JsonMappingException
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
@ContextConfiguration
(
classes
=
InverseFiltersTest
.
Config
.
class
,
initializers
=
PropertyPlacholderInitializer
.
class
)
@ActiveProfiles
(
"dev"
)
public
class
InverseFiltersTest
{
public
static
final
Log
LOG
=
LogFactory
.
getLog
(
InverseFiltersTest
.
class
);
public
static
class
Config
{
@Bean
public
ObjectMapper
objectMapper
()
{
return
new
ObjectMapper
();
}
}
@Autowired
private
ObjectMapper
objectMapper
;
@Test
public
void
testDeserializeNeg
()
throws
JsonParseException
,
JsonMappingException
,
IOException
{
String
source
=
"{\"key\":[1,{\"min\":2},\"Test\"],\"-key2\":[{\"max\":2.1},{\"range\":[-1,3.0]}],\"key3\":[{\"like\":\"Te\"},null]}"
;
AppliedFilters
afs
=
objectMapper
.
readValue
(
source
,
AppliedFilters
.
class
);
String
result
=
objectMapper
.
writeValueAsString
(
afs
);
LOG
.
info
(
result
);
assertTrue
(
source
.
equals
(
result
));
assertTrue
(
"-key2 must be a negative filter"
,
afs
.
get
(
"key2"
).
isInverse
());
assertFalse
(
"key must not be a negative filter"
,
afs
.
get
(
"key"
).
isInverse
());
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment