Skip to content

Commit

Permalink
adds config option to always allow custom input in SELECT-style Filters
Browse files Browse the repository at this point in the history
  • Loading branch information
awildturtok committed Aug 30, 2023
1 parent fbb9d36 commit 078a89d
Show file tree
Hide file tree
Showing 18 changed files with 69 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ public void resolve(QueryResolveContext context) {
* Values of group filters can have an arbitrary format which is set by the filter itself.
* Hence, we treat the value for the filter as Object.class.
* <p>
* The resolved filter instructs the frontend on how to render and serialize the filter value using the {@link Filter#createFrontendConfig()} method. The filter must implement {@link GroupFilter} and provide the type information of the value to correctly deserialize the received object.
* The resolved filter instructs the frontend on how to render and serialize the filter value using the {@link Filter#createFrontendConfig(com.bakdata.conquery.models.config.ConqueryConfig)} method. The filter must implement {@link GroupFilter} and provide the type information of the value to correctly deserialize the received object.
*/
public static class GroupFilterDeserializer extends StdDeserializer<GroupFilterValue> {
private final NsIdReferenceDeserializer<FilterId, Filter<?>> nsIdDeserializer = new NsIdReferenceDeserializer<>(Filter.class, null, FilterId.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ public class FrontendConfig {
@Email
private String contactEmail;

/**
* If true, users are always allowed to add custom values into SelectFilter input fields.
*/
private boolean alwaysAllowCreateValue = false;


@Data
public static class CurrencyConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.bakdata.conquery.io.storage.NamespaceStorage;
import com.bakdata.conquery.models.auth.entities.Subject;
import com.bakdata.conquery.models.auth.permissions.Ability;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.datasets.Column;
import com.bakdata.conquery.models.datasets.concepts.filters.Filter;
import com.bakdata.conquery.models.datasets.concepts.select.Select;
Expand All @@ -35,17 +36,19 @@
import com.bakdata.conquery.models.identifiable.ids.specific.ConceptId;
import com.bakdata.conquery.models.identifiable.ids.specific.ConceptTreeChildId;
import com.bakdata.conquery.models.identifiable.ids.specific.StructureNodeId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
* This class constructs the concept tree as it is presented to the front end.
*/
@AllArgsConstructor
@Data
@Slf4j
public class FrontEndConceptBuilder {

public static FrontendRoot createRoot(NamespaceStorage storage, Subject subject) {
private final ConqueryConfig conqueryConfig;

public FrontendRoot createRoot(NamespaceStorage storage, Subject subject) {

final FrontendRoot root = new FrontendRoot();
final Map<Id<?>, FrontendNode> roots = root.getConcepts();
Expand Down Expand Up @@ -95,7 +98,7 @@ public static FrontendRoot createRoot(NamespaceStorage storage, Subject subject)
return root;
}

private static FrontendNode createConceptRoot(Concept<?> concept, StructureNode[] structureNodes) {
private FrontendNode createConceptRoot(Concept<?> concept, StructureNode[] structureNodes) {

final MatchingStats matchingStats = concept.getMatchingStats();

Expand All @@ -121,8 +124,8 @@ private static FrontendNode createConceptRoot(Concept<?> concept, StructureNode[
.flatMap(Collection::stream)
.findAny()
.isEmpty())
.selects(concept.getSelects().stream().map(FrontEndConceptBuilder::createSelect).collect(Collectors.toList()))
.tables(concept.getConnectors().stream().map(FrontEndConceptBuilder::createTable).collect(Collectors.toList()))
.selects(concept.getSelects().stream().map(this::createSelect).collect(Collectors.toList()))
.tables(concept.getConnectors().stream().map(this::createTable).collect(Collectors.toList()))
.build();

if (concept instanceof ConceptTreeNode<?> tree && tree.getChildren() != null) {
Expand All @@ -132,7 +135,7 @@ private static FrontendNode createConceptRoot(Concept<?> concept, StructureNode[
}

@Nullable
private static FrontendNode createStructureNode(StructureNode structureNode, Map<Id<?>, FrontendNode> roots) {
private FrontendNode createStructureNode(StructureNode structureNode, Map<Id<?>, FrontendNode> roots) {
final List<ConceptId> unstructured = new ArrayList<>();
for (ConceptId id : structureNode.getContainedRoots()) {
if (!roots.containsKey(id)) {
Expand All @@ -158,7 +161,7 @@ private static FrontendNode createStructureNode(StructureNode structureNode, Map
.build();
}

public static FrontendSelect createSelect(Select select) {
public FrontendSelect createSelect(Select select) {
return FrontendSelect.builder()
.id(select.getId())
.label(select.getLabel())
Expand All @@ -168,16 +171,16 @@ public static FrontendSelect createSelect(Select select) {
.build();
}

public static FrontendTable createTable(Connector con) {
public FrontendTable createTable(Connector con) {
final FrontendTable
result =
FrontendTable.builder()
.id(con.getTable().getId())
.connectorId(con.getId())
.label(con.getLabel())
.isDefault(con.isDefault())
.filters(con.collectAllFilters().stream().map(FrontEndConceptBuilder::createFilter).collect(Collectors.toList()))
.selects(con.getSelects().stream().map(FrontEndConceptBuilder::createSelect).collect(Collectors.toList()))
.filters(con.collectAllFilters().stream().map(this::createFilter).collect(Collectors.toList()))
.selects(con.getSelects().stream().map(this::createSelect).collect(Collectors.toList()))
.supportedSecondaryIds(Arrays.stream(con.getTable().getColumns())
.map(Column::getSecondaryId)
.filter(Objects::nonNull)
Expand All @@ -199,16 +202,16 @@ public static FrontendTable createTable(Connector con) {
return result;
}

public static FrontendFilterConfiguration.Top createFilter(Filter<?> filter) {
public FrontendFilterConfiguration.Top createFilter(Filter<?> filter) {
try {
return filter.createFrontendConfig();
return filter.createFrontendConfig(conqueryConfig);
}
catch (ConceptConfigurationException e) {
throw new IllegalStateException(e);
}
}

private static FrontendNode createCTNode(ConceptElement<?> ce) {
private FrontendNode createCTNode(ConceptElement<?> ce) {
final MatchingStats matchingStats = ce.getMatchingStats();
FrontendNode.FrontendNodeBuilder nodeBuilder = FrontendNode.builder()
.active(null)
Expand Down Expand Up @@ -248,13 +251,13 @@ private static FrontendNode createCTNode(ConceptElement<?> ce) {
return n;
}

public static FrontendList createTreeMap(Concept<?> concept) {
public FrontendList createTreeMap(Concept<?> concept) {
final FrontendList map = new FrontendList();
fillTreeMap(concept, map);
return map;
}

private static void fillTreeMap(ConceptElement<?> ce, FrontendList map) {
private void fillTreeMap(ConceptElement<?> ce, FrontendList map) {
map.add(ce.getId(), createCTNode(ce));
if (ce instanceof ConceptTreeNode && ((ConceptTreeNode<?>) ce).getChildren() != null) {
for (ConceptTreeChild c : ((ConceptTreeNode<?>) ce).getChildren()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.bakdata.conquery.apiv1.frontend.FrontendFilterConfiguration;
import com.bakdata.conquery.io.cps.CPSBase;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.datasets.Column;
import com.bakdata.conquery.models.datasets.Dataset;
import com.bakdata.conquery.models.datasets.concepts.Connector;
Expand Down Expand Up @@ -52,21 +53,21 @@ public Dataset getDataset() {
return getConnector().getDataset();
}

public FrontendFilterConfiguration.Top createFrontendConfig() throws ConceptConfigurationException {
FrontendFilterConfiguration.Top f = FrontendFilterConfiguration.Top.builder()
.id(getId())
.label(getLabel())
.tooltip(getTooltip())
.unit(getUnit())
.allowDropFile(getAllowDropFile())
.pattern(getPattern())
.defaultValue(getDefaultValue())
.build();
configureFrontend(f);
public FrontendFilterConfiguration.Top createFrontendConfig(ConqueryConfig conqueryConfig) throws ConceptConfigurationException {
final FrontendFilterConfiguration.Top f = FrontendFilterConfiguration.Top.builder()
.id(getId())
.label(getLabel())
.tooltip(getTooltip())
.unit(getUnit())
.allowDropFile(getAllowDropFile())
.pattern(getPattern())
.defaultValue(getDefaultValue())
.build();
configureFrontend(f, conqueryConfig);
return f;
}

protected abstract void configureFrontend(FrontendFilterConfiguration.Top f) throws ConceptConfigurationException;
protected abstract void configureFrontend(FrontendFilterConfiguration.Top f, ConqueryConfig conqueryConfig) throws ConceptConfigurationException;

@JsonIgnore
public abstract List<Column> getRequiredColumns();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.bakdata.conquery.io.jackson.serializer.NsIdRef;
import com.bakdata.conquery.io.jackson.serializer.NsIdRefCollection;
import com.bakdata.conquery.models.common.Range;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.datasets.Column;
import com.bakdata.conquery.models.datasets.concepts.filters.Filter;
import com.bakdata.conquery.models.query.filter.RangeFilterNode;
Expand All @@ -36,7 +37,7 @@ public class CountFilter extends Filter<Range.LongRange> {
private boolean distinct;

@Override
public void configureFrontend(FrontendFilterConfiguration.Top f) {
public void configureFrontend(FrontendFilterConfiguration.Top f, ConqueryConfig conqueryConfig) {
f.setType(FrontendFilterType.Fields.INTEGER_RANGE);
f.setMin(1);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.bakdata.conquery.apiv1.frontend.FrontendFilterType;
import com.bakdata.conquery.io.cps.CPSType;
import com.bakdata.conquery.models.common.Range;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.datasets.concepts.filters.Filter;
import com.bakdata.conquery.models.datasets.concepts.filters.SingleColumnFilter;
import com.bakdata.conquery.models.events.MajorTypeId;
Expand All @@ -26,7 +27,7 @@ public EnumSet<MajorTypeId> getAcceptedColumnTypes() {
}

@Override
public void configureFrontend(FrontendFilterConfiguration.Top f) {
public void configureFrontend(FrontendFilterConfiguration.Top f, ConqueryConfig conqueryConfig) {
f.setType(FrontendFilterType.Fields.INTEGER_RANGE);
f.setMin(1);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.bakdata.conquery.apiv1.frontend.FrontendFilterType;
import com.bakdata.conquery.io.cps.CPSType;
import com.bakdata.conquery.models.common.Range;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.datasets.concepts.filters.Filter;
import com.bakdata.conquery.models.datasets.concepts.filters.SingleColumnFilter;
import com.bakdata.conquery.models.events.MajorTypeId;
Expand All @@ -35,7 +36,7 @@ public EnumSet<MajorTypeId> getAcceptedColumnTypes() {
}

@Override
public void configureFrontend(FrontendFilterConfiguration.Top f) throws ConceptConfigurationException {
public void configureFrontend(FrontendFilterConfiguration.Top f, ConqueryConfig conqueryConfig) throws ConceptConfigurationException {
if (getColumn().getType() != MajorTypeId.DATE) {
throw new ConceptConfigurationException(getConnector(), "DATE_DISTANCE filter is incompatible with columns of type " + getColumn().getType());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.bakdata.conquery.apiv1.frontend.FrontendFilterType;
import com.bakdata.conquery.io.cps.CPSType;
import com.bakdata.conquery.models.common.Range;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.datasets.concepts.filters.Filter;
import com.bakdata.conquery.models.datasets.concepts.filters.SingleColumnFilter;
import com.bakdata.conquery.models.events.MajorTypeId;
Expand All @@ -29,7 +30,7 @@ public EnumSet<MajorTypeId> getAcceptedColumnTypes() {
}

@Override
public void configureFrontend(FrontendFilterConfiguration.Top f) throws ConceptConfigurationException {
public void configureFrontend(FrontendFilterConfiguration.Top f, ConqueryConfig conqueryConfig) throws ConceptConfigurationException {
if (getColumn().getType() != MajorTypeId.DATE_RANGE) {
throw new ConceptConfigurationException(getConnector(), "DURATION_SUM filter is incompatible with columns of type "
+ getColumn().getType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.bakdata.conquery.apiv1.frontend.FrontendValue;
import com.bakdata.conquery.io.cps.CPSType;
import com.bakdata.conquery.io.jackson.serializer.NsIdRefCollection;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.datasets.Column;
import com.bakdata.conquery.models.datasets.concepts.filters.Filter;
import com.bakdata.conquery.models.error.ConqueryError;
Expand Down Expand Up @@ -39,7 +40,7 @@ public class FlagFilter extends Filter<String[]> {
private final Map<String, Column> flags;

@Override
protected void configureFrontend(FrontendFilterConfiguration.Top f) throws ConceptConfigurationException {
protected void configureFrontend(FrontendFilterConfiguration.Top f, ConqueryConfig conqueryConfig) throws ConceptConfigurationException {
f.setType(FrontendFilterType.Fields.MULTI_SELECT);

f.setOptions(flags.keySet().stream().map(key -> new FrontendValue(key, key)).toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.bakdata.conquery.io.cps.CPSType;
import com.bakdata.conquery.models.common.IRange;
import com.bakdata.conquery.models.common.Range;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.datasets.concepts.filters.Filter;
import com.bakdata.conquery.models.datasets.concepts.filters.SingleColumnFilter;
import com.bakdata.conquery.models.exceptions.ConceptConfigurationException;
Expand All @@ -29,7 +30,7 @@
public class NumberFilter<RANGE extends IRange<? extends Number, ?>> extends SingleColumnFilter<RANGE> {

@Override
public void configureFrontend(FrontendFilterConfiguration.Top f) throws ConceptConfigurationException {
public void configureFrontend(FrontendFilterConfiguration.Top f, ConqueryConfig conqueryConfig) throws ConceptConfigurationException {
final String type = switch (getColumn().getType()) {
case MONEY -> FrontendFilterType.Fields.MONEY_RANGE;
case INTEGER -> FrontendFilterType.Fields.INTEGER_RANGE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.bakdata.conquery.apiv1.frontend.FrontendFilterConfiguration;
import com.bakdata.conquery.apiv1.frontend.FrontendFilterType;
import com.bakdata.conquery.io.cps.CPSType;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.datasets.concepts.filters.Filter;
import com.bakdata.conquery.models.datasets.concepts.filters.SingleColumnFilter;
import com.bakdata.conquery.models.events.MajorTypeId;
Expand All @@ -20,7 +21,7 @@ public class PrefixTextFilter extends SingleColumnFilter<String> {


@Override
public void configureFrontend(FrontendFilterConfiguration.Top f) {
public void configureFrontend(FrontendFilterConfiguration.Top f, ConqueryConfig conqueryConfig) {
f.setType(FrontendFilterType.Fields.STRING);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.bakdata.conquery.apiv1.frontend.FrontendFilterType;
import com.bakdata.conquery.io.cps.CPSType;
import com.bakdata.conquery.models.common.Range;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.datasets.concepts.filters.Filter;
import com.bakdata.conquery.models.datasets.concepts.filters.SingleColumnFilter;
import com.bakdata.conquery.models.events.MajorTypeId;
Expand All @@ -24,7 +25,7 @@ public EnumSet<MajorTypeId> getAcceptedColumnTypes() {
}

@Override
public void configureFrontend(FrontendFilterConfiguration.Top f) {
public void configureFrontend(FrontendFilterConfiguration.Top f, ConqueryConfig conqueryConfig) {
f.setType(FrontendFilterType.Fields.INTEGER_RANGE);
f.setMin(1);
f.setMax(4);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.bakdata.conquery.io.jackson.View;
import com.bakdata.conquery.io.jackson.serializer.NsIdRef;
import com.bakdata.conquery.io.storage.NamespaceStorage;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.config.IndexConfig;
import com.bakdata.conquery.models.datasets.concepts.Searchable;
import com.bakdata.conquery.models.datasets.concepts.filters.SingleColumnFilter;
Expand Down Expand Up @@ -56,12 +57,12 @@ public EnumSet<MajorTypeId> getAcceptedColumnTypes() {
}

@Override
public void configureFrontend(FrontendFilterConfiguration.Top f) throws ConceptConfigurationException {
public void configureFrontend(FrontendFilterConfiguration.Top f, ConqueryConfig conqueryConfig) throws ConceptConfigurationException {
f.setTemplate(getTemplate());
f.setType(getFilterType());

// If either not searches are available or all are disabled, we allow users to supply their own values
f.setCreatable(getSearchReferences().stream().noneMatch(Predicate.not(Searchable::isSearchDisabled)));
f.setCreatable(conqueryConfig.getFrontend().isAlwaysAllowCreateValue() || getSearchReferences().stream().noneMatch(Predicate.not(Searchable::isSearchDisabled)));

f.setOptions(collectLabels());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.bakdata.conquery.io.jackson.serializer.NsIdRefCollection;
import com.bakdata.conquery.models.common.IRange;
import com.bakdata.conquery.models.common.Range;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.datasets.Column;
import com.bakdata.conquery.models.datasets.concepts.filters.Filter;
import com.bakdata.conquery.models.events.MajorTypeId;
Expand Down Expand Up @@ -57,7 +58,7 @@ public class SumFilter<RANGE extends IRange<? extends Number, ?>> extends Filter
private List<Column> distinctByColumn = Collections.emptyList();

@Override
public void configureFrontend(FrontendFilterConfiguration.Top f) throws ConceptConfigurationException {
public void configureFrontend(FrontendFilterConfiguration.Top f, ConqueryConfig conqueryConfig) throws ConceptConfigurationException {
final String type = switch (getColumn().getType()) {
case MONEY -> FrontendFilterType.Fields.MONEY_RANGE;
case INTEGER -> FrontendFilterType.Fields.INTEGER_RANGE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,14 @@ public class ConceptsProcessor {

private final ConqueryConfig config;

@Getter(lazy = true)
private final FrontEndConceptBuilder frontEndConceptBuilder = new FrontEndConceptBuilder(getConfig());

private final LoadingCache<Concept<?>, FrontendList> nodeCache =
CacheBuilder.newBuilder().softValues().expireAfterWrite(10, TimeUnit.MINUTES).build(new CacheLoader<>() {
@Override
public FrontendList load(Concept<?> concept) {
return FrontEndConceptBuilder.createTreeMap(concept);
return getFrontEndConceptBuilder().createTreeMap(concept);
}
});

Expand Down Expand Up @@ -106,7 +109,7 @@ public CursorAndLength load(Searchable<?> searchable) {

public FrontendRoot getRoot(NamespaceStorage storage, Subject subject) {

final FrontendRoot root = FrontEndConceptBuilder.createRoot(storage, subject);
final FrontendRoot root = getFrontEndConceptBuilder().createRoot(storage, subject);

// Report Violation
ValidatorHelper.createViolationsString(validator.validate(root), log.isTraceEnabled()).ifPresent(log::warn);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public Query getQuery() {
@Override
public void executeTest(StandaloneSupport standaloneSupport) throws IOException {
try {
final FrontendFilterConfiguration.Top actual = connector.getFilters().iterator().next().createFrontendConfig();
final FrontendFilterConfiguration.Top actual = connector.getFilters().iterator().next().createFrontendConfig(standaloneSupport.getConfig());

if (expectedFrontendConfig != null) {
log.info("Checking actual FrontendConfig: {}", actual);
Expand Down
Loading

0 comments on commit 078a89d

Please sign in to comment.