google_cloud_spanner/admin/database/
database_admin_client.rs

1use google_cloud_gax::conn::Channel;
2use google_cloud_gax::create_request;
3use google_cloud_gax::grpc::{Response, Status};
4use google_cloud_gax::retry::{invoke, MapErr, RetrySetting};
5use google_cloud_googleapis::iam::v1::{
6    GetIamPolicyRequest, Policy, SetIamPolicyRequest, TestIamPermissionsRequest, TestIamPermissionsResponse,
7};
8use google_cloud_googleapis::longrunning::Operation as InternalOperation;
9use google_cloud_googleapis::spanner::admin::database::v1::database_admin_client::DatabaseAdminClient as InternalDatabaseAdminClient;
10use google_cloud_googleapis::spanner::admin::database::v1::{
11    Backup, CreateBackupRequest, CreateDatabaseRequest, Database, DeleteBackupRequest, DropDatabaseRequest,
12    GetBackupRequest, GetDatabaseDdlRequest, GetDatabaseDdlResponse, GetDatabaseRequest, ListBackupOperationsRequest,
13    ListBackupsRequest, ListDatabaseOperationsRequest, ListDatabasesRequest, RestoreDatabaseRequest,
14    UpdateBackupRequest, UpdateDatabaseDdlRequest,
15};
16use google_cloud_longrunning::autogen::operations_client::OperationsClient;
17use google_cloud_longrunning::longrunning::Operation;
18
19use crate::admin::default_retry_setting;
20
21#[derive(Clone)]
22pub struct DatabaseAdminClient {
23    inner: InternalDatabaseAdminClient<Channel>,
24    lro_client: OperationsClient,
25}
26
27impl DatabaseAdminClient {
28    pub fn new(channel: Channel, lro_client: OperationsClient) -> Self {
29        Self {
30            inner: InternalDatabaseAdminClient::new(channel).max_decoding_message_size(i32::MAX as usize),
31            lro_client,
32        }
33    }
34
35    /// list_databases lists Cloud Spanner databases.
36    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
37    pub async fn list_databases(
38        &self,
39        mut req: ListDatabasesRequest,
40        retry: Option<RetrySetting>,
41    ) -> Result<Vec<Database>, Status> {
42        let retry = Some(retry.unwrap_or_else(default_retry_setting));
43        let parent = &req.parent;
44        let mut all_databases = vec![];
45        //eager loading
46        loop {
47            let action = || async {
48                let request = create_request(format!("parent={parent}"), req.clone());
49                self.inner
50                    .clone()
51                    .list_databases(request)
52                    .await
53                    .map(|d| d.into_inner())
54                    .map_transient_err()
55            };
56            let response = invoke(retry.clone(), action).await?;
57            all_databases.extend(response.databases.into_iter());
58            if response.next_page_token.is_empty() {
59                return Ok(all_databases);
60            }
61            req.page_token = response.next_page_token;
62        }
63    }
64
65    /// create_database creates a new Cloud Spanner database and starts to prepare it for serving.
66    /// The returned [long-running operation][google.longrunning.Operation] will
67    /// have a name of the format <database_name>/operations/<operation_id> and
68    /// can be used to track preparation of the database. The metadata field type is CreateDatabaseMetadata.
69    /// The response field type is Database, if successful.
70    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
71    pub async fn create_database(
72        &self,
73        req: CreateDatabaseRequest,
74        retry: Option<RetrySetting>,
75    ) -> Result<Operation<Database>, Status> {
76        let retry = Some(retry.unwrap_or_else(default_retry_setting));
77        let parent = &req.parent;
78        let action = || async {
79            let request = create_request(format!("parent={parent}"), req.clone());
80            self.inner.clone().create_database(request).await.map_transient_err()
81        };
82        invoke(retry, action)
83            .await
84            .map(|d| Operation::new(self.lro_client.clone(), d.into_inner()))
85    }
86
87    /// get_database gets the state of a Cloud Spanner database.
88    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
89    pub async fn get_database(
90        &self,
91        req: GetDatabaseRequest,
92        retry: Option<RetrySetting>,
93    ) -> Result<Response<Database>, Status> {
94        let retry = Some(retry.unwrap_or_else(default_retry_setting));
95        let name = &req.name;
96        let action = || async {
97            let request = create_request(format!("name={name}"), req.clone());
98            self.inner.clone().get_database(request).await.map_transient_err()
99        };
100        invoke(retry, action).await
101    }
102
103    /// update_database_ddl updates the schema of a Cloud Spanner database by
104    /// creating/altering/dropping tables, columns, indexes, etc. The returned
105    /// [long-running operation][google.longrunning.Operation] will have a name of
106    /// the format <database_name>/operations/<operation_id> and can be used to
107    /// track execution of the schema change(s). The
108    /// metadata field type is
109    /// UpdateDatabaseDdlMetadata.
110    /// The operation has no response.
111    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
112    pub async fn update_database_ddl(
113        &self,
114        req: UpdateDatabaseDdlRequest,
115        retry: Option<RetrySetting>,
116    ) -> Result<Operation<()>, Status> {
117        let retry = Some(retry.unwrap_or_else(default_retry_setting));
118        let database = &req.database;
119        let action = || async {
120            let request = create_request(format!("database={database}"), req.clone());
121            self.inner
122                .clone()
123                .update_database_ddl(request)
124                .await
125                .map_transient_err()
126        };
127        invoke(retry, action)
128            .await
129            .map(|d| Operation::new(self.lro_client.clone(), d.into_inner()))
130    }
131
132    /// drop_database drops (aka deletes) a Cloud Spanner database.
133    /// Completed backups for the database will be retained according to their
134    /// expire_time.
135    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
136    pub async fn drop_database(
137        &self,
138        req: DropDatabaseRequest,
139        retry: Option<RetrySetting>,
140    ) -> Result<Response<()>, Status> {
141        let retry = Some(retry.unwrap_or_else(default_retry_setting));
142        let database = &req.database;
143        let action = || async {
144            let request = create_request(format!("database={database}"), req.clone());
145            self.inner.clone().drop_database(request).await.map_transient_err()
146        };
147        invoke(retry, action).await
148    }
149
150    /// get_database_ddl returns the schema of a Cloud Spanner database as a list of formatted
151    /// DDL statements. This method does not show pending schema updates, those may
152    /// be queried using the Operations API.
153    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
154    pub async fn get_database_ddl(
155        &self,
156        req: GetDatabaseDdlRequest,
157        retry: Option<RetrySetting>,
158    ) -> Result<Response<GetDatabaseDdlResponse>, Status> {
159        let retry = Some(retry.unwrap_or_else(default_retry_setting));
160        let database = &req.database;
161        let action = || async {
162            let request = create_request(format!("database={database}"), req.clone());
163            self.inner.clone().get_database_ddl(request).await.map_transient_err()
164        };
165        invoke(retry, action).await
166    }
167
168    /// set_iam_policy sets the access control policy on a database or backup resource.
169    /// Replaces any existing policy.
170    ///
171    /// Authorization requires spanner.databases.setIamPolicy
172    /// permission on resource.
173    /// For backups, authorization requires spanner.backups.setIamPolicy
174    /// permission on resource.
175    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
176    pub async fn set_iam_policy(
177        &self,
178        req: SetIamPolicyRequest,
179        retry: Option<RetrySetting>,
180    ) -> Result<Response<Policy>, Status> {
181        let retry = Some(retry.unwrap_or_else(default_retry_setting));
182        let resource = &req.resource;
183        let action = || async {
184            let request = create_request(format!("resource={resource}"), req.clone());
185            self.inner.clone().set_iam_policy(request).await.map_transient_err()
186        };
187        invoke(retry, action).await
188    }
189
190    /// get_iam_policy gets the access control policy for a database or backup resource.
191    /// Returns an empty policy if a database or backup exists but does not have a
192    /// policy set.
193    ///
194    /// Authorization requires spanner.databases.getIamPolicy permission on
195    /// resource.
196    /// For backups, authorization requires spanner.backups.getIamPolicy
197    /// permission on resource.
198    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
199    pub async fn get_iam_policy(
200        &self,
201        req: GetIamPolicyRequest,
202        retry: Option<RetrySetting>,
203    ) -> Result<Response<Policy>, Status> {
204        let retry = Some(retry.unwrap_or_else(default_retry_setting));
205        let resource = &req.resource;
206        let action = || async {
207            let request = create_request(format!("resource={resource}"), req.clone());
208            self.inner.clone().get_iam_policy(request).await.map_transient_err()
209        };
210        invoke(retry, action).await
211    }
212
213    /// test_iam_permissions returns permissions that the caller has on the specified database or backup
214    /// resource.
215    ///
216    /// Attempting this RPC on a non-existent Cloud Spanner database will
217    /// result in a NOT_FOUND error if the user has
218    /// spanner.databases.list permission on the containing Cloud
219    /// Spanner instance. Otherwise returns an empty set of permissions.
220    /// Calling this method on a backup that does not exist will
221    /// result in a NOT_FOUND error if the user has
222    /// spanner.backups.list permission on the containing instance
223    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
224    pub async fn test_iam_permissions(
225        &self,
226        req: TestIamPermissionsRequest,
227        retry: Option<RetrySetting>,
228    ) -> Result<Response<TestIamPermissionsResponse>, Status> {
229        let retry = Some(retry.unwrap_or_else(default_retry_setting));
230        let resource = &req.resource;
231        let action = || async {
232            let request = create_request(format!("resource={resource}"), req.clone());
233            self.inner
234                .clone()
235                .test_iam_permissions(request)
236                .await
237                .map_transient_err()
238        };
239        invoke(retry, action).await
240    }
241
242    /// create_backup starts creating a new Cloud Spanner Backup.
243    /// The returned backup [long-running operation][google.longrunning.Operation]
244    /// will have a name of the format
245    /// projects/<project>/instances/<instance>/backups/<backup>/operations/<operation_id>
246    /// and can be used to track creation of the backup. The
247    /// metadata field type is
248    /// CreateBackupMetadata.
249    /// The response field type is
250    /// Backup, if successful.
251    /// Cancelling the returned operation will stop the creation and delete the
252    /// backup. There can be only one pending backup creation per database. Backup
253    /// creation of different databases can run concurrently.
254    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
255    pub async fn create_backup(
256        &self,
257        req: CreateBackupRequest,
258        retry: Option<RetrySetting>,
259    ) -> Result<Operation<Backup>, Status> {
260        let retry = Some(retry.unwrap_or_else(default_retry_setting));
261        let parent = &req.parent;
262        let action = || async {
263            let request = create_request(format!("parent={parent}"), req.clone());
264            self.inner.clone().create_backup(request).await.map_transient_err()
265        };
266        invoke(retry, action)
267            .await
268            .map(|d| Operation::new(self.lro_client.clone(), d.into_inner()))
269    }
270
271    /// get_backup gets metadata on a pending or completed Backup.
272    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
273    pub async fn get_backup(
274        &self,
275        req: GetBackupRequest,
276        retry: Option<RetrySetting>,
277    ) -> Result<Response<Backup>, Status> {
278        let retry = Some(retry.unwrap_or_else(default_retry_setting));
279        let name = &req.name;
280        let action = || async {
281            let request = create_request(format!("name={name}"), req.clone());
282            self.inner.clone().get_backup(request).await.map_transient_err()
283        };
284        invoke(retry, action).await
285    }
286
287    /// update_backup updates a pending or completed Backup.
288    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
289    pub async fn update_backup(
290        &self,
291        req: UpdateBackupRequest,
292        retry: Option<RetrySetting>,
293    ) -> Result<Response<Backup>, Status> {
294        let retry = Some(retry.unwrap_or_else(default_retry_setting));
295        let name = &req.backup.as_ref().unwrap().name;
296        let action = || async {
297            let request = create_request(format!("backup.name={name}"), req.clone());
298            self.inner.clone().update_backup(request).await.map_transient_err()
299        };
300        invoke(retry, action).await
301    }
302
303    /// delete_backup deletes a pending or completed Backup.
304    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
305    pub async fn delete_backup(
306        &self,
307        req: DeleteBackupRequest,
308        retry: Option<RetrySetting>,
309    ) -> Result<Response<()>, Status> {
310        let retry = Some(retry.unwrap_or_else(default_retry_setting));
311        let name = &req.name;
312        let action = || async {
313            let request = create_request(format!("name={name}"), req.clone());
314            self.inner.clone().delete_backup(request).await.map_transient_err()
315        };
316        invoke(retry, action).await
317    }
318
319    /// list_backups lists completed and pending backups.
320    /// Backups returned are ordered by create_time in descending order,
321    /// starting from the most recent create_time.
322    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
323    pub async fn list_backups(
324        &self,
325        mut req: ListBackupsRequest,
326        retry: Option<RetrySetting>,
327    ) -> Result<Vec<Backup>, Status> {
328        let retry = Some(retry.unwrap_or_else(default_retry_setting));
329        let parent = &req.parent;
330        let mut all_backups = vec![];
331        //eager loading
332        loop {
333            let action = || async {
334                let request = create_request(format!("parent={parent}"), req.clone());
335                self.inner
336                    .clone()
337                    .list_backups(request)
338                    .await
339                    .map(|d| d.into_inner())
340                    .map_transient_err()
341            };
342            let response = invoke(retry.clone(), action).await?;
343            all_backups.extend(response.backups.into_iter());
344            if response.next_page_token.is_empty() {
345                return Ok(all_backups);
346            }
347            req.page_token = response.next_page_token;
348        }
349    }
350
351    /// restore_database create a new database by restoring from a completed backup. The new
352    /// database must be in the same project and in an instance with the same
353    /// instance configuration as the instance containing
354    /// the backup. The returned database [long-running
355    /// operation][google.longrunning.Operation] has a name of the format
356    /// projects/<project>/instances/<instance>/databases/<database>/operations/<operation_id>,
357    /// and can be used to track the progress of the operation, and to cancel it.
358    /// The metadata field type is
359    /// RestoreDatabaseMetadata.
360    /// The response type
361    /// is Database, if
362    /// successful. Cancelling the returned operation will stop the restore and
363    /// delete the database.
364    /// There can be only one database being restored into an instance at a time.
365    /// Once the restore operation completes, a new restore operation can be
366    /// initiated, without waiting for the optimize operation associated with the
367    /// first restore to complete.
368    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
369    pub async fn restore_database(
370        &self,
371        req: RestoreDatabaseRequest,
372        retry: Option<RetrySetting>,
373    ) -> Result<Operation<Database>, Status> {
374        let retry = Some(retry.unwrap_or_else(default_retry_setting));
375        let parent = &req.parent;
376        let action = || async {
377            let request = create_request(format!("parent={parent}"), req.clone());
378            self.inner.clone().restore_database(request).await.map_transient_err()
379        };
380        invoke(retry, action)
381            .await
382            .map(|d| Operation::new(self.lro_client.clone(), d.into_inner()))
383    }
384
385    /// list_backup_operations lists the backup [long-running operations][google.longrunning.Operation] in
386    /// the given instance. A backup operation has a name of the form
387    /// projects/<project>/instances/<instance>/backups/<backup>/operations/<operation>.
388    /// The long-running operation
389    /// metadata field type
390    /// metadata.type_url describes the type of the metadata. Operations returned
391    /// include those that have completed/failed/canceled within the last 7 days,
392    /// and pending operations. Operations returned are ordered by
393    /// operation.metadata.value.progress.start_time in descending order starting
394    /// from the most recently started operation.
395    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
396    pub async fn list_backup_operations(
397        &self,
398        mut req: ListBackupOperationsRequest,
399        retry: Option<RetrySetting>,
400    ) -> Result<Vec<InternalOperation>, Status> {
401        let retry = Some(retry.unwrap_or_else(default_retry_setting));
402        let parent = &req.parent;
403        let mut all_operations = vec![];
404        //eager loading
405        loop {
406            let action = || async {
407                let request = create_request(format!("parent={parent}"), req.clone());
408                self.inner
409                    .clone()
410                    .list_backup_operations(request)
411                    .await
412                    .map(|d| d.into_inner())
413                    .map_transient_err()
414            };
415            let response = invoke(retry.clone(), action).await?;
416            all_operations.extend(response.operations.into_iter());
417            if response.next_page_token.is_empty() {
418                return Ok(all_operations);
419            }
420            req.page_token = response.next_page_token;
421        }
422    }
423
424    /// list_database_operations lists database [longrunning-operations][google.longrunning.Operation].
425    /// A database operation has a name of the form
426    /// projects/<project>/instances/<instance>/databases/<database>/operations/<operation>.
427    /// The long-running operation
428    /// metadata field type
429    /// metadata.type_url describes the type of the metadata. Operations returned
430    /// include those that have completed/failed/canceled within the last 7 days,
431    /// and pending operations.
432    #[cfg_attr(feature = "trace", tracing::instrument(skip_all))]
433    pub async fn list_database_operations(
434        &self,
435        mut req: ListDatabaseOperationsRequest,
436        retry: Option<RetrySetting>,
437    ) -> Result<Vec<InternalOperation>, Status> {
438        let retry = Some(retry.unwrap_or_else(default_retry_setting));
439        let parent = &req.parent;
440        let mut all_operations = vec![];
441        //eager loading
442        loop {
443            let action = || async {
444                let request = create_request(format!("parent={parent}"), req.clone());
445                self.inner
446                    .clone()
447                    .list_database_operations(request)
448                    .await
449                    .map(|d| d.into_inner())
450                    .map_transient_err()
451            };
452            let response = invoke(retry.clone(), action).await?;
453            all_operations.extend(response.operations.into_iter());
454            if response.next_page_token.is_empty() {
455                return Ok(all_operations);
456            }
457            req.page_token = response.next_page_token;
458        }
459    }
460}