aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/query/Select.java
blob: 32e28dc3ff754e4e68792d13345ad5a31ace0ee0 (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 Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.query;

import com.yahoo.search.Query;
import com.yahoo.search.grouping.GroupingRequest;
import com.yahoo.search.query.parser.ParserEnvironment;
import com.yahoo.search.query.parser.ParserFactory;
import com.yahoo.search.query.profile.types.FieldDescription;
import com.yahoo.search.query.profile.types.QueryProfileType;
import com.yahoo.search.yql.VespaGroupingStep;

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


/**
 * The parameters defining the where-clause and grouping of a query
 *
 * @author henrhoi
 */
public class Select implements Cloneable {

    /** The type representing the property arguments consumed by this */
    private static final QueryProfileType argumentType;

    public static final String SELECT = "select";
    public static final String WHERE = "where";
    public static final String GROUPING = "grouping";

    private final Query parent;
    private final List<GroupingRequest> groupingRequests;

    private String where;
    private String grouping;
    private String groupingExpressionString;

    static {
        argumentType = new QueryProfileType(SELECT);
        argumentType.setStrict(true);
        argumentType.setBuiltin(true);
        argumentType.addField(new FieldDescription(WHERE, "string"));
        argumentType.addField(new FieldDescription(GROUPING, "string"));
        argumentType.freeze();
    }

    public static QueryProfileType getArgumentType() { return argumentType; }

    /** Creates an empty select statement */
    public Select(Query query) {
        this("", "", query);
    }

    public Select(String where, String grouping, Query query) {
        this(where, grouping, null, query, Collections.emptyList());
    }

    private Select(String where, String grouping, String groupingExpressionString, Query query, List<GroupingRequest> groupingRequests) {
        this.where = Objects.requireNonNull(where, "A Select must have a where string (possibly the empty string)");
        this.grouping = Objects.requireNonNull(grouping, "A Select must have a select string (possibly the empty string)");
        this.groupingExpressionString = groupingExpressionString;
        this.parent = Objects.requireNonNull(query, "A Select must have a parent query");
        this.groupingRequests = deepCopy(groupingRequests, this);
    }

    private static List<GroupingRequest> deepCopy(List<GroupingRequest> groupingRequests, Select parentOfCopy) {
        List<GroupingRequest> copy = new ArrayList<>(groupingRequests.size());
        for (GroupingRequest request : groupingRequests)
            copy.add(request.copy(parentOfCopy));
        return copy;
    }

    /**
     * Sets the document selection criterion of the query.
     *
     * @param where the documents to select as a JSON string on the format specified in
     *        <a href="https://docs.vespa.ai/en/reference/select-reference.html">the select reference doc</a>
     */
    public void setWhereString(String where) {
        this.where = where;
        parent.getModel().setType(SELECT);

        // This replaces the current query
        parent.getModel().clearQueryTree();
    }

    /** Returns the where clause string previously assigned, or an empty string if none */
    public String getWhereString() { return where; }

    /**
     * Sets the grouping operation of the query.
     *
     * @param grouping the grouping to perform as a JSON string on the format specified in
     *        <a href="https://docs.vespa.ai/en/reference/select-reference.html">the select reference doc</a>
     */
    public void setGroupingString(String grouping) {
        groupingRequests.clear();
        this.grouping = grouping;
        SelectParser parser = (SelectParser) ParserFactory.newInstance(Query.Type.SELECT, new ParserEnvironment());
        for (VespaGroupingStep step : parser.getGroupingSteps(grouping)) {
            GroupingRequest.newInstance(parent)
                    .setRootOperation(step.getOperation())
                    .continuations().addAll(step.continuations());
        }
    }

    /**
     * Sets the grouping expression string directly.
     * This will not be parsed by this but will be accessed later by GroupingQueryParser.
     */
    public void setGroupingExpressionString(String groupingExpressionString) {
        this.groupingExpressionString = groupingExpressionString;
    }

    public String getGroupingExpressionString() { return groupingExpressionString; }

    /** Returns the grouping in the query */
    public String getGroupingString(){
        return grouping;
    }

    /**
     * Returns the query's {@link GroupingRequest} as a mutable list. Changing this directly changes the grouping
     * operations which will be performed by this query.
     */
    public List<GroupingRequest> getGrouping() { return groupingRequests; }

    @Override
    public String toString() {
        return "where: [" + where + "], grouping: [" + grouping + "]";
    }

    @Override
    public Object clone() {
        return new Select(where, grouping, groupingExpressionString, parent, groupingRequests);
    }

    public Select cloneFor(Query parent)  {
        return new Select(where, grouping, groupingExpressionString, parent, groupingRequests);
    }

}