Skip to content

Commit fe9f92d

Browse files
committed
Updated ViewMetadata with view name inside View, and structured as list
Changes the structure to look like: { "views": [ { "name": "view1", "query": "FROM …" }, { "name": "otherview", "query": "FROM …" } ] }
1 parent a77ad01 commit fe9f92d

File tree

13 files changed

+182
-123
lines changed

13 files changed

+182
-123
lines changed

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/view/ClusterViewService.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
import org.elasticsearch.core.SuppressForbidden;
2424
import org.elasticsearch.xpack.esql.plugin.EsqlFeatures;
2525

26+
import java.util.List;
2627
import java.util.Locale;
27-
import java.util.Map;
2828
import java.util.function.Function;
2929

3030
/**
@@ -66,7 +66,7 @@ protected void updateViewMetadata(
6666
ProjectId projectId,
6767
AcknowledgedRequest<?> request,
6868
ActionListener<? extends AcknowledgedResponse> callback,
69-
Function<ViewMetadata, Map<String, View>> function
69+
Function<ViewMetadata, List<View>> function
7070
) {
7171
ViewMetadataUpdateTask updateTask = new ViewMetadataUpdateTask(request, callback, projectId, function);
7272
String taskName = String.format(Locale.ROOT, "update-esql-view-metadata-[%s]", verb.toLowerCase(Locale.ROOT));
@@ -90,13 +90,13 @@ protected boolean viewsFeatureEnabled() {
9090

9191
class ViewMetadataUpdateTask extends AckedClusterStateUpdateTask {
9292
private final ProjectId projectId;
93-
private final Function<ViewMetadata, Map<String, View>> updateFunction;
93+
private final Function<ViewMetadata, List<View>> updateFunction;
9494

9595
ViewMetadataUpdateTask(
9696
AcknowledgedRequest<?> request,
9797
ActionListener<? extends AcknowledgedResponse> listener,
9898
ProjectId projectId,
99-
Function<ViewMetadata, Map<String, View>> updateFunction
99+
Function<ViewMetadata, List<View>> updateFunction
100100
) {
101101
super(request, listener);
102102
this.projectId = projectId;
@@ -107,7 +107,7 @@ class ViewMetadataUpdateTask extends AckedClusterStateUpdateTask {
107107
public ClusterState execute(ClusterState currentState) {
108108
var project = currentState.metadata().getProject(projectId);
109109
var views = project.custom(ViewMetadata.TYPE, ViewMetadata.EMPTY);
110-
Map<String, View> policies = updateFunction.apply(views);
110+
List<View> policies = updateFunction.apply(views);
111111
var metadata = ProjectMetadata.builder(project).putCustom(ViewMetadata.TYPE, new ViewMetadata(policies));
112112
return ClusterState.builder(currentState).putProjectMetadata(metadata).build();
113113
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/view/PutViewAction.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,24 @@ private PutViewAction() {
2626
}
2727

2828
public static class Request extends AcknowledgedRequest<Request> {
29-
private final String name;
3029
private final View view;
3130

32-
public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, String name, View view) {
31+
public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, View view) {
3332
super(masterNodeTimeout, ackTimeout);
34-
this.name = Objects.requireNonNull(name, "name cannot be null");
3533
this.view = view;
3634
}
3735

3836
public Request(StreamInput in) throws IOException {
3937
super(in);
40-
name = in.readString();
4138
view = new View(in);
4239
}
4340

4441
@Override
4542
public void writeTo(StreamOutput out) throws IOException {
4643
super.writeTo(out);
47-
out.writeString(name);
4844
view.writeTo(out);
4945
}
5046

51-
public String name() {
52-
return name;
53-
}
54-
5547
public View view() {
5648
return view;
5749
}
@@ -61,12 +53,12 @@ public boolean equals(Object o) {
6153
if (this == o) return true;
6254
if (o == null || getClass() != o.getClass()) return false;
6355
Request request = (Request) o;
64-
return name.equals(request.name) && view.equals(request.view);
56+
return view.equals(request.view);
6557
}
6658

6759
@Override
6860
public int hashCode() {
69-
return Objects.hash(name, view);
61+
return Objects.hash(view);
7062
}
7163
}
7264
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/view/RestPutViewAction.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
3939
PutViewAction.Request req = new PutViewAction.Request(
4040
RestUtils.getMasterNodeTimeout(request),
4141
RestUtils.getAckTimeout(request),
42-
request.param("name"),
43-
View.PARSER.parse(parser, null)
42+
View.parser(request.param("name")).parse(parser, null)
4443
);
4544
return channel -> client.execute(PutViewAction.INSTANCE, req, new RestToXContentListener<>(channel));
4645
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/view/TransportGetViewAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ protected void localClusterStateOperation(
6464
List<String> missing = new ArrayList<>();
6565
Collection<String> names = request.names();
6666
if (names.isEmpty()) {
67-
names = Collections.unmodifiableSet(viewService.list(projectId));
67+
names = Collections.unmodifiableList(viewService.list(projectId));
6868
}
6969
for (String name : names) {
7070
View view = viewService.get(projectId, name);

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/view/View.java

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,42 @@
2323
* Represents a single view definition, which is simply a name and a query string.
2424
*/
2525
public final class View implements Writeable, ToXContentFragment {
26+
private static final ParseField NAME = new ParseField("name");
2627
private static final ParseField QUERY = new ParseField("query");
2728

29+
// Parser that includes the name field (eg. serializing/deserializing the full object)
2830
static final ConstructingObjectParser<View, Void> PARSER = new ConstructingObjectParser<>(
2931
"view",
3032
false,
31-
(args, ctx) -> new View((String) args[0])
33+
(args, ctx) -> new View((String) args[0], (String) args[1])
3234
);
3335

3436
static {
37+
PARSER.declareString(ConstructingObjectParser.constructorArg(), NAME);
3538
PARSER.declareString(ConstructingObjectParser.constructorArg(), QUERY);
3639
}
3740

41+
// Parser that excludes the name field (eg. when the name is provided externally, in the URL path)
42+
static ConstructingObjectParser<View, Void> parser(String name) {
43+
ConstructingObjectParser<View, Void> parser = new ConstructingObjectParser<>(
44+
"view",
45+
false,
46+
(args, ctx) -> new View(name, (String) args[0])
47+
);
48+
parser.declareString(ConstructingObjectParser.constructorArg(), QUERY);
49+
return parser;
50+
}
51+
52+
private final String name;
3853
private final String query;
3954

40-
public View(String query) {
55+
public View(String name, String query) {
56+
this.name = name;
4157
this.query = query;
4258
}
4359

4460
public View(StreamInput in) throws IOException {
61+
this.name = in.readString();
4562
this.query = in.readString();
4663
}
4764

@@ -51,15 +68,21 @@ public static View fromXContent(XContentParser parser) throws IOException {
5168

5269
@Override
5370
public void writeTo(StreamOutput out) throws IOException {
71+
out.writeString(name);
5472
out.writeString(query);
5573
}
5674

75+
public String name() {
76+
return name;
77+
}
78+
5779
public String query() {
5880
return query;
5981
}
6082

6183
@Override
6284
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
85+
builder.field(NAME.getPreferredName(), name);
6386
builder.field(QUERY.getPreferredName(), query);
6487
return builder;
6588
}
@@ -69,12 +92,12 @@ public boolean equals(Object o) {
6992
if (this == o) return true;
7093
if (o == null || getClass() != o.getClass()) return false;
7194
View other = (View) o;
72-
return Objects.equals(query, other.query);
95+
return Objects.equals(name, other.name) && Objects.equals(query, other.query);
7396
}
7497

7598
@Override
7699
public int hashCode() {
77-
return Objects.hash(query);
100+
return Objects.hash(name, query);
78101
}
79102

80103
public String toString() {

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/view/ViewMetadata.java

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,70 +14,83 @@
1414
import org.elasticsearch.common.io.stream.StreamInput;
1515
import org.elasticsearch.common.io.stream.StreamOutput;
1616
import org.elasticsearch.common.xcontent.ChunkedToXContentHelper;
17-
import org.elasticsearch.xcontent.ConstructingObjectParser;
17+
import org.elasticsearch.xcontent.ObjectParser;
1818
import org.elasticsearch.xcontent.ParseField;
1919
import org.elasticsearch.xcontent.ToXContent;
2020
import org.elasticsearch.xcontent.XContentParser;
2121

2222
import java.io.IOException;
23+
import java.util.ArrayList;
2324
import java.util.Collections;
2425
import java.util.EnumSet;
25-
import java.util.HashMap;
2626
import java.util.Iterator;
2727
import java.util.List;
28-
import java.util.Map;
2928
import java.util.Objects;
3029

30+
import static org.elasticsearch.common.io.stream.StreamOutput.GENERIC_LIST_HEADER;
31+
3132
/**
3233
* Encapsulates view definitions as custom metadata inside ProjectMetadata within cluster state.
3334
*/
3435
public final class ViewMetadata extends AbstractNamedDiffable<Metadata.ProjectCustom> implements Metadata.ProjectCustom {
3536
public static final String TYPE = "esql_view";
3637
public static final List<NamedWriteableRegistry.Entry> ENTRIES = List.of(
37-
new NamedWriteableRegistry.Entry(Metadata.ProjectCustom.class, TYPE, ViewMetadata::new),
38+
new NamedWriteableRegistry.Entry(Metadata.ProjectCustom.class, TYPE, ViewMetadata::readFromStream),
3839
new NamedWriteableRegistry.Entry(NamedDiff.class, TYPE, in -> ViewMetadata.readDiffFrom(Metadata.ProjectCustom.class, TYPE, in))
3940
);
4041
private static final TransportVersion ESQL_VIEWS = TransportVersion.fromName("esql_views");
4142

4243
static final ParseField VIEWS = new ParseField("views");
4344

44-
public static final ViewMetadata EMPTY = new ViewMetadata(Collections.emptyMap());
45+
public static final ViewMetadata EMPTY = new ViewMetadata(Collections.emptyList());
4546

4647
@SuppressWarnings("unchecked")
47-
private static final ConstructingObjectParser<ViewMetadata, Void> PARSER = new ConstructingObjectParser<>(
48-
"view_metadata",
49-
args -> new ViewMetadata((Map<String, View>) args[0])
50-
);
48+
private static final ObjectParser<ViewMetadata, Void> PARSER = new ObjectParser<>("view_metadata", ViewMetadata::new);
5149

5250
static {
53-
PARSER.declareObject(ConstructingObjectParser.constructorArg(), (p, c) -> {
54-
Map<String, View> patterns = new HashMap<>();
55-
while (p.nextToken() != XContentParser.Token.END_OBJECT) {
56-
String name = p.currentName();
57-
patterns.put(name, View.fromXContent(p));
58-
}
59-
return patterns;
60-
}, VIEWS);
51+
PARSER.declareObjectArrayOrNull((viewMetadata, views) -> views.forEach(viewMetadata::add), (p, c) -> View.fromXContent(p), VIEWS);
6152
}
6253

6354
public static ViewMetadata fromXContent(XContentParser parser) throws IOException {
6455
return PARSER.parse(parser, null);
6556
}
6657

67-
private final Map<String, View> views;
58+
private final ArrayList<View> views;
59+
60+
public static ViewMetadata readFromStream(StreamInput in) throws IOException {
61+
assert in.readByte() == GENERIC_LIST_HEADER;
62+
int count = in.readVInt();
63+
ArrayList<View> views = new ArrayList<>(count);
64+
for (int i = 0; i < count; i++) {
65+
views.add(new View(in));
66+
}
67+
return new ViewMetadata(views);
68+
}
69+
70+
public ViewMetadata() {
71+
this(List.of());
72+
}
6873

69-
public ViewMetadata(StreamInput in) throws IOException {
70-
this(in.readMap(View::new));
74+
public ViewMetadata(List<View> views) {
75+
this.views = new ArrayList<>(views);
7176
}
7277

73-
public ViewMetadata(Map<String, View> views) {
74-
this.views = Collections.unmodifiableMap(views);
78+
public void add(View view) {
79+
views.add(view);
7580
}
7681

77-
public Map<String, View> views() {
82+
public List<View> views() {
7883
return views;
7984
}
8085

86+
public List<String> viewNames() {
87+
return views.stream().map(View::name).toList();
88+
}
89+
90+
public View getView(String name) {
91+
return views.stream().filter(v -> v.name().equals(name)).findAny().orElse(null);
92+
}
93+
8194
@Override
8295
public EnumSet<Metadata.XContentContext> context() {
8396
return Metadata.ALL_CONTEXTS;
@@ -95,12 +108,32 @@ public String getWriteableName() {
95108

96109
@Override
97110
public void writeTo(StreamOutput out) throws IOException {
98-
out.writeMap(views, StreamOutput::writeWriteable);
111+
out.writeGenericList(views, StreamOutput::writeWriteable);
99112
}
100113

101114
@Override
102115
public Iterator<? extends ToXContent> toXContentChunked(ToXContent.Params ignored) {
103-
return ChunkedToXContentHelper.xContentObjectFieldObjects(VIEWS.getPreferredName(), views);
116+
return ChunkedToXContentHelper.array(VIEWS.getPreferredName(), new ViewIterator());
117+
}
118+
119+
private class ViewIterator implements Iterator<ToXContent> {
120+
private final Iterator<View> internal = views.iterator();
121+
122+
@Override
123+
public boolean hasNext() {
124+
return internal.hasNext();
125+
}
126+
127+
@Override
128+
public ToXContent next() {
129+
View view = internal.next();
130+
return (builder, params) -> {
131+
builder.startObject();
132+
view.toXContent(builder, params);
133+
builder.endObject();
134+
return builder;
135+
};
136+
}
104137
}
105138

106139
@Override

0 commit comments

Comments
 (0)