net.intelie.pipes.MapPropertySource Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pipes-api Show documentation
Show all versions of pipes-api Show documentation
Intelie Pipes' API classes and interfaces
package net.intelie.pipes;
import net.intelie.pipes.filters.ObjectSink;
import net.intelie.pipes.types.*;
import net.intelie.pipes.util.GetUtils;
import net.intelie.pipes.util.Iterables;
import net.intelie.pipes.util.Levenshtein;
import java.util.*;
public class MapPropertySource implements PropertySource {
public static final String TIMESTAMP = "timestamp";
private static final long serialVersionUID = 1L;
private final List defaultProperties;
private final String timestampKey;
private final Map types;
private final boolean strict;
private final MapAdapter adapter;
private final Metadata metadata;
private final Type defaultType;
public MapPropertySource() {
this(TIMESTAMP, Collections.emptyList(), Collections.emptyMap(), false, null, Metadata.RAW);
}
private MapPropertySource(String timestampKey, List defaultProperties, Map types, boolean strict, MapAdapter adapter, Metadata metadata) {
this.timestampKey = timestampKey;
this.adapter = adapter != null ? adapter : new DefaultMapAdapter();
this.metadata = metadata;
this.defaultProperties = defaultProperties;
this.types = types;
this.strict = strict;
Type valueType = MapType.getValueType(metadata.type());
this.defaultType = valueType != null ? valueType : Type.STRING;
}
private List resolve(List defaultProperties) throws PipeException {
List props = new ArrayList<>(defaultProperties.size());
for (String name : defaultProperties) {
props.add(new PropertyGroup(property(name)));
}
return props;
}
public MapPropertySource asStrict() {
return asStrict(true);
}
public MapPropertySource asStrict(boolean strict) {
return new MapPropertySource(timestampKey, defaultProperties, types, strict, adapter, metadata);
}
public MapPropertySource safe() {
return safe(true);
}
public MapPropertySource safe(boolean safe) {
return new MapPropertySource(timestampKey, defaultProperties, types, strict, adapter, metadata.withSafe(safe));
}
public MapPropertySource withTypes(Map types) {
return new MapPropertySource(timestampKey, defaultProperties, types, strict, adapter, metadata);
}
public MapPropertySource withDefaultProperties(String... filterProperties) throws PipeException {
return withDefaultProperties(Arrays.asList(filterProperties));
}
public MapPropertySource withDefaultProperties(List filterProperties) throws PipeException {
return new MapPropertySource(timestampKey, resolve(filterProperties), types, strict, adapter, metadata);
}
public MapPropertySource withTimestamp(String timestampKey) {
return new MapPropertySource(timestampKey, defaultProperties, types, strict, adapter, metadata);
}
public MapPropertySource withAdapter(MapAdapter adapter) {
return new MapPropertySource(timestampKey, defaultProperties, types, strict, adapter, metadata);
}
@Override
public Property timestamp() throws PipeException {
return makeProp(timestampKey, Type.NUMBER);
}
@Override
public Property property() throws PipeException {
return new MapProperty(metadata.type(), null);
}
@Override
public PropertySource newSource(Metadata metadata) {
return metadata.hasRowFields() ?
new PipePropertySource(metadata) :
new MapPropertySource(timestampKey, defaultProperties, types, strict, adapter, metadata);
}
@Override
@SuppressWarnings("unchecked")
public Property property(String name) throws PipeException {
Type type = types.get(name);
if (type == null && (strict || !acceptsProperties()))
throw Levenshtein.makeExc(name, types.keySet(), "Cannot resolve property '%s'.%s");
return makeProp(name, type);
}
private boolean acceptsProperties() {
return Type.OBJECT.equals(metadata.type()) || metadata.type().isAssignableTo(Type.MAP);
}
private Property makeProp(String name, Type type) throws PipeException {
return new MapProperty(type, name);
}
@Override
public List defaultProperties() {
return defaultProperties;
}
@Override
public PropertyReplacer makeReplacer(ClauseInfo fields) throws PipeException {
PipeException.check(acceptsProperties(), "Cannot set fields in an expression of type '%s'", metadata.type());
RowFields rowFields = new RowFields(fields);
return new MyReplacer(rowFields);
}
@Override
public Metadata metadata() {
return metadata;
}
public class MapProperty implements Property {
private static final long serialVersionUID = 3847552900381849629L;
private final Type originalType;
private final Type hint;
private final Type type;
private final String identifier;
private final boolean single;
private final Scalar[] nth;
private final boolean reallySingle;
private final boolean requiresObjectFix;
public MapProperty(Type type, String identifier) throws PipeException {
this(type, null, identifier, true);
}
public MapProperty(Type originalType, Type hint, String identifier, boolean single, Scalar... nth) throws PipeException {
this.originalType = originalType;
this.hint = hint;
this.single = single;
this.reallySingle = single && nth.length == 0;
Type type = makeType(originalType, hint, identifier, reallySingle, nth);
this.type = type != null ? type : defaultType;
this.requiresObjectFix = type == null;
this.identifier = identifier;
this.nth = nth;
}
@Override
public boolean requiresObjectFix() {
return requiresObjectFix;
}
private Type makeType(Type originalType, Type hint, String identifier, boolean reallySingle, Scalar[] nth) throws PipeException {
if (hint != null)
return hint;
if (originalType == null)
originalType = adapter.type(identifier, reallySingle);
Type answer = GetUtils.inferType(originalType, nth);
if (answer != null)
return answer;
else
return null;
}
@Override
public Object eval(Scope parent, Object obj) {
if (identifier == null)
return type.cast(resolveIndexes(parent, obj, obj));
return type.cast(resolveValue(parent, obj));
}
@Override
public boolean sameProperty(Property other) {
if (!(other instanceof MapProperty))
return false;
MapProperty that = (MapProperty) other;
return Objects.equals(this.identifier, that.identifier) &&
Objects.equals(this.type, that.type) &&
sameScalars(this.nth, that.nth);
}
private boolean sameScalars(Scalar[] thisNth, Scalar[] thatNth) {
if (thisNth.length != thatNth.length)
return false;
for (int i = 0; i < thisNth.length; i++) {
if (!Level.CONSTANT.accepts(thatNth[i]) ||
!Level.CONSTANT.accepts(thisNth[i]) ||
!Objects.equals(Level.asScalar(thisNth[i]).eval(null, null), Level.asScalar(thatNth[i]).eval(null, null)))
return false;
}
return true;
}
private Object resolveValue(Scope parent, Object obj) {
Object value = identifier == null ? obj : adapter.get(obj, identifier, reallySingle);
return resolveIndexes(parent, obj, value);
}
private Object resolveIndexes(Scope parent, Object obj, Object value) {
if (nth.length == 0)
return value;
for (Scalar scalar : nth) {
value = GetUtils.get(value, scalar.eval(parent, obj));
}
return value;
}
@Override
public Type