StringFilter.java

/*
 * Copyright 2019 Global Crop Diversity Trust
 *
 * 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 org.genesys.blocks.model.filters;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.collections4.CollectionUtils;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.StringPath;

import lombok.Data;
import lombok.experimental.Accessors;

/**
 * Utility filtering for String types. Matches all constraints.
 */
@Data
@Accessors(fluent = true)
public class StringFilter implements PropertyFilter<StringFilter, StringPath> {

	private static final long serialVersionUID = -1950139291270046688L;

	/** Equal. */
	@JsonDeserialize(using = StringFilter.SetDeserializer.class)
	public Set<String> eq;

	/** Contains substring. */
	@JsonDeserialize(using = StringFilter.SetDeserializer.class)
	public Set<String> contains;

	/** Starts with. */
	@JsonDeserialize(using = StringFilter.SetDeserializer.class)
	public Set<String> sw;

	/** Greater or equal than. */
	public String ge;
	/** Less or equal than. */
	public String le;

	@Override
	public boolean isEmpty() {
		return CollectionUtils.isEmpty(eq) && CollectionUtils.isEmpty(contains) && CollectionUtils.isEmpty(sw) && ge == null && le == null;
	}

	@Override
	public StringFilter copyFilter() {
		return new StringFilter()
			.eq(eq == null ? null : new HashSet<>(eq))
			.contains(contains == null ? null : new HashSet<>(contains))
			.sw(sw == null ? null : new HashSet<>(sw))
			.ge(ge)
			.le(le);
	}

	/**
	 * Builds the query.
	 *
	 * @param val the val
	 * @return the boolean builder
	 */
	public BooleanBuilder buildQuery(final StringPath val) {
		final BooleanBuilder and = new BooleanBuilder();
		if (eq != null && !eq.isEmpty()) {
			and.and(val.isNotNull()).and(val.in(eq));
		}
		if (sw != null && !sw.isEmpty()) {
			and.and(val.isNotNull()).andAnyOf(sw.stream().map(val::startsWith).toArray(Predicate[]::new));
		}
		if (contains != null && !contains.isEmpty()) {
			and.and(val.isNotNull()).andAnyOf(contains.stream().map(val::contains).toArray(Predicate[]::new));
		}
		if (ge != null) {
			and.and(val.isNotNull().and(val.goe(ge)));
		}
		if (le != null) {
			and.and(val.isNotNull().and(val.loe(le)));
		}
		return and;
	}

	static class SetDeserializer extends JsonDeserializer<Set<String>> {
		@Override
		public Set<String> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
			final Set<String> values = new HashSet<>();
			if (jsonParser.getCurrentToken() == JsonToken.START_ARRAY) {
				while (jsonParser.getCurrentToken() != null && jsonParser.getCurrentToken() != JsonToken.END_ARRAY) {
					if (jsonParser.nextToken() == JsonToken.VALUE_STRING) {
						values.add(jsonParser.getText());
					}
				}
			} else if (jsonParser.getCurrentToken() == JsonToken.VALUE_STRING) {
				values.add(jsonParser.getText());
			}
			return values;
		}
	}

}