All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.intelie.pipes.PipePropertySource Maven / Gradle / Ivy

There is a newer version: 0.25.5
Show newest version
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.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

public class PipePropertySource implements PropertySource {
    private static final long serialVersionUID = 1L;
    private final RowFields fields;
    private final int offset;
    private final Metadata metadata;

    public PipePropertySource(Metadata metadata) {
        this.metadata = metadata;
        this.fields = metadata.getRowFields();
        this.offset = fields.timestamp().size() + fields.group().size();
    }

    @Override
    public Property timestamp() throws PipeException {
        if (fields.indexOf(Row.TIMESTAMP) < 0)
            return new PipeProperty(Type.NUMBER, Row.TIMESTAMP, -1);
        return property(Type.NUMBER, Row.TIMESTAMP);
    }

    @Override
    public Property property() throws PipeException {
        return new PipeProperty(defineTypeFor(offset), fields.name(offset), offset);
    }

    @Override
    public Property property(String name) throws PipeException {
        return property(null, name);
    }

    Property property(Type declared, String name) throws PipeException {
        int index = fields.indexOf(name);
        if (index < 0)
            throw Levenshtein.makeExc(name, fields.names(), "Cannot resolve property '%s'.%s");

        return new PipeProperty(declared == null ? defineTypeFor(index) : declared, name, index);
    }

    @Override
    public List defaultProperties() {
        return Collections.emptyList();
    }

    @Override
    public Metadata metadata() {
        return metadata;
    }

    @Override
    public PropertyReplacer makeReplacer(ClauseInfo fields) {
        return new PipePropertyReplacer(this.fields, fields);
    }

    @Override
    public PropertySource newSource(Metadata metadata) {
        throw new UnsupportedOperationException("Can't use newSource on a PipePropertySource");
    }

    private Type defineTypeFor(int index) throws PipeException {
        return fields.type(index);
    }

    public static class PipeProperty implements Property {
        private final Type originalType;
        private final Type type;
        private final String identifier;
        private final int index;
        private final Scalar[] args;

        public PipeProperty(Type type, String identifier, int index, Scalar... args) throws PipeException {
            this(type, type, identifier, index, args);
        }

        public PipeProperty(Type originalType, Type type, String identifier, int index, Scalar... args) throws PipeException {
            this.originalType = originalType;
            this.type = type != null ? type : Type.OBJECT;
            this.identifier = identifier;
            this.index = index;
            this.args = args;
        }

        @Override
        public Object eval(Scope parent, Object obj) {
            if (index == -1) return null;
            Row row = castRow(obj);
            if (row == null) return null;
            Object value = row.get(index);
            for (Scalar arg : args) {
                value = GetUtils.get(value, arg.eval(parent, obj));
            }
            return type.cast(value);
        }

        @Override
        public boolean sameProperty(Property other) {
            if (!(other instanceof PipeProperty))
                return false;
            PipeProperty that = (PipeProperty) other;
            return Objects.equals(this.identifier, that.identifier) &&
                    Objects.equals(this.index, that.index) &&
                    Objects.equals(this.type, that.type) &&
                    sameScalars(this.args, that.args);
        }

        @Override
        public boolean requiresObjectFix() {
            return false;
        }

        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 Row castRow(Object obj) {
            if (!(obj instanceof Row)) return null;
            Row row = (Row) obj;
            if (index >= row.size()) return null;
            return row;
        }

        @Override
        public Type type() {
            return type;
        }

        @Override
        public String name() {
            return identifier;
        }

        @Override
        public Iterable args() {
            return Arrays.asList(args);
        }

        @Override
        public Property indexed(Scalar... args) throws PipeException {
            return new PipeProperty(originalType, GetUtils.inferType(originalType, args), identifier, index, args);
        }

        @Override
        public Property hint(Type type) throws PipeException {
            return new PipeProperty(type, identifier, index, args);
        }

        @Override
        public void evalRaw(Scope parent, Object obj, ObjectSink sink) {
            if (index == -1) return;

            Row row = castRow(obj);
            if (row == null) return;

            Object o = row.get(index);
            for (Scalar scalar : args)
                o = GetUtils.get(o, scalar.eval(parent, obj));

            sink.onSingle(o);
        }

        @Override
        public PropertyVisitor visit(Scope parent, PropertyVisitor visitor) {
            for (Scalar scalar : args)
                scalar.visit(parent, visitor);
            return visitor.property(this);
        }

        @Override
        public String toString() {
            return "pipe:" + identifier + "[" + Iterables.join(", ", Arrays.asList(args)) + "]@" + type;
        }
    }

    public static class PipePropertyReplacer implements PropertyReplacer {
        private static final long serialVersionUID = 1L;
        private final RowType type;

        public PipePropertyReplacer(RowFields originalFields, ClauseInfo newFields) {
            this.type = new RowType(new RowFields(
                    originalFields.timestamp(),
                    originalFields.group(),
                    new ClauseInfo(Stream.concat(
                            originalFields.select().stream(),
                            newFields.stream()).toArray(FieldInfo[]::new))
            ));
        }

        @Override
        public Type type() {
            return type;
        }

        @Override
        public Object replaceValues(Object obj, Row row) {
            if (!(obj instanceof Row)) return obj;

            return ArrayRow.concat((Row) obj, row);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy