Skip to content

Commit 55cd719

Browse files
authored
feat(bigtable): Add support for Materialized Views in Admin API (#2511)
Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly: - [x] Make sure to open an issue as a [bug/issue](https://togithub.com/googleapis/java-bigtable/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [x] Ensure the tests and linter pass - [x] Code coverage does not decrease (if any source code was changed) - [x] Appropriate docs were updated (if necessary) - [x] Rollback plan is reviewed and LGTMed - [x] All new data plane features have a completed end to end testing plan Fixes #<issue_number_goes_here> ☕️ If you write sample code, please follow the [samples format]( https://togithub.com/GoogleCloudPlatform/java-docs-samples/blob/main/SAMPLE_FORMAT.md).
1 parent 966f46d commit 55cd719

12 files changed

+1175
-0
lines changed

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClient.java

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,33 @@
2222
import com.google.api.gax.rpc.ApiExceptions;
2323
import com.google.api.gax.rpc.NotFoundException;
2424
import com.google.bigtable.admin.v2.DeleteAppProfileRequest;
25+
import com.google.bigtable.admin.v2.DeleteMaterializedViewRequest;
2526
import com.google.bigtable.admin.v2.GetAppProfileRequest;
27+
import com.google.bigtable.admin.v2.GetMaterializedViewRequest;
2628
import com.google.bigtable.admin.v2.ListAppProfilesRequest;
29+
import com.google.bigtable.admin.v2.ListMaterializedViewsRequest;
2730
import com.google.bigtable.admin.v2.PartialUpdateClusterRequest;
2831
import com.google.cloud.Policy;
2932
import com.google.cloud.Policy.DefaultMarshaller;
3033
import com.google.cloud.bigtable.admin.v2.BaseBigtableInstanceAdminClient.ListAppProfilesPage;
3134
import com.google.cloud.bigtable.admin.v2.BaseBigtableInstanceAdminClient.ListAppProfilesPagedResponse;
35+
import com.google.cloud.bigtable.admin.v2.BaseBigtableInstanceAdminClient.ListMaterializedViewsPage;
36+
import com.google.cloud.bigtable.admin.v2.BaseBigtableInstanceAdminClient.ListMaterializedViewsPagedResponse;
3237
import com.google.cloud.bigtable.admin.v2.internal.NameUtil;
3338
import com.google.cloud.bigtable.admin.v2.models.AppProfile;
3439
import com.google.cloud.bigtable.admin.v2.models.Cluster;
3540
import com.google.cloud.bigtable.admin.v2.models.ClusterAutoscalingConfig;
3641
import com.google.cloud.bigtable.admin.v2.models.CreateAppProfileRequest;
3742
import com.google.cloud.bigtable.admin.v2.models.CreateClusterRequest;
3843
import com.google.cloud.bigtable.admin.v2.models.CreateInstanceRequest;
44+
import com.google.cloud.bigtable.admin.v2.models.CreateMaterializedViewRequest;
3945
import com.google.cloud.bigtable.admin.v2.models.Instance;
46+
import com.google.cloud.bigtable.admin.v2.models.MaterializedView;
4047
import com.google.cloud.bigtable.admin.v2.models.PartialListClustersException;
4148
import com.google.cloud.bigtable.admin.v2.models.PartialListInstancesException;
4249
import com.google.cloud.bigtable.admin.v2.models.UpdateAppProfileRequest;
4350
import com.google.cloud.bigtable.admin.v2.models.UpdateInstanceRequest;
51+
import com.google.cloud.bigtable.admin.v2.models.UpdateMaterializedViewRequest;
4452
import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStub;
4553
import com.google.common.base.Verify;
4654
import com.google.common.collect.ImmutableList;
@@ -1392,6 +1400,304 @@ public List<String> apply(TestIamPermissionsResponse input) {
13921400
MoreExecutors.directExecutor());
13931401
}
13941402

1403+
/**
1404+
* Creates a new materialized view.
1405+
*
1406+
* <p>Sample code:
1407+
*
1408+
* <pre>{@code
1409+
* MaterializedView materializedView = client.createMaterializedView(
1410+
* CreateMaterializedViewRequest.of("my-instance", "my-new-materialized-view")
1411+
* .setQuery(query)
1412+
* );
1413+
* }</pre>
1414+
*
1415+
* @see CreateMaterializedViewRequest
1416+
*/
1417+
@SuppressWarnings("WeakerAccess")
1418+
public MaterializedView createMaterializedView(CreateMaterializedViewRequest request) {
1419+
return ApiExceptions.callAndTranslateApiException(createMaterializedViewAsync(request));
1420+
}
1421+
1422+
/**
1423+
* Asynchronously creates a new materialized view.
1424+
*
1425+
* <p>Sample code:
1426+
*
1427+
* <pre>{@code
1428+
* ApiFuture<MaterializedView> materializedViewFuture = client.createMaterializedViewAsync(
1429+
* CreateMaterializedViewRequest.of("my-instance", "my-new-materialized-view")
1430+
* .setQuery(query)
1431+
* );
1432+
*
1433+
* MaterializedView materializedView = materializedViewFuture.get();
1434+
* }</pre>
1435+
*
1436+
* @see CreateMaterializedViewRequest
1437+
*/
1438+
@SuppressWarnings("WeakerAccess")
1439+
public ApiFuture<MaterializedView> createMaterializedViewAsync(
1440+
CreateMaterializedViewRequest request) {
1441+
return ApiFutures.transform(
1442+
stub.createMaterializedViewOperationCallable().futureCall(request.toProto(projectId)),
1443+
new ApiFunction<com.google.bigtable.admin.v2.MaterializedView, MaterializedView>() {
1444+
@Override
1445+
public MaterializedView apply(com.google.bigtable.admin.v2.MaterializedView proto) {
1446+
return MaterializedView.fromProto(proto);
1447+
}
1448+
},
1449+
MoreExecutors.directExecutor());
1450+
}
1451+
1452+
/**
1453+
* Gets the materialized view by ID.
1454+
*
1455+
* <p>Sample code:
1456+
*
1457+
* <pre>{@code
1458+
* MaterializedView materializedView = client.getMaterializedView("my-instance", "my-materialized-view");
1459+
* }</pre>
1460+
*
1461+
* @see MaterializedView
1462+
*/
1463+
public MaterializedView getMaterializedView(String instanceId, String materializedViewId) {
1464+
return ApiExceptions.callAndTranslateApiException(
1465+
getMaterializedViewAsync(instanceId, materializedViewId));
1466+
}
1467+
1468+
/**
1469+
* Asynchronously gets the materialized view by ID.
1470+
*
1471+
* <p>Sample code:
1472+
*
1473+
* <pre>{@code
1474+
* ApiFuture<MaterializedView> materializedViewFuture = client.getMaterializedViewAsync("my-instance", "my-materialized-view");
1475+
*
1476+
* MaterializedView materializedView = materializedViewFuture.get();
1477+
* }</pre>
1478+
*
1479+
* @see MaterializedView
1480+
*/
1481+
@SuppressWarnings("WeakerAccess")
1482+
public ApiFuture<MaterializedView> getMaterializedViewAsync(
1483+
String instanceId, String materializedViewId) {
1484+
String name = NameUtil.formatMaterializedViewName(projectId, instanceId, materializedViewId);
1485+
1486+
GetMaterializedViewRequest request =
1487+
GetMaterializedViewRequest.newBuilder().setName(name).build();
1488+
1489+
return ApiFutures.transform(
1490+
stub.getMaterializedViewCallable().futureCall(request),
1491+
new ApiFunction<com.google.bigtable.admin.v2.MaterializedView, MaterializedView>() {
1492+
@Override
1493+
public MaterializedView apply(com.google.bigtable.admin.v2.MaterializedView proto) {
1494+
return MaterializedView.fromProto(proto);
1495+
}
1496+
},
1497+
MoreExecutors.directExecutor());
1498+
}
1499+
1500+
/**
1501+
* Lists all materialized views of the specified instance.
1502+
*
1503+
* <p>Sample code:
1504+
*
1505+
* <pre>{@code
1506+
* List<MaterializedView> materializedViews = client.listMaterializedViews("my-instance");
1507+
* }</pre>
1508+
*
1509+
* @see MaterializedView
1510+
*/
1511+
@SuppressWarnings("WeakerAccess")
1512+
public List<MaterializedView> listMaterializedViews(String instanceId) {
1513+
return ApiExceptions.callAndTranslateApiException(listMaterializedViewsAsync(instanceId));
1514+
}
1515+
1516+
/**
1517+
* Asynchronously lists all materialized views of the specified instance.
1518+
*
1519+
* <p>Sample code:
1520+
*
1521+
* <pre>{@code
1522+
* ApiFuture<List<MaterializedView>> materializedViewsFuture = client.listMaterializedViewsAsync("my-instance");
1523+
*
1524+
* List<MaterializedView> materializedViews = materializedViewFuture.get();
1525+
* }</pre>
1526+
*
1527+
* @see MaterializedView
1528+
*/
1529+
@SuppressWarnings("WeakerAccess")
1530+
public ApiFuture<List<MaterializedView>> listMaterializedViewsAsync(String instanceId) {
1531+
String instanceName = NameUtil.formatInstanceName(projectId, instanceId);
1532+
1533+
ListMaterializedViewsRequest request =
1534+
ListMaterializedViewsRequest.newBuilder().setParent(instanceName).build();
1535+
1536+
// TODO(igorbernstein2): try to upstream pagination spooling or figure out a way to expose the
1537+
// paginated responses while maintaining the wrapper facade.
1538+
1539+
// Fetches the first page.
1540+
ApiFuture<ListMaterializedViewsPage> firstPageFuture =
1541+
ApiFutures.transform(
1542+
stub.listMaterializedViewsPagedCallable().futureCall(request),
1543+
new ApiFunction<ListMaterializedViewsPagedResponse, ListMaterializedViewsPage>() {
1544+
@Override
1545+
public ListMaterializedViewsPage apply(ListMaterializedViewsPagedResponse response) {
1546+
return response.getPage();
1547+
}
1548+
},
1549+
MoreExecutors.directExecutor());
1550+
1551+
// Fetches the rest of the pages by chaining the futures.
1552+
ApiFuture<List<com.google.bigtable.admin.v2.MaterializedView>> allProtos =
1553+
ApiFutures.transformAsync(
1554+
firstPageFuture,
1555+
new ApiAsyncFunction<
1556+
ListMaterializedViewsPage, List<com.google.bigtable.admin.v2.MaterializedView>>() {
1557+
List<com.google.bigtable.admin.v2.MaterializedView> responseAccumulator =
1558+
Lists.newArrayList();
1559+
1560+
@Override
1561+
public ApiFuture<List<com.google.bigtable.admin.v2.MaterializedView>> apply(
1562+
ListMaterializedViewsPage page) {
1563+
// Add all entries from the page
1564+
responseAccumulator.addAll(Lists.newArrayList(page.getValues()));
1565+
1566+
// If this is the last page, just return the accumulated responses.
1567+
if (!page.hasNextPage()) {
1568+
return ApiFutures.immediateFuture(responseAccumulator);
1569+
}
1570+
1571+
// Otherwise fetch the next page.
1572+
return ApiFutures.transformAsync(
1573+
page.getNextPageAsync(), this, MoreExecutors.directExecutor());
1574+
}
1575+
},
1576+
MoreExecutors.directExecutor());
1577+
1578+
// Wraps all of the accumulated protos.
1579+
return ApiFutures.transform(
1580+
allProtos,
1581+
new ApiFunction<
1582+
List<com.google.bigtable.admin.v2.MaterializedView>, List<MaterializedView>>() {
1583+
@Override
1584+
public List<MaterializedView> apply(
1585+
List<com.google.bigtable.admin.v2.MaterializedView> input) {
1586+
List<MaterializedView> results = Lists.newArrayListWithCapacity(input.size());
1587+
for (com.google.bigtable.admin.v2.MaterializedView materializedView : input) {
1588+
results.add(MaterializedView.fromProto(materializedView));
1589+
}
1590+
return results;
1591+
}
1592+
},
1593+
MoreExecutors.directExecutor());
1594+
}
1595+
1596+
/**
1597+
* Updates an existing materialized view.
1598+
*
1599+
* <p>Sample code:
1600+
*
1601+
* <pre>{@code
1602+
* MaterializedView existingMaterializedView = client.getMaterializedView("my-instance", "my-materialized-view");
1603+
*
1604+
* MaterializedView updatedMaterializedView = client.updateMaterializedView(
1605+
* UpdateMaterializedViewRequest.of(existingMaterializedView)
1606+
* .setDeletionProtection(false)
1607+
* );
1608+
* }</pre>
1609+
*
1610+
* @see UpdateMaterializedViewRequest
1611+
*/
1612+
@SuppressWarnings("WeakerAccess")
1613+
public MaterializedView updateMaterializedView(UpdateMaterializedViewRequest request) {
1614+
return ApiExceptions.callAndTranslateApiException(updateMaterializedViewAsync(request));
1615+
}
1616+
1617+
/**
1618+
* Asynchronously updates an existing materialized view.
1619+
*
1620+
* <p>Sample code:
1621+
*
1622+
* <pre>{@code
1623+
* ApiFuture<MaterializedView> existingMaterializedViewFuture = client.getMaterializedViewAsync("my-instance", "my-materialized-view");
1624+
*
1625+
* ApiFuture<MaterializedView> updatedMaterializedViewFuture = ApiFutures.transformAsync(
1626+
* existingMaterializedViewFuture,
1627+
* new ApiAsyncFunction<MaterializedView, MaterializedView>() {
1628+
* public ApiFuture<MaterializedView> apply(MaterializedView existingMaterializedView) {
1629+
* return client.updateMaterializedViewAsync(
1630+
* UpdateMaterializedViewRequest.of(existingMaterializedView)
1631+
* .setDeletionProtection(false)
1632+
* );
1633+
* }
1634+
* },
1635+
* MoreExecutors.directExecutor()
1636+
* );
1637+
*
1638+
* ApiFuture<MaterializedView> materializedView = updatedMaterializedViewFuture.get();
1639+
* }</pre>
1640+
*
1641+
* @see UpdateMaterializedViewRequest
1642+
*/
1643+
@SuppressWarnings("WeakerAccess")
1644+
public ApiFuture<MaterializedView> updateMaterializedViewAsync(
1645+
UpdateMaterializedViewRequest request) {
1646+
return ApiFutures.transform(
1647+
stub.updateMaterializedViewOperationCallable().futureCall(request.toProto(projectId)),
1648+
new ApiFunction<com.google.bigtable.admin.v2.MaterializedView, MaterializedView>() {
1649+
@Override
1650+
public MaterializedView apply(com.google.bigtable.admin.v2.MaterializedView proto) {
1651+
return MaterializedView.fromProto(proto);
1652+
}
1653+
},
1654+
MoreExecutors.directExecutor());
1655+
}
1656+
1657+
/**
1658+
* Deletes the specified materialized view.
1659+
*
1660+
* <p>Sample code:
1661+
*
1662+
* <pre>{@code
1663+
* client.deleteMaterializedView("my-instance", "my-materialized-view");
1664+
* }</pre>
1665+
*/
1666+
@SuppressWarnings("WeakerAccess")
1667+
public void deleteMaterializedView(String instanceId, String materializedViewId) {
1668+
ApiExceptions.callAndTranslateApiException(
1669+
deleteMaterializedViewAsync(instanceId, materializedViewId));
1670+
}
1671+
1672+
/**
1673+
* Asynchronously deletes the specified materialized view.
1674+
*
1675+
* <p>Sample code:
1676+
*
1677+
* <pre>{@code
1678+
* ApiFuture<Void> deleteFuture = client.deleteMaterializedViewAsync("my-instance", "my-materialized-view");
1679+
*
1680+
* deleteFuture.get();
1681+
* }</pre>
1682+
*/
1683+
@SuppressWarnings("WeakerAccess")
1684+
public ApiFuture<Void> deleteMaterializedViewAsync(String instanceId, String materializedViewId) {
1685+
1686+
String name = NameUtil.formatMaterializedViewName(projectId, instanceId, materializedViewId);
1687+
DeleteMaterializedViewRequest request =
1688+
DeleteMaterializedViewRequest.newBuilder().setName(name).build();
1689+
1690+
return ApiFutures.transform(
1691+
stub.deleteMaterializedViewCallable().futureCall(request),
1692+
new ApiFunction<Empty, Void>() {
1693+
@Override
1694+
public Void apply(Empty input) {
1695+
return null;
1696+
}
1697+
},
1698+
MoreExecutors.directExecutor());
1699+
}
1700+
13951701
/**
13961702
* Simple adapter to expose {@link DefaultMarshaller} to this class. It enables this client to
13971703
* convert to/from IAM wrappers and protobufs.

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminSettings.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ public String toString() {
113113
.add("getIamPolicySettings", stubSettings.getIamPolicySettings())
114114
.add("setIamPolicySettings", stubSettings.setIamPolicySettings())
115115
.add("testIamPermissionsSettings", stubSettings.testIamPermissionsSettings())
116+
.add("createMaterializedViewSettings", stubSettings.createMaterializedViewSettings())
117+
.add("getMaterializedViewSettings", stubSettings.getMaterializedViewSettings())
118+
.add("listMaterializedViewsSettings", stubSettings.listMaterializedViewsSettings())
119+
.add("updateMaterializedViewSettings", stubSettings.updateMaterializedViewSettings())
120+
.add("deleteMaterializedViewSettings", stubSettings.deleteMaterializedViewSettings())
116121
.add("stubSettings", stubSettings)
117122
.toString();
118123
}

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/internal/NameUtil.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.google.api.core.InternalApi;
1919
import java.util.regex.Matcher;
2020
import java.util.regex.Pattern;
21+
import javax.annotation.Nonnull;
2122

2223
/**
2324
* Internal helper to compose full resource names.
@@ -49,6 +50,11 @@ public static String formatTableName(String projectId, String instanceId, String
4950
return formatInstanceName(projectId, instanceId) + "/tables/" + tableId;
5051
}
5152

53+
public static String formatMaterializedViewName(
54+
@Nonnull String projectId, @Nonnull String instanceId, @Nonnull String materializedViewId) {
55+
return formatInstanceName(projectId, instanceId) + "/materializedViews/" + materializedViewId;
56+
}
57+
5258
public static String formatLocationName(String projectId, String zone) {
5359
return formatProjectName(projectId) + "/locations/" + zone;
5460
}

0 commit comments

Comments
 (0)