aboutsummaryrefslogtreecommitdiffstats
path: root/document/src/main/java/com/yahoo/document/FieldPath.java
blob: dfdf60e0791cd560c9bb9730dfdb758c975533d0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.document;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * This class represents a path into a document, that can be used to iterate through the document and extract the field
 * values you're interested in.
 *
 * @author Thomas Gundersen
 */
public class FieldPath implements Iterable<FieldPathEntry> {

    private final List<FieldPathEntry> list;
    /**
     * Constructs an empty path.
     */
    public FieldPath() {
        list = Collections.emptyList();
    }

    /**
     * Constructs a path containing the entries of the specified path, in the order they are returned by that path's
     * iterator.
     *
     * @param path The path whose entries are to be placed into this path.
     * @throws NullPointerException If the specified path is null.
     */
    public FieldPath(FieldPath path) {
        this(path.list);
    }

    public FieldPath(List<FieldPathEntry> path) {
        list = Collections.unmodifiableList(path);
    }

    public int size() { return list.size(); }
    public FieldPathEntry get(int index) { return list.get(index); }
    public boolean isEmpty() { return list.isEmpty(); }
    public Iterator<FieldPathEntry> iterator() { return list.iterator(); }
    public List<FieldPathEntry> getList() { return list; }

    /**
     * Compares this field path with the given field path, returns true if the field path starts with the other.
     *
     * @param other The field path to compare with.
     * @return Returns true if this field path starts with the other field path, otherwise false
     */
    public boolean startsWith(FieldPath other) {
        if (other.size() > size()) {
            return false;
        }

        for (int i = 0; i < other.size(); i++) {
            if (!other.get(i).equals(get(i))) {
                return false;
            }
        }

        return true;
    }

    /**
     * @return Returns the datatype we can expect this field path to return.
     */
    public DataType getResultingDataType() {
        if (isEmpty()) {
            return null;
        }

        return get(size() - 1).getResultingDataType();
    }

    /**
     * Convenience method to build a field path from a path string. This is a simple proxy for {@link
     * DataType#buildFieldPath(String)}.
     *
     * @param fieldType The data type of the value to build a path for.
     * @param fieldPath The path string to parse.
     * @return The corresponding field path object.
     */
    public static FieldPath newInstance(DataType fieldType, String fieldPath) {
        return fieldType.buildFieldPath(fieldPath);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        FieldPath that = (FieldPath) o;

        return list.equals(that.list);
    }

    @Override
    public int hashCode() {
        return list.hashCode();
    }

    @Override
    public String toString() {
        StringBuilder out = new StringBuilder();
        DataType prevType = null;
        for (FieldPathEntry entry : this) {
            FieldPathEntry.Type type = entry.getType();
            switch (type) {
            case STRUCT_FIELD:
                if (out.length() > 0) {
                    out.append(".");
                }
                Field field = entry.getFieldRef();
                out.append(field.getName());
                prevType = field.getDataType();
                break;
            case ARRAY_INDEX:
                out.append("[").append(entry.getLookupIndex()).append("]");
                break;
            case MAP_KEY:
                out.append("{").append(entry.getLookupKey()).append("}");
                break;
            case MAP_ALL_KEYS:
                out.append(".key");
                break;
            case MAP_ALL_VALUES:
                out.append(".value");
                break;
            case VARIABLE:
                if (prevType instanceof ArrayDataType) {
                    out.append("[$").append(entry.getVariableName()).append("]");
                } else if (prevType instanceof WeightedSetDataType || prevType instanceof MapDataType) {
                    out.append("{$").append(entry.getVariableName()).append("}");
                } else {
                    out.append("$").append(entry.getVariableName());
                }
            }
        }
        return out.toString();
    }
}