You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2018/12/14 15:02:24 UTC
[syncope] 02/02: [SYNCOPE-1416] merge on jsonb implementation
This is an automated email from the ASF dual-hosted git repository.
fmartelli pushed a commit to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
commit 40fc384f9851868c4db267457d49fb7757b23a77
Author: fmartelli <fa...@gmail.com>
AuthorDate: Fri Dec 14 15:38:23 2018 +0100
[SYNCOPE-1416] merge on jsonb implementation
---
.../persistence/jpa/dao/PGJPAJSONAnySearchDAO.java | 105 ++++++++++++++++-----
.../core/persistence/jpa/dao/JPAAnySearchDAO.java | 11 +--
.../core/persistence/jpa/dao/SearchSupport.java | 24 +++++
.../persistence/jpa/dao/SearchViewSupport.java | 4 -
.../org/apache/syncope/fit/core/SearchITCase.java | 9 +-
5 files changed, 118 insertions(+), 35 deletions(-)
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
index f240705..75b8ff5 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
@@ -18,10 +18,16 @@
*/
package org.apache.syncope.core.persistence.jpa.dao;
+import java.text.ParseException;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
@@ -34,17 +40,60 @@ import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
+ private static final FastDateFormat DATE_FORMAT = FastDateFormat.getInstance(SyncopeConstants.DEFAULT_DATE_PATTERN);
+
@Override
SearchSupport buildSearchSupport(final AnyTypeKind kind) {
return new SearchSupport(kind);
}
@Override
- protected void processOBS(final SearchSupport svs, final OrderBySupport obs, final StringBuilder where) {
+ protected void processOBS(
+ final SearchSupport svs,
+ final Set<String> involvedPlainAttrs,
+ final OrderBySupport obs,
+ final StringBuilder where) {
+
+ Set<String> attrs = obs.items.stream().
+ map(item -> item.orderBy.substring(0, item.orderBy.indexOf(" "))).collect(Collectors.toSet());
+
obs.views.forEach(searchView -> {
- where.append(',').
- append(searchView.name).
- append(' ').append(searchView.alias);
+ if (searchView.name.equals(svs.field().name)) {
+ StringBuilder attrWhere = new StringBuilder();
+ StringBuilder nullAttrWhere = new StringBuilder();
+
+ where.append(", (SELECT * FROM ").append(searchView.name);
+
+ if (svs.nonMandatorySchemas || obs.nonMandatorySchemas) {
+ attrs.forEach(field -> {
+ if (attrWhere.length() == 0) {
+ attrWhere.append(" WHERE ");
+ } else {
+ attrWhere.append(" OR ");
+ }
+ attrWhere.append("plainAttrs @> '[{\"schema\":\"").append(field).append("\"}]'::jsonb");
+
+ nullAttrWhere.append(" UNION SELECT DISTINCT any_id,").append(svs.table().alias).append(".*, ").
+ append("'{\"schema\": \"").
+ append(field).
+ append("\"}'::jsonb as attrs, '{}'::jsonb as attrValues").
+ append(" FROM ").append(svs.table().name).append(" ").append(svs.table().alias).
+ append(", ").append(svs.field().name).
+ append(" WHERE ").
+ append("any_id NOT IN ").
+ append("(SELECT distinct any_id FROM ").
+ append(svs.field().name).
+ append(" WHERE ").append(svs.table().alias).append(".id=any_id AND ").
+ append("plainAttrs @> '[{\"schema\":\"").append(field).append("\"}]'::jsonb)");
+ });
+ where.append(attrWhere).append(nullAttrWhere);
+ }
+
+ where.append(')');
+ } else {
+ where.append(',').append(searchView.name);
+ }
+ where.append(' ').append(searchView.alias);
});
}
@@ -62,20 +111,12 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
obs.views.add(svs.field());
- item.select = svs.field().alias + ".attrValues ->> '" + fieldName + "' AS " + fieldName;
+ item.select = svs.field().alias + ".attrValues ->> '" + field(schema, null) + "' AS " + fieldName;
item.where = "attrs ->> 'schema' = '" + fieldName + "'";
item.orderBy = fieldName + " " + clause.getDirection().name();
}
- private void fillAttrQuery(
- final AnyUtils anyUtils,
- final StringBuilder query,
- final PlainAttrValue attrValue,
- final PlainSchema schema,
- final AttributeCond cond,
- final boolean not,
- final List<Object> parameters) {
-
+ private Pair<Boolean, String> field(final PlainSchema schema, final AttributeCond.Type type) {
String key;
boolean lower = false;
switch (schema.getType()) {
@@ -100,9 +141,22 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
break;
default:
- lower = cond.getType() == AttributeCond.Type.IEQ || cond.getType() == AttributeCond.Type.ILIKE;
+ lower = type == AttributeCond.Type.IEQ || type == AttributeCond.Type.ILIKE;
key = "stringValue";
}
+ return Pair.of(lower, key);
+ }
+
+ private void fillAttrQuery(
+ final AnyUtils anyUtils,
+ final StringBuilder query,
+ final PlainAttrValue attrValue,
+ final PlainSchema schema,
+ final AttributeCond cond,
+ final boolean not,
+ final List<Object> parameters) {
+
+ Pair<Boolean, String> field = field(schema, cond.getType());
if (!not && cond.getType() == AttributeCond.Type.EQ) {
PlainAttr<?> container = anyUtils.newPlainAttr();
@@ -119,11 +173,11 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
} else {
query.append("attrs ->> 'schema' = ?").append(setParameter(parameters, cond.getSchema())).
append(" AND ").
- append(lower ? "LOWER(" : "").
+ append(field.getLeft() ? "LOWER(" : "").
append(schema.isUniqueConstraint()
? "attrs -> 'uniqueValue'" : "attrValues").
- append(" ->> '").append(key).append("'").
- append(lower ? ")" : "");
+ append(" ->> '").append(field.getRight()).append("'").
+ append(field.getLeft() ? ")" : "");
switch (cond.getType()) {
case LIKE:
@@ -175,9 +229,18 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
query.append('=');
}
- query.append(lower ? "LOWER(" : "").
- append("?").append(setParameter(parameters, cond.getExpression())).
- append(lower ? ")" : "");
+ String value = cond.getExpression();
+ if (schema.getType() == AttrSchemaType.Date) {
+ try {
+ value = String.valueOf(DATE_FORMAT.parse(value).getTime());
+ } catch (ParseException e) {
+ LOG.error("Could not parse {} as date", value, e);
+ }
+ }
+
+ query.append(field.getLeft() ? "LOWER(" : "").
+ append("?").append(setParameter(parameters, value)).
+ append(field.getLeft() ? ")" : "");
}
}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
index 11ace3a..0a50b2d 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
@@ -245,10 +245,8 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
final OrderBySupport obs,
final StringBuilder where) {
- Set<String> attrs = new HashSet<>(involvedPlainAttrs);
- for (OrderBySupport.Item item : obs.items) {
- attrs.add(item.orderBy.substring(0, item.orderBy.indexOf(" ")));
- }
+ Set<String> attrs = obs.items.stream().
+ map(item -> item.orderBy.substring(0, item.orderBy.indexOf(" "))).collect(Collectors.toSet());
obs.views.forEach(searchView -> {
where.append(',');
@@ -261,10 +259,11 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
if (svs.nonMandatorySchemas || obs.nonMandatorySchemas) {
attrs.forEach(field -> {
if (attrWhere.length() == 0) {
- attrWhere.append(" WHERE schema_id='").append(field).append("'");
+ attrWhere.append(" WHERE ");
} else {
- attrWhere.append(" OR ").append("schema_id='").append(field).append("'");
+ attrWhere.append(" OR ");
}
+ attrWhere.append("schema_id='").append(field).append("'");
nullAttrWhere.append(" UNION SELECT any_id, ").
append("'").
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
index 3304a70..f10b29a 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
@@ -22,6 +22,9 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAnyObject;
+import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
public class SearchSupport {
@@ -103,6 +106,27 @@ public class SearchSupport {
return result;
}
+ public SearchView table() {
+ String result;
+
+ switch (anyTypeKind) {
+ case ANY_OBJECT:
+ result = JPAAnyObject.TABLE;
+ break;
+
+ case GROUP:
+ result = JPAGroup.TABLE;
+ break;
+
+ case USER:
+ default:
+ result = JPAUser.TABLE;
+ break;
+ }
+
+ return new SearchView("t", result);
+ }
+
public SearchView field() {
String result;
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchViewSupport.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchViewSupport.java
index 9dc95d8..93045f9 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchViewSupport.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchViewSupport.java
@@ -30,10 +30,6 @@ public class SearchViewSupport extends SearchSupport {
return new SearchView("sva", field().name + "_attr");
}
- public SearchView nullAttr() {
- return new SearchView("svna", field().name + "_null_attr");
- }
-
public SearchView uniqueAttr() {
return new SearchView("svua", field().name + "_unique_attr");
}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
index 98cfd21..6151871 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
@@ -293,7 +293,7 @@ public class SearchITCase extends AbstractITCase {
PagedResult<UserTO> issueSYNCOPE1416 = userService.search(new AnyQuery.Builder().
realm(SyncopeConstants.ROOT_REALM).
fiql(SyncopeClient.getUserSearchConditionBuilder().
- is("loginDate").lexicalNotBefore("2009-05-26").
+ is("loginDate").lexicalNotBefore("2009-05-26T00:00:00+0300").
and("username").equalTo("rossini").query()).
orderBy(SyncopeClient.getOrderByClauseBuilder().asc("loginDate").build()).
build());
@@ -438,9 +438,10 @@ public class SearchITCase extends AbstractITCase {
@Test
public void orderBy() {
PagedResult<UserTO> matchingUsers = userService.search(
- new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
- fiql(SyncopeClient.getUserSearchConditionBuilder().is("userId").equalTo("*@apache.org").query()).
- orderBy(SyncopeClient.getOrderByClauseBuilder().asc("status").desc("firstname").build()).build());
+ new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).fiql(
+ SyncopeClient.getUserSearchConditionBuilder().is("userId").equalTo("*@apache.org").query()).
+ orderBy(SyncopeClient.getOrderByClauseBuilder().asc("status").desc("firstname").build()).
+ build());
assertNotNull(matchingUsers);
assertFalse(matchingUsers.getResult().isEmpty());