Skip to content

Commit 366437b

Browse files
committed
Core: Add view support
Co-authored-by: anjalinorwood@gmail.com
1 parent 667aaaf commit 366437b

28 files changed

+2675
-0
lines changed

core/src/main/java/org/apache/iceberg/util/JsonUtil.java

+71
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.List;
3030
import java.util.Map;
3131
import java.util.Set;
32+
import java.util.function.Function;
3233
import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
3334
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
3435
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap;
@@ -182,6 +183,62 @@ public static void writeLongFieldIf(boolean condition, String key, Long value, J
182183
}
183184
}
184185

186+
@FunctionalInterface
187+
public interface JsonWriter<T> {
188+
void write(T object, JsonGenerator generator) throws IOException;
189+
}
190+
191+
public static <T> void writeObjectList(
192+
String property,
193+
Iterable<T> objectList,
194+
JsonWriter<T> writer,
195+
JsonGenerator generator)
196+
throws IOException {
197+
generator.writeArrayFieldStart(property);
198+
for (T object : objectList) {
199+
writer.write(object, generator);
200+
}
201+
generator.writeEndArray();
202+
}
203+
204+
public static void writeStringList(String property, List<String> stringList, JsonGenerator generator)
205+
throws IOException {
206+
generator.writeArrayFieldStart(property);
207+
for (String s : stringList) {
208+
generator.writeString(s);
209+
}
210+
generator.writeEndArray();
211+
}
212+
213+
public static void writeStringMap(String property, Map<String, String> map, JsonGenerator generator)
214+
throws IOException {
215+
generator.writeObjectFieldStart(property);
216+
for (Map.Entry<String, String> entry : map.entrySet()) {
217+
generator.writeStringField(entry.getKey(), entry.getValue());
218+
}
219+
generator.writeEndObject();
220+
}
221+
222+
@FunctionalInterface
223+
public interface JsonReader<T> {
224+
T read(JsonNode node);
225+
}
226+
227+
public static <T> T getObject(String property, JsonNode node, JsonReader<T> reader) {
228+
Preconditions.checkArgument(node.has(property), "Cannot parse missing object %s", property);
229+
JsonNode pNode = node.get(property);
230+
Preconditions.checkArgument(pNode.isObject(),
231+
"Cannot parse %s from non-object value: %s", property, pNode);
232+
return reader.read(pNode);
233+
}
234+
235+
public static <T> List<T> getObjectList(String property, JsonNode node, Function<JsonNode, T> reader) {
236+
Preconditions.checkArgument(node.has(property), "Cannot parse missing list %s", property);
237+
return ImmutableList.<T>builder()
238+
.addAll(objectArrayIterator(property, node, reader))
239+
.build();
240+
}
241+
185242
abstract static class JsonArrayIterator<T> implements Iterator<T> {
186243

187244
private final Iterator<JsonNode> elements;
@@ -243,4 +300,18 @@ void validate(JsonNode element) {
243300
Preconditions.checkArgument(element.isInt(), "Cannot parse integer from non-int value: %s", element);
244301
}
245302
}
303+
304+
static <T> Iterator<T> objectArrayIterator(String property, JsonNode node, Function<JsonNode, T> reader) {
305+
return new JsonArrayIterator<T>(property, node) {
306+
protected T convert(JsonNode element) {
307+
return reader.apply(element);
308+
}
309+
310+
protected void validate(JsonNode element) {
311+
Preconditions.checkArgument(
312+
element.isObject(),
313+
"Cannot parse %s from non-object value: %s", property, element);
314+
}
315+
};
316+
}
246317
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.iceberg.view;
21+
22+
import java.util.List;
23+
import java.util.Map;
24+
25+
/**
26+
* Base {@link View} implementation.
27+
* <p>
28+
* This can be extended by providing a {@link ViewOperations} to the constructor.
29+
*/
30+
public class BaseView implements View, HasViewOperations {
31+
private final ViewOperations ops;
32+
private final String name;
33+
34+
public BaseView(ViewOperations ops, String name) {
35+
this.ops = ops;
36+
this.name = name;
37+
}
38+
39+
@Override
40+
public String name() {
41+
return name;
42+
}
43+
44+
@Override
45+
public ViewOperations operations() {
46+
return ops;
47+
}
48+
49+
@Override
50+
public ViewVersion currentVersion() {
51+
return ops.current().currentVersion();
52+
}
53+
54+
@Override
55+
public ViewVersion version(int versionId) {
56+
return ops.current().version(versionId);
57+
}
58+
59+
@Override
60+
public Iterable<ViewVersion> versions() {
61+
return ops.current().versions();
62+
}
63+
64+
@Override
65+
public List<ViewHistoryEntry> history() {
66+
return ops.current().history();
67+
}
68+
69+
@Override
70+
public ViewUpdateProperties updateProperties() {
71+
return new ViewPropertiesUpdate(ops);
72+
}
73+
74+
@Override
75+
public Map<String, String> properties() {
76+
return ops.current().properties();
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.iceberg.view;
21+
22+
import java.util.Collections;
23+
import java.util.List;
24+
import java.util.Objects;
25+
import org.apache.iceberg.Schema;
26+
import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
27+
28+
/**
29+
* SQL definition for a view
30+
*/
31+
class BaseViewDefinition implements ViewDefinition {
32+
private final String sql;
33+
private final String dialect;
34+
private final Schema schema;
35+
private final String defaultCatalog;
36+
private final List<String> defaultNamespace;
37+
private final List<String> fieldAliases;
38+
private final List<String> fieldComments;
39+
40+
public static Builder builder() {
41+
return new Builder();
42+
}
43+
44+
public static Builder buildFrom(ViewDefinition that) {
45+
return builder()
46+
.sql(that.sql())
47+
.dialect(that.dialect())
48+
.schema(that.schema())
49+
.defaultCatalog(that.defaultCatalog())
50+
.defaultNamespace(that.defaultNamespace())
51+
.fieldAliases(that.fieldAliases())
52+
.fieldComments(that.fieldComments());
53+
}
54+
55+
private BaseViewDefinition(
56+
String sql, String dialect, Schema schema, String defaultCatalog, List<String> defaultNamespace,
57+
List<String> fieldAliases, List<String> fieldComments) {
58+
this.sql = Preconditions.checkNotNull(sql, "sql should not be null");
59+
this.dialect = Preconditions.checkNotNull(dialect, "dialect should not be null");
60+
this.schema = schema;
61+
this.defaultCatalog = Preconditions.checkNotNull(defaultCatalog, "default catalog should not null");
62+
this.defaultNamespace = Preconditions.checkNotNull(defaultNamespace, "default namespace should not be null");
63+
this.fieldAliases = Preconditions.checkNotNull(fieldAliases, "field aliases should not be null");
64+
this.fieldComments = Preconditions.checkNotNull(fieldComments, "field comments should not be null");
65+
}
66+
67+
@Override
68+
public String sql() {
69+
return sql;
70+
}
71+
72+
@Override
73+
public String dialect() {
74+
return dialect;
75+
}
76+
77+
@Override
78+
public Schema schema() {
79+
return schema;
80+
}
81+
82+
@Override
83+
public String defaultCatalog() {
84+
return defaultCatalog;
85+
}
86+
87+
@Override
88+
public List<String> defaultNamespace() {
89+
return defaultNamespace;
90+
}
91+
92+
@Override
93+
public List<String> fieldAliases() {
94+
return fieldAliases;
95+
}
96+
97+
@Override
98+
public List<String> fieldComments() {
99+
return fieldComments;
100+
}
101+
102+
@Override
103+
public boolean equals(Object o) {
104+
if (this == o) {
105+
return true;
106+
}
107+
if (o == null || getClass() != o.getClass()) {
108+
return false;
109+
}
110+
BaseViewDefinition that = (BaseViewDefinition) o;
111+
return Objects.equals(sql, that.sql) &&
112+
Objects.equals(dialect, that.dialect) &&
113+
Objects.equals(schema.asStruct(), that.schema.asStruct()) &&
114+
Objects.equals(defaultCatalog, that.defaultCatalog) &&
115+
Objects.equals(defaultNamespace, that.defaultNamespace) &&
116+
Objects.equals(fieldAliases, that.fieldAliases) &&
117+
Objects.equals(fieldComments, that.fieldComments);
118+
}
119+
120+
@Override
121+
public int hashCode() {
122+
return Objects.hash(sql, dialect, schema.asStruct(), defaultCatalog, defaultNamespace, fieldAliases, fieldComments);
123+
}
124+
125+
@Override
126+
public String toString() {
127+
return "BaseViewDefinition{" +
128+
"sql='" + sql + '\'' +
129+
", dialect=" + dialect +
130+
", schema=" + schema +
131+
", defaultCatalog='" + defaultCatalog + '\'' +
132+
", defaultNamespace=" + defaultNamespace +
133+
", fieldAliases=" + fieldAliases +
134+
", fieldComments=" + fieldComments +
135+
'}';
136+
}
137+
138+
public static final class Builder {
139+
140+
private String sql;
141+
private String dialect = "";
142+
private Schema schema = new Schema();
143+
private String defaultCatalog = "";
144+
private List<String> defaultNamespace = Collections.emptyList();
145+
private List<String> fieldAliases = Collections.emptyList();
146+
private List<String> fieldComments = Collections.emptyList();
147+
148+
private Builder() {
149+
}
150+
151+
public Builder sql(String value) {
152+
sql = value;
153+
return this;
154+
}
155+
156+
public Builder dialect(String value) {
157+
dialect = value;
158+
return this;
159+
}
160+
161+
public Builder schema(Schema value) {
162+
schema = value;
163+
return this;
164+
}
165+
166+
public Builder defaultCatalog(String value) {
167+
defaultCatalog = value;
168+
return this;
169+
}
170+
171+
public Builder defaultNamespace(List<String> value) {
172+
defaultNamespace = value;
173+
return this;
174+
}
175+
176+
public Builder fieldAliases(List<String> value) {
177+
fieldAliases = value;
178+
return this;
179+
}
180+
181+
public Builder fieldComments(List<String> value) {
182+
fieldComments = value;
183+
return this;
184+
}
185+
186+
public BaseViewDefinition build() {
187+
return new BaseViewDefinition(
188+
sql,
189+
dialect,
190+
schema,
191+
defaultCatalog,
192+
defaultNamespace,
193+
fieldAliases,
194+
fieldComments);
195+
}
196+
}
197+
}

0 commit comments

Comments
 (0)