Skip to content

Commit c4c8980

Browse files
authored
[core] Support view API in Rest catalog (apache#4908)
1 parent 1a5915d commit c4c8980

File tree

18 files changed

+1072
-162
lines changed

18 files changed

+1072
-162
lines changed

paimon-common/src/main/java/org/apache/paimon/types/RowType.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import org.apache.paimon.utils.Preconditions;
2525
import org.apache.paimon.utils.StringUtils;
2626

27+
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonCreator;
28+
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonProperty;
2729
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.core.JsonGenerator;
2830

2931
import java.io.IOException;
@@ -52,6 +54,8 @@ public final class RowType extends DataType {
5254

5355
private static final long serialVersionUID = 1L;
5456

57+
private static final String FIELD_FIELDS = "fields";
58+
5559
public static final String FORMAT = "ROW<%s>";
5660

5761
private final List<DataField> fields;
@@ -67,7 +71,8 @@ public RowType(boolean isNullable, List<DataField> fields) {
6771
validateFields(fields);
6872
}
6973

70-
public RowType(List<DataField> fields) {
74+
@JsonCreator
75+
public RowType(@JsonProperty(FIELD_FIELDS) List<DataField> fields) {
7176
this(true, fields);
7277
}
7378

paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java

+93-15
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.apache.paimon.rest.requests.CreateDatabaseRequest;
4646
import org.apache.paimon.rest.requests.CreatePartitionsRequest;
4747
import org.apache.paimon.rest.requests.CreateTableRequest;
48+
import org.apache.paimon.rest.requests.CreateViewRequest;
4849
import org.apache.paimon.rest.requests.DropPartitionsRequest;
4950
import org.apache.paimon.rest.requests.MarkDonePartitionsRequest;
5051
import org.apache.paimon.rest.requests.RenameTableRequest;
@@ -55,16 +56,22 @@
5556
import org.apache.paimon.rest.responses.ErrorResponseResourceType;
5657
import org.apache.paimon.rest.responses.GetDatabaseResponse;
5758
import org.apache.paimon.rest.responses.GetTableResponse;
59+
import org.apache.paimon.rest.responses.GetViewResponse;
5860
import org.apache.paimon.rest.responses.ListDatabasesResponse;
5961
import org.apache.paimon.rest.responses.ListPartitionsResponse;
6062
import org.apache.paimon.rest.responses.ListTablesResponse;
63+
import org.apache.paimon.rest.responses.ListViewsResponse;
6164
import org.apache.paimon.schema.Schema;
6265
import org.apache.paimon.schema.SchemaChange;
6366
import org.apache.paimon.schema.TableSchema;
6467
import org.apache.paimon.table.FileStoreTable;
6568
import org.apache.paimon.table.Table;
6669
import org.apache.paimon.table.sink.BatchWriteBuilder;
70+
import org.apache.paimon.types.RowType;
6771
import org.apache.paimon.utils.Pair;
72+
import org.apache.paimon.view.View;
73+
import org.apache.paimon.view.ViewImpl;
74+
import org.apache.paimon.view.ViewSchema;
6875

6976
import org.apache.paimon.shade.guava30.com.google.common.collect.ImmutableList;
7077

@@ -290,8 +297,7 @@ public boolean commitSnapshot(Identifier identifier, Snapshot snapshot) {
290297
CommitTableRequest request = new CommitTableRequest(identifier, snapshot);
291298
CommitTableResponse response =
292299
client.post(
293-
resourcePaths.commitTable(
294-
identifier.getDatabaseName(), identifier.getTableName()),
300+
resourcePaths.commitTable(identifier.getDatabaseName()),
295301
request,
296302
CommitTableResponse.class,
297303
headers());
@@ -325,11 +331,7 @@ public void createTable(Identifier identifier, Schema schema, boolean ignoreIfEx
325331
checkNotSystemTable(identifier, "createTable");
326332
validateAutoCreateClose(schema.options());
327333
CreateTableRequest request = new CreateTableRequest(identifier, schema);
328-
client.post(
329-
resourcePaths.tables(identifier.getDatabaseName()),
330-
request,
331-
GetTableResponse.class,
332-
headers());
334+
client.post(resourcePaths.tables(identifier.getDatabaseName()), request, headers());
333335
} catch (AlreadyExistsException e) {
334336
if (!ignoreIfExists) {
335337
throw new TableAlreadyExistException(identifier);
@@ -353,13 +355,8 @@ public void renameTable(Identifier fromTable, Identifier toTable, boolean ignore
353355
checkNotSystemTable(fromTable, "renameTable");
354356
checkNotSystemTable(toTable, "renameTable");
355357
try {
356-
RenameTableRequest request = new RenameTableRequest(toTable);
357-
client.post(
358-
resourcePaths.renameTable(
359-
fromTable.getDatabaseName(), fromTable.getTableName()),
360-
request,
361-
GetTableResponse.class,
362-
headers());
358+
RenameTableRequest request = new RenameTableRequest(fromTable, toTable);
359+
client.post(resourcePaths.renameTable(fromTable.getDatabaseName()), request, headers());
363360
} catch (NoSuchResourceException e) {
364361
if (!ignoreIfNotExists) {
365362
throw new TableNotExistException(fromTable);
@@ -381,7 +378,6 @@ public void alterTable(
381378
client.post(
382379
resourcePaths.table(identifier.getDatabaseName(), identifier.getTableName()),
383380
request,
384-
GetTableResponse.class,
385381
headers());
386382
} catch (NoSuchResourceException e) {
387383
if (!ignoreIfNotExists) {
@@ -532,6 +528,88 @@ public List<Partition> listPartitions(Identifier identifier) throws TableNotExis
532528
return response.getPartitions();
533529
}
534530

531+
@Override
532+
public View getView(Identifier identifier) throws ViewNotExistException {
533+
try {
534+
GetViewResponse response =
535+
client.get(
536+
resourcePaths.view(
537+
identifier.getDatabaseName(), identifier.getTableName()),
538+
GetViewResponse.class,
539+
headers());
540+
return new ViewImpl(
541+
identifier,
542+
response.getSchema().rowType(),
543+
response.getSchema().query(),
544+
response.getSchema().comment(),
545+
response.getSchema().options());
546+
} catch (NoSuchResourceException e) {
547+
throw new ViewNotExistException(identifier);
548+
}
549+
}
550+
551+
@Override
552+
public void dropView(Identifier identifier, boolean ignoreIfNotExists)
553+
throws ViewNotExistException {
554+
try {
555+
client.delete(
556+
resourcePaths.view(identifier.getDatabaseName(), identifier.getTableName()),
557+
headers());
558+
} catch (NoSuchResourceException e) {
559+
if (!ignoreIfNotExists) {
560+
throw new ViewNotExistException(identifier);
561+
}
562+
}
563+
}
564+
565+
@Override
566+
public void createView(Identifier identifier, View view, boolean ignoreIfExists)
567+
throws ViewAlreadyExistException, DatabaseNotExistException {
568+
try {
569+
ViewSchema schema =
570+
new ViewSchema(
571+
new RowType(view.rowType().getFields()),
572+
view.options(),
573+
view.comment().orElse(null),
574+
view.query());
575+
CreateViewRequest request = new CreateViewRequest(identifier, schema);
576+
client.post(resourcePaths.views(identifier.getDatabaseName()), request, headers());
577+
} catch (NoSuchResourceException e) {
578+
throw new DatabaseNotExistException(identifier.getDatabaseName());
579+
} catch (AlreadyExistsException e) {
580+
if (!ignoreIfExists) {
581+
throw new ViewAlreadyExistException(identifier);
582+
}
583+
}
584+
}
585+
586+
@Override
587+
public List<String> listViews(String databaseName) throws DatabaseNotExistException {
588+
try {
589+
ListViewsResponse response =
590+
client.get(
591+
resourcePaths.views(databaseName), ListViewsResponse.class, headers());
592+
return response.getViews();
593+
} catch (NoSuchResourceException e) {
594+
throw new DatabaseNotExistException(databaseName);
595+
}
596+
}
597+
598+
@Override
599+
public void renameView(Identifier fromView, Identifier toView, boolean ignoreIfNotExists)
600+
throws ViewNotExistException, ViewAlreadyExistException {
601+
try {
602+
RenameTableRequest request = new RenameTableRequest(fromView, toView);
603+
client.post(resourcePaths.renameView(fromView.getDatabaseName()), request, headers());
604+
} catch (NoSuchResourceException e) {
605+
if (!ignoreIfNotExists) {
606+
throw new ViewNotExistException(fromView);
607+
}
608+
} catch (AlreadyExistsException e) {
609+
throw new ViewAlreadyExistException(toView);
610+
}
611+
}
612+
535613
@Override
536614
public boolean caseSensitive() {
537615
return options.getOptional(CASE_SENSITIVE).orElse(true);

paimon-core/src/main/java/org/apache/paimon/rest/ResourcePaths.java

+16-4
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ public String table(String databaseName, String tableName) {
6262
return SLASH.join(V1, prefix, DATABASES, databaseName, TABLES, tableName);
6363
}
6464

65-
public String renameTable(String databaseName, String tableName) {
66-
return SLASH.join(V1, prefix, DATABASES, databaseName, TABLES, tableName, "rename");
65+
public String renameTable(String databaseName) {
66+
return SLASH.join(V1, prefix, DATABASES, databaseName, TABLES, "rename");
6767
}
6868

69-
public String commitTable(String databaseName, String tableName) {
70-
return SLASH.join(V1, prefix, DATABASES, databaseName, TABLES, tableName, "commit");
69+
public String commitTable(String databaseName) {
70+
return SLASH.join(V1, prefix, DATABASES, databaseName, TABLES, "commit");
7171
}
7272

7373
public String partitions(String databaseName, String tableName) {
@@ -88,4 +88,16 @@ public String markDonePartitions(String databaseName, String tableName) {
8888
return SLASH.join(
8989
V1, prefix, DATABASES, databaseName, TABLES, tableName, "partitions", "mark");
9090
}
91+
92+
public String views(String databaseName) {
93+
return SLASH.join(V1, prefix, DATABASES, databaseName, "views");
94+
}
95+
96+
public String view(String databaseName, String viewName) {
97+
return SLASH.join(V1, prefix, DATABASES, databaseName, "views", viewName);
98+
}
99+
100+
public String renameView(String databaseName) {
101+
return SLASH.join(V1, prefix, DATABASES, databaseName, "views", "rename");
102+
}
91103
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.paimon.rest.requests;
20+
21+
import org.apache.paimon.catalog.Identifier;
22+
import org.apache.paimon.rest.RESTRequest;
23+
import org.apache.paimon.view.ViewSchema;
24+
25+
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonCreator;
26+
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonGetter;
27+
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
28+
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonProperty;
29+
30+
/** Request for creating view. */
31+
@JsonIgnoreProperties(ignoreUnknown = true)
32+
public class CreateViewRequest implements RESTRequest {
33+
34+
private static final String FIELD_IDENTIFIER = "identifier";
35+
private static final String FIELD_SCHEMA = "schema";
36+
37+
@JsonProperty(FIELD_IDENTIFIER)
38+
private final Identifier identifier;
39+
40+
@JsonProperty(FIELD_SCHEMA)
41+
private final ViewSchema schema;
42+
43+
@JsonCreator
44+
public CreateViewRequest(
45+
@JsonProperty(FIELD_IDENTIFIER) Identifier identifier,
46+
@JsonProperty(FIELD_SCHEMA) ViewSchema schema) {
47+
this.schema = schema;
48+
this.identifier = identifier;
49+
}
50+
51+
@JsonGetter(FIELD_IDENTIFIER)
52+
public Identifier getIdentifier() {
53+
return identifier;
54+
}
55+
56+
@JsonGetter(FIELD_SCHEMA)
57+
public ViewSchema getSchema() {
58+
return schema;
59+
}
60+
}

paimon-core/src/main/java/org/apache/paimon/rest/requests/RenameTableRequest.java

+21-9
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,34 @@
2626
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
2727
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonProperty;
2828

29-
/** Request for renaming table. */
29+
/** Request for renaming. */
3030
@JsonIgnoreProperties(ignoreUnknown = true)
3131
public class RenameTableRequest implements RESTRequest {
3232

33-
private static final String FIELD_NEW_IDENTIFIER_NAME = "newIdentifier";
33+
private static final String FIELD_SOURCE = "source";
34+
private static final String FIELD_DESTINATION = "destination";
3435

35-
@JsonProperty(FIELD_NEW_IDENTIFIER_NAME)
36-
private final Identifier newIdentifier;
36+
@JsonProperty(FIELD_SOURCE)
37+
private final Identifier source;
38+
39+
@JsonProperty(FIELD_DESTINATION)
40+
private final Identifier destination;
3741

3842
@JsonCreator
39-
public RenameTableRequest(@JsonProperty(FIELD_NEW_IDENTIFIER_NAME) Identifier newIdentifier) {
40-
this.newIdentifier = newIdentifier;
43+
public RenameTableRequest(
44+
@JsonProperty(FIELD_SOURCE) Identifier source,
45+
@JsonProperty(FIELD_DESTINATION) Identifier destination) {
46+
this.source = source;
47+
this.destination = destination;
48+
}
49+
50+
@JsonGetter(FIELD_DESTINATION)
51+
public Identifier getDestination() {
52+
return destination;
4153
}
4254

43-
@JsonGetter(FIELD_NEW_IDENTIFIER_NAME)
44-
public Identifier getNewIdentifier() {
45-
return newIdentifier;
55+
@JsonGetter(FIELD_SOURCE)
56+
public Identifier getSource() {
57+
return source;
4658
}
4759
}

paimon-core/src/main/java/org/apache/paimon/rest/responses/ErrorResponseResourceType.java

+1
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ public enum ErrorResponseResourceType {
2323
DATABASE,
2424
TABLE,
2525
COLUMN,
26+
VIEW
2627
}

0 commit comments

Comments
 (0)