Skip to content

Commit

Permalink
view: kick out a row if is no longer matching the filters
Browse files Browse the repository at this point in the history
  • Loading branch information
teosarca committed Mar 25, 2019
1 parent 735e01a commit ddb5603
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 14 deletions.
99 changes: 88 additions & 11 deletions src/main/java/de/metas/ui/web/view/DefaultView.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -52,7 +55,6 @@
import de.metas.ui.web.window.model.sql.SqlOptions;
import de.metas.util.NumberUtils;
import de.metas.util.Services;
import lombok.Getter;
import lombok.NonNull;

/*
Expand Down Expand Up @@ -114,6 +116,7 @@ public static final Builder builder(final IViewDataRepository viewDataRepository
/** Regular filters */
private final ImmutableList<DocumentFilter> filters;
private transient ImmutableList<DocumentFilter> _allFilters;
private final boolean applySecurityRestrictions;

//
// Misc
Expand All @@ -125,6 +128,8 @@ public static final Builder builder(final IViewDataRepository viewDataRepository

private final IViewInvalidationAdvisor viewInvalidationAdvisor;

private final ChangedRowIdsCollector changedRowIdsToCheck = new ChangedRowIdsCollector();

private DefaultView(final Builder builder)
{
viewId = builder.getViewId();
Expand All @@ -147,20 +152,19 @@ private DefaultView(final Builder builder)
{
viewEvaluationCtx = ViewEvaluationCtx.newInstanceFromCurrentContext();

final boolean applySecurityRestrictions = builder.isApplySecurityRestrictions();
this.applySecurityRestrictions = builder.isApplySecurityRestrictions();
selectionsRef = ExtendedMemorizingSupplier.of(() -> {
if (defaultSelectionDeleteBeforeCreate.get())
{
viewDataRepository.deleteSelection(viewId);
}

final SqlDocumentFilterConverterContext context = SqlDocumentFilterConverterContext.EMPTY;
final ViewRowIdsOrderedSelection defaultSelection = viewDataRepository.createOrderedSelection(
getViewEvaluationCtx(),
viewId,
ImmutableList.copyOf(Iterables.concat(stickyFilters, filters)),
applySecurityRestrictions,
context);
SqlDocumentFilterConverterContext.EMPTY);

return new ViewRowIdsOrderedSelections(defaultSelection);
});
Expand Down Expand Up @@ -358,6 +362,7 @@ private ViewEvaluationCtx getViewEvaluationCtx()
public ViewResult getPage(final int firstRow, final int pageLength, final List<DocumentQueryOrderBy> orderBys)
{
assertNotClosed();
checkChangedRows();

final ViewEvaluationCtx evalCtx = getViewEvaluationCtx();
final ViewRowIdsOrderedSelection orderedSelection = getOrderedSelection(orderBys);
Expand Down Expand Up @@ -422,6 +427,7 @@ else if (widgetType.isNumeric())
public ViewResult getPageWithRowIdsOnly(final int firstRow, final int pageLength, final List<DocumentQueryOrderBy> orderBys)
{
assertNotClosed();
checkChangedRows();

final ViewEvaluationCtx evalCtx = getViewEvaluationCtx();
final ViewRowIdsOrderedSelection orderedSelection = getOrderedSelection(orderBys);
Expand All @@ -446,6 +452,8 @@ public IViewRow getById(final DocumentId rowId)

private final IViewRow getOrRetrieveById(final DocumentId rowId)
{
checkChangedRows();

return cache_rowsById.getOrLoad(rowId, () -> retrieveRowById(rowId));
}

Expand Down Expand Up @@ -543,14 +551,26 @@ public void notifyRecordsChanged(final TableRecordReferenceSet recordRefs)
return;
}

//
// TODO: Schedule rows to be checked and added or removed from current view
changedRowIdsToCheck.addChangedRows(rowIds);

// Invalidate local rowsById cache
rowIds.forEach(cache_rowsById::remove);
cache_rowsById.removeAll(rowIds);

// Collect event
// TODO: check which rowIds are contained in this view and fire events only for those
ViewChangesCollector.getCurrentOrAutoflush().collectRowsChanged(this, rowIds);
}

private void checkChangedRows()
{
changedRowIdsToCheck.process(rowIds -> selectionsRef
.get()
.computeDefaultSelection(defaultSelection -> viewDataRepository.removeRowIdsNotMatchingFilters(defaultSelection, getAllFilters(), rowIds)));

}

@Override
public void patchViewRow(final RowEditingContext ctx, final List<JSONDocumentChangedEvent> fieldChangeRequests)
{
Expand Down Expand Up @@ -609,24 +629,81 @@ public LookupValuesList getFieldDropdown(final RowEditingContext ctx, final Stri
return documentsCollection.forDocumentReadonly(documentPath, document -> document.getFieldLookupValues(fieldName));
}

//
//
//
//
//
private static class ChangedRowIdsCollector
{
private final HashSet<DocumentId> rowIds = new HashSet<>();

public synchronized void process(@NonNull final Consumer<Set<DocumentId>> consumer)
{
if (rowIds.isEmpty())
{
return;
}

consumer.accept(rowIds);
rowIds.clear();
}

public synchronized void addChangedRows(@NonNull final Collection<DocumentId> rowIdsToAdd)
{
rowIds.addAll(rowIdsToAdd);
}
}

//
//
//
//
//

@FunctionalInterface
private static interface ViewRowIdsOrderedSelectionFactory
{
ViewRowIdsOrderedSelection create(ViewRowIdsOrderedSelection defaultSelection, List<DocumentQueryOrderBy> orderBys);
}

//
//
//

private static final class ViewRowIdsOrderedSelections
{
@Getter
private final ViewRowIdsOrderedSelection defaultSelection;
private final ConcurrentHashMap<ImmutableList<DocumentQueryOrderBy>, ViewRowIdsOrderedSelection> selectionsByOrderBys = new ConcurrentHashMap<>();
private ViewRowIdsOrderedSelection defaultSelection;
private final HashMap<ImmutableList<DocumentQueryOrderBy>, ViewRowIdsOrderedSelection> selectionsByOrderBys = new HashMap<>();

public ViewRowIdsOrderedSelections(@NonNull final ViewRowIdsOrderedSelection defaultSelection)
{
this.defaultSelection = defaultSelection;
}

public ViewRowIdsOrderedSelection computeIfAbsent(final List<DocumentQueryOrderBy> orderBys, @NonNull final ViewRowIdsOrderedSelectionFactory factory)
public synchronized ViewRowIdsOrderedSelection getDefaultSelection()
{
return defaultSelection;
}

public synchronized ViewRowIdsOrderedSelection computeDefaultSelection(@NonNull final UnaryOperator<ViewRowIdsOrderedSelection> mapper)
{
final ViewRowIdsOrderedSelection newDefaultSelection = mapper.apply(defaultSelection);
if (newDefaultSelection == null)
{
throw new AdempiereException("null default selection is not allowed");
}

if (!defaultSelection.equals(newDefaultSelection))
{
this.defaultSelection = newDefaultSelection;
selectionsByOrderBys.clear();
}

return defaultSelection;
}

public synchronized ViewRowIdsOrderedSelection computeIfAbsent(final List<DocumentQueryOrderBy> orderBys, @NonNull final ViewRowIdsOrderedSelectionFactory factory)
{
if (orderBys == null || orderBys.isEmpty())
{
Expand All @@ -641,7 +718,7 @@ public ViewRowIdsOrderedSelection computeIfAbsent(final List<DocumentQueryOrderB
return selectionsByOrderBys.computeIfAbsent(ImmutableList.copyOf(orderBys), orderBysImmutable -> factory.create(defaultSelection, orderBysImmutable));
}

public Set<String> getSelectionIds()
public synchronized ImmutableSet<String> getSelectionIds()
{
final ImmutableSet.Builder<String> selectionIds = ImmutableSet.builder();
selectionIds.add(defaultSelection.getSelectionId());
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/de/metas/ui/web/view/IViewDataRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public interface IViewDataRepository
String getTableName();

String getSqlWhereClause(ViewId viewId, List<DocumentFilter> filters, DocumentIdsSelection rowIds, SqlOptions sqlOpts);

Map<String, DocumentFieldWidgetType> getWidgetTypesByFieldName();

DocumentFilterDescriptorsProvider getViewFilterDescriptors();
Expand All @@ -69,4 +69,6 @@ public interface IViewDataRepository
void scheduleDeleteSelections(Set<String> viewIds);

ViewRowIdsOrderedSelection createOrderedSelection(ViewEvaluationCtx viewEvalCtx, ViewId viewId, List<DocumentFilter> filters, boolean applySecurityRestrictions, SqlDocumentFilterConverterContext context);

ViewRowIdsOrderedSelection removeRowIdsNotMatchingFilters(ViewRowIdsOrderedSelection selection, List<DocumentFilter> filters, Set<DocumentId> rowIds);
}
80 changes: 78 additions & 2 deletions src/main/java/de/metas/ui/web/view/SqlViewDataRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;

import de.metas.logging.LogManager;
import de.metas.ui.web.document.filter.DocumentFilter;
Expand Down Expand Up @@ -133,7 +134,11 @@ private String getTableAlias()
}

@Override
public String getSqlWhereClause(final ViewId viewId, final List<DocumentFilter> filters, final DocumentIdsSelection rowIds, final SqlOptions sqlOpts)
public String getSqlWhereClause(
final ViewId viewId,
final List<DocumentFilter> filters,
final DocumentIdsSelection rowIds,
final SqlOptions sqlOpts)
{
final StringBuilder sqlWhereClause = new StringBuilder();

Expand Down Expand Up @@ -174,7 +179,8 @@ public Map<String, DocumentFieldWidgetType> getWidgetTypesByFieldName()
}

@Override
public ViewRowIdsOrderedSelection createOrderedSelection(final ViewEvaluationCtx viewEvalCtx,
public ViewRowIdsOrderedSelection createOrderedSelection(
final ViewEvaluationCtx viewEvalCtx,
final ViewId viewId,
final List<DocumentFilter> filters,
final boolean applySecurityRestrictions,
Expand Down Expand Up @@ -604,4 +610,74 @@ public <T> List<T> retrieveModelsByIds(final ViewId viewId, final DocumentIdsSel
.list(modelClass);
}

@Override
public ViewRowIdsOrderedSelection removeRowIdsNotMatchingFilters(
@NonNull final ViewRowIdsOrderedSelection selection,
@NonNull final List<DocumentFilter> filters,
@NonNull final Set<DocumentId> rowIds)
{
if (rowIds.isEmpty())
{
return selection;
}

final ViewId viewId = selection.getViewId();
final Set<DocumentId> matchingRowIds = retrieveRowIdsMatchingFilters(viewId, filters, rowIds);
final Set<DocumentId> notMatchingRowIds = Sets.difference(rowIds, matchingRowIds);
if (notMatchingRowIds.isEmpty())
{
return selection;
}

return viewRowIdsOrderedSelectionFactory.removeRowIdsFromSelection(selection, DocumentIdsSelection.of(notMatchingRowIds));
}

private Set<DocumentId> retrieveRowIdsMatchingFilters(
final ViewId viewId,
final List<DocumentFilter> filters,
@NonNull final Set<DocumentId> rowIds)
{
if (rowIds.isEmpty())
{
return rowIds;
}

final String sqlWhereClause = getSqlWhereClause(
viewId,
filters,
DocumentIdsSelection.of(rowIds),
SqlOptions.usingTableName(getTableName()));
final String sql = "SELECT "
+ keyColumnNamesMap.getKeyColumnNamesCommaSeparated()
+ "\n FROM " + getTableName()
+ "\n WHERE " + sqlWhereClause;

PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql, ITrx.TRXNAME_ThreadInherited);
rs = pstmt.executeQuery();

final HashSet<DocumentId> matchingRowIds = new HashSet<>();
while (rs.next())
{
DocumentId rowId = keyColumnNamesMap.retrieveRowId(rs);
if (rowId != null)
{
matchingRowIds.add(rowId);
}
}

return matchingRowIds;
}
catch (Exception ex)
{
throw new DBException(ex, sql);
}
finally
{
DB.close(rs, pstmt);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,13 @@ public List<Object> getSqlValuesList(@NonNull final DocumentId rowId)
return ImmutableList.copyOf(extractComposedKey(rowId).values());
}

public DocumentId retrieveRowId(final ResultSet rs)
{
final String sqlColumnPrefix = null;
final boolean useKeyColumnNames = true;
return retrieveRowId(rs, sqlColumnPrefix, useKeyColumnNames);
}

public DocumentId retrieveRowId(final ResultSet rs, final String sqlColumnPrefix, final boolean useKeyColumnNames)
{
final List<Object> rowIdParts = keyFields
Expand Down

0 comments on commit ddb5603

Please sign in to comment.