1 5
/**
2 5
 * Copyright 2020 Google LLC
3 5
 * Licensed under the Apache License, Version 2.0 (the "License");
4 5
 * you may not use this file except in compliance with the License.
5 5
 * You may obtain a copy of the License at
6 5
 *
7 5
 *    http://www.apache.org/licenses/LICENSE-2.0
8 5
 *
9 5
 * Unless required by applicable law or agreed to in writing, software
10 5
 * distributed under the License is distributed on an "AS IS" BASIS,
11 5
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 5
 * See the License for the specific language governing permissions and
13 5
 * limitations under the License.
14 5
 */
15 5

16 5
import {promisifyAll, callbackifyAll} from '@google-cloud/promisify';
17 5
import {Instance} from './instance';
18 5
import {
19 5
  IOperation,
20 5
  LongRunningCallback,
21 5
  RequestCallback,
22 5
  ResourceCallback,
23 5
  NormalCallback,
24 5
  CLOUD_RESOURCE_HEADER,
25 5
} from './common';
26 5
import {EnumKey, Spanner, RequestConfig, TranslateEnumKeys} from '.';
27 5
import {
28 5
  grpc,
29 5
  CallOptions,
30 5
  Metadata,
31 5
  Operation as GaxOperation,
32 5
} from 'google-gax';
33 5
import {DateStruct, PreciseDate} from '@google-cloud/precise-date';
34 5
import {google as databaseAdmin} from '../protos/protos';
35 5
import {common as p} from 'protobufjs';
36 5

37 5
export type CreateBackupCallback = LongRunningCallback<Backup>;
38 5

39 5
export interface CreateBackupGaxOperation extends GaxOperation {
40 5
  // Overridden with more specific type for CreateBackup operation
41 5
  metadata: Metadata &
42 5
    databaseAdmin.spanner.admin.database.v1.ICreateBackupMetadata;
43 5
}
44 5

45 5
export type CreateBackupResponse = [
46 5
  Backup,
47 5
  CreateBackupGaxOperation,
48 5
  IOperation
49 5
];
50 5

51 5
export interface CreateBackupOptions {
52 5
  databasePath: string;
53 5
  expireTime: string | number | p.ITimestamp | PreciseDate;
54 5
  gaxOptions?: CallOptions;
55 5
}
56 5

57 5
/**
58 5
 * IBackup structure with backup state enum translated to string form.
59 5
 */
60 5
type IBackupTranslatedEnum = TranslateEnumKeys<
61 5
  databaseAdmin.spanner.admin.database.v1.IBackup,
62 5
  'state',
63 5
  typeof databaseAdmin.spanner.admin.database.v1.Backup.State
64 5
>;
65 5

66 5
export type GetMetadataResponse = [IBackupTranslatedEnum];
67 5
type GetMetadataCallback = RequestCallback<IBackupTranslatedEnum>;
68 5

69 5
type UpdateExpireTimeCallback = RequestCallback<databaseAdmin.spanner.admin.database.v1.IBackup>;
70 5

71 5
type DeleteCallback = RequestCallback<databaseAdmin.protobuf.IEmpty>;
72 5

73 5
interface BackupRequest {
74 5
  (
75 5
    config: RequestConfig,
76 5
    callback: ResourceCallback<GaxOperation, IOperation>
77 5
  ): void;
78 5
  <T>(config: RequestConfig, callback: RequestCallback<T>): void;
79 5
}
80 5
export type GetStateCallback = NormalCallback<
81 5
  EnumKey<typeof databaseAdmin.spanner.admin.database.v1.Backup.State>
82 5
>;
83 5
export type GetExpireTimeCallback = NormalCallback<PreciseDate>;
84 5
export type ExistsCallback = NormalCallback<boolean>;
85 5
/**
86 5
 * The {@link Backup} class represents a Cloud Spanner backup.
87 5
 *
88 5
 * Create a `Backup` object to interact with or create a Cloud Spanner backup.
89 5
 *
90 5
 * @class
91 5
 *
92 5
 * @example
93 5
 * const {Spanner} = require('@google-cloud/spanner');
94 5
 * const spanner = new Spanner();
95 5
 * const instance = spanner.instance('my-instance');
96 5
 * const backup = instance.backup('my-backup');
97 5
 */
98 5
class Backup {
99 5
  id: string;
100 5
  formattedName_: string;
101 5
  instanceFormattedName_: string;
102 5
  resourceHeader_: {[k: string]: string};
103 5
  request: BackupRequest;
104 5
  metadata?: databaseAdmin.spanner.admin.database.v1.IBackup;
105 5
  constructor(instance: Instance, name: string) {
106 5
    this.request = instance.request;
107 5
    this.instanceFormattedName_ = instance.formattedName_;
108 5
    this.formattedName_ = Backup.formatName_(instance.formattedName_, name);
109 5
    this.id = this.formattedName_.split('/').pop() || '';
110 5
    this.resourceHeader_ = {
111 5
      [CLOUD_RESOURCE_HEADER]: this.instanceFormattedName_,
112 5
    };
113 5
  }
114 5

115 5
  create(options: CreateBackupOptions): Promise<CreateBackupResponse>;
116 5
  create(options: CreateBackupOptions, callback: CreateBackupCallback): void;
117 5
  /**
118 5
   * @typedef {object} CreateBackupOptions
119 5
   * @property {string} databasePath The database path.
120 5
   * @property {string|number|google.protobuf.Timestamp|external:PreciseDate}
121 5
   *     expireTime The expire time of the backup.
122 5
   * @property {CallOptions} [gaxOptions] The request configuration options
123 5
   *     outlined here:
124 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
125 5
   */
126 5
  /**
127 5
   * @typedef {array} CreateBackupResponse
128 5
   * @property {Backup} 0 The new {@link Backup}.
129 5
   * @property {Operation} 1 An {@link Operation} object that can be used to check
130 5
   *     the status of the request.
131 5
   * @property {object} 2 The full API response.
132 5
   */
133 5
  /**
134 5
   * @callback CreateBackupCallback
135 5
   * @param {?Error} err Request error, if any.
136 5
   * @param {Backup} backup The new {@link Backup}.
137 5
   * @param {Operation} operation An {@link Operation} object that can be used to
138 5
   *     check the status of the request.
139 5
   * @param {object} apiResponse The full API response.
140 5
   */
141 5
  /**
142 5
   * Create a backup.
143 5
   *
144 5
   * @method Backup#create
145 5
   * @param {CreateBackupOptions} options Parameters for creating a backup.
146 5
   * @param {CallOptions} [options.gaxOptions] The request configuration
147 5
   *     options, outlined here:
148 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
149 5
   * @param {CreateBackupCallback} [callback] Callback function.
150 5
   * @returns {Promise<CreateBackupResponse>} When resolved, the backup
151 5
   *     operation will have started, but will not have necessarily completed.
152 5
   *
153 5
   * @example
154 5
   * const {Spanner} = require('@google-cloud/spanner');
155 5
   * const spanner = new Spanner();
156 5
   * const instance = spanner.instance('my-instance');
157 5
   * const oneDay = 1000 * 60 * 60 * 24;
158 5
   * const expireTime = Date.now() + oneDay;
159 5
   * const backup = instance.backup('my-backup');
160 5
   * const [, backupOperation] = await backup.create({
161 5
   *   databasePath: 'projects/my-project/instances/my-instance/databases/my-database',
162 5
   *   expireTime: expireTime,
163 5
   * });
164 5
   * // Await completion of the backup operation.
165 5
   * await backupOperation.promise();
166 5
   */
167 5
  create(
168 5
    options: CreateBackupOptions,
169 5
    callback?: CreateBackupCallback
170 5
  ): Promise<CreateBackupResponse> | void {
171 5
    const gaxOpts = options.gaxOptions;
172 5
    const reqOpts: databaseAdmin.spanner.admin.database.v1.ICreateBackupRequest = {
173 5
      parent: this.instanceFormattedName_,
174 5
      backupId: this.id,
175 5
      backup: {
176 5
        database: options.databasePath,
177 5
        expireTime: Spanner.timestamp(options.expireTime).toStruct(),
178 5
        name: this.formattedName_,
179 5
      },
180 5
    };
181 5
    this.request(
182 5
      {
183 5
        client: 'DatabaseAdminClient',
184 5
        method: 'createBackup',
185 5
        reqOpts,
186 5
        gaxOpts,
187 5
        headers: this.resourceHeader_,
188 5
      },
189 5
      (err, operation, resp) => {
190 5
        if (err) {
191 5
          callback!(err, null, null, resp);
192 5
          return;
193 5
        }
194 5
        callback!(null, this, operation, resp);
195 5
      }
196 5
    );
197 5
  }
198 5

199 5
  getMetadata(gaxOptions?: CallOptions): Promise<GetMetadataResponse>;
200 5
  getMetadata(callback: GetMetadataCallback): void;
201 5
  getMetadata(gaxOptions: CallOptions, callback: GetMetadataCallback): void;
202 5
  /**
203 5
   * @typedef {array} GetMetadataResponse
204 5
   * @property {object} 0 The {@link Backup} metadata.
205 5
   * @property {object} 1 The full API response.
206 5
   */
207 5
  /**
208 5
   * @callback GetMetadataCallback
209 5
   * @param {?Error} err Request error, if any.
210 5
   * @param {object} metadata The {@link Backup} metadata.
211 5
   * @param {object} apiResponse The full API response.
212 5
   */
213 5
  /**
214 5
   * Retrieves backup's metadata.
215 5
   *
216 5
   * @see {@link #getState}
217 5
   * @see {@link #getExpireTime}
218 5
   *
219 5
   * @method Backup#getMetadata
220 5
   * @param {object} [gaxOptions] Request configuration options, outlined here:
221 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
222 5
   * @param {GetMetadataCallback} [callback] Callback function.
223 5
   * @returns {Promise<GetMetadataResponse>}
224 5
   *
225 5
   * @example
226 5
   * const {Spanner} = require('@google-cloud/spanner');
227 5
   * const spanner = new Spanner();
228 5
   * const instance = spanner.instance('my-instance');
229 5
   * const backup = instance.backup('my-backup');
230 5
   * const [backupInfo] = await backup.getMetadata();
231 5
   * console.log(`${backupInfo.name}: size=${backupInfo.sizeBytes}`);
232 5
   */
233 5
  getMetadata(
234 5
    gaxOptionsOrCallback?: CallOptions | GetMetadataCallback,
235 5
    cb?: GetMetadataCallback
236 5
  ): void | Promise<GetMetadataResponse> {
237 5
    const callback =
238 5
      typeof gaxOptionsOrCallback === 'function'
239 5
        ? (gaxOptionsOrCallback as GetMetadataCallback)
240 5
        : cb;
241 5
    const gaxOpts =
242 5
      typeof gaxOptionsOrCallback === 'object'
243 5
        ? (gaxOptionsOrCallback as CallOptions)
244 5
        : {};
245 5
    const reqOpts: databaseAdmin.spanner.admin.database.v1.IGetBackupRequest = {
246 5
      name: this.formattedName_,
247 5
    };
248 5
    this.request<IBackupTranslatedEnum>(
249 5
      {
250 5
        client: 'DatabaseAdminClient',
251 5
        method: 'getBackup',
252 5
        reqOpts,
253 5
        gaxOpts,
254 5
        headers: this.resourceHeader_,
255 5
      },
256 5
      (err, response) => {
257 5
        if (response) {
258 5
          this.metadata = response;
259 5
        }
260 5
        callback!(err, response);
261 5
      }
262 5
    );
263 5
  }
264 5

265 5
  getState(): Promise<
266 5
    | EnumKey<typeof databaseAdmin.spanner.admin.database.v1.Backup.State>
267 5
    | undefined
268 5
    | null
269 5
  >;
270 5
  getState(callback: GetStateCallback): void;
271 5
  /**
272 5
   * Retrieves the state of the backup.
273 5
   *
274 5
   * The backup state indicates if the backup has completed.
275 5
   *
276 5
   * @see {@link #getMetadata}
277 5
   *
278 5
   * @method Backup#getState
279 5
   * @param {GetStateCallback} [callback] Callback function.
280 5
   * @returns {Promise<EnumKey<typeof, databaseAdmin.spanner.admin.database.v1.Backup.State> | undefined>}
281 5
   *     When resolved, contains the current state of the backup if it exists.
282 5
   *
283 5
   * @example
284 5
   * const {Spanner} = require('@google-cloud/spanner');
285 5
   * const spanner = new Spanner();
286 5
   * const instance = spanner.instance('my-instance');
287 5
   * const backup = instance.backup('my-backup');
288 5
   * const state = await backup.getState();
289 5
   * const backupCompleted = (state === 'READY');
290 5
   */
291 5
  async getState(): Promise<
292 5
    | EnumKey<typeof databaseAdmin.spanner.admin.database.v1.Backup.State>
293 5
    | undefined
294 5
    | null
295 5
  > {
296 5
    const [backupInfo] = await this.getMetadata();
297 5
    return backupInfo.state;
298 5
  }
299 5

300 5
  getExpireTime(): Promise<PreciseDate | undefined>;
301 5
  getExpireTime(callback: GetExpireTimeCallback): void;
302 5
  /**
303 5
   * Retrieves the expiry time of the backup.
304 5
   *
305 5
   * @see {@link #updateExpireTime}
306 5
   * @see {@link #getMetadata}
307 5
   *
308 5
   * @method Backup#getExpireTime
309 5
   * @returns {Promise<external:PreciseDate>} When resolved, contains the
310 5
   *     current expire time of the backup if it exists.
311 5
   *
312 5
   * @example
313 5
   * const {Spanner} = require('@google-cloud/spanner');
314 5
   * const spanner = new Spanner();
315 5
   * const instance = spanner.instance('my-instance');
316 5
   * const backup = instance.backup('my-backup');
317 5
   * const expireTime = await backup.getExpireTime();
318 5
   * console.log(`Backup expires on ${expireTime.toISOString()}`);
319 5
   */
320 5
  async getExpireTime(): Promise<PreciseDate | undefined> {
321 5
    const [backupInfo] = await this.getMetadata();
322 5
    return new PreciseDate(backupInfo.expireTime as DateStruct);
323 5
  }
324 5

325 5
  exists(): Promise<boolean>;
326 5
  exists(callback: ExistsCallback): void;
327 5
  /**
328 5
   * Checks whether the backup exists.
329 5
   *
330 5
   * @see {@link #getMetadata}
331 5
   *
332 5
   * @method Backup#exists
333 5
   * @returns {Promise<boolean>} When resolved, contains true if the backup
334 5
   *     exists and false if it does not exist.
335 5
   *
336 5
   * @example
337 5
   * const {Spanner} = require('@google-cloud/spanner');
338 5
   * const spanner = new Spanner();
339 5
   * const instance = spanner.instance('my-instance');
340 5
   * const backup = instance.backup('my-backup');
341 5
   * const alreadyExists = await backup.exists();
342 5
   * console.log(`Does backup exist? ${alreadyExists}`);
343 5
   */
344 5
  async exists(): Promise<boolean> {
345 5
    try {
346 5
      // Attempt to read metadata to determine whether backup exists
347 5
      await this.getMetadata();
348 5
      // Found therefore it exists
349 5
      return true;
350 5
    } catch (err) {
351 5
      if (err.code === grpc.status.NOT_FOUND) {
352 5
        return false;
353 5
      }
354 5
      // Some other error occurred, rethrow
355 5
      throw err;
356 5
    }
357 5
  }
358 5

359 5
  updateExpireTime(
360 5
    expireTime: string | number | p.ITimestamp | PreciseDate
361 5
  ): Promise<databaseAdmin.spanner.admin.database.v1.IBackup>;
362 5
  updateExpireTime(
363 5
    expireTime: string | number | p.ITimestamp | PreciseDate,
364 5
    gaxOptions?: CallOptions
365 5
  ): Promise<databaseAdmin.spanner.admin.database.v1.IBackup>;
366 5
  updateExpireTime(
367 5
    expireTime: string | number | p.ITimestamp | PreciseDate,
368 5
    callback: UpdateExpireTimeCallback
369 5
  ): void;
370 5
  updateExpireTime(
371 5
    expireTime: string | number | p.ITimestamp | PreciseDate,
372 5
    gaxOptions: CallOptions,
373 5
    callback: UpdateExpireTimeCallback
374 5
  ): void;
375 5
  /**
376 5
   * @callback UpdateExpireTimeCallback
377 5
   * @param {?Error} err Request error, if any.
378 5
   * @param {google.spanner.admin.database.v1.IBackup} backup The updated
379 5
   *     backup.
380 5
   */
381 5
  /**
382 5
   * Sets the expiry time of a backup.
383 5
   *
384 5
   * @see {@link #getExpireTime}
385 5
   *
386 5
   * @method Backup#updateExpireTime
387 5
   * @param {string|number|google.protobuf.Timestamp|external:PreciseDate}
388 5
   *     expireTime The expiry time to update with.
389 5
   * @param {object} [gaxOptions] Request configuration options, outlined here:
390 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
391 5
   * @param {UpdateExpireTimeCallback} [callback] Callback function.
392 5
   * @returns {Promise<google.spanner.admin.database.v1.IBackup>} When resolved,
393 5
   *     the backup's expire time will have been updated.
394 5
   *
395 5
   * @example
396 5
   * const {Spanner} = require('@google-cloud/spanner');
397 5
   * const spanner = new Spanner();
398 5
   * const instance = spanner.instance('my-instance');
399 5
   * const backup = instance.backup('my-backup');
400 5
   * const oneDay = 1000 * 60 * 60 * 24;
401 5
   * const newExpireTime = Spanner.timestamp(Date.now() + oneDay);
402 5
   * await backup.updateExpireTime(newExpireTime);
403 5
   */
404 5
  updateExpireTime(
405 5
    expireTime: string | number | p.ITimestamp | PreciseDate,
406 5
    gaxOptionsOrCallback?: CallOptions | UpdateExpireTimeCallback,
407 5
    cb?: UpdateExpireTimeCallback
408 5
  ): void | Promise<databaseAdmin.spanner.admin.database.v1.IBackup> {
409 5
    const callback =
410 5
      typeof gaxOptionsOrCallback === 'function'
411 5
        ? (gaxOptionsOrCallback as UpdateExpireTimeCallback)
412 5
        : cb;
413 5
    const gaxOpts =
414 5
      typeof gaxOptionsOrCallback === 'object'
415 5
        ? (gaxOptionsOrCallback as CallOptions)
416 5
        : {};
417 5
    const reqOpts: databaseAdmin.spanner.admin.database.v1.IUpdateBackupRequest = {
418 5
      backup: {
419 5
        name: this.formattedName_,
420 5
        expireTime: Spanner.timestamp(expireTime).toStruct(),
421 5
      },
422 5
      updateMask: {
423 5
        paths: ['expire_time'],
424 5
      },
425 5
    };
426 5
    this.request<databaseAdmin.spanner.admin.database.v1.IBackup>(
427 5
      {
428 5
        client: 'DatabaseAdminClient',
429 5
        method: 'updateBackup',
430 5
        reqOpts,
431 5
        gaxOpts,
432 5
        headers: this.resourceHeader_,
433 5
      },
434 5
      (err, response) => {
435 5
        callback!(err, response);
436 5
      }
437 5
    );
438 5
  }
439 5

440 5
  delete(gaxOptions?: CallOptions): Promise<databaseAdmin.protobuf.IEmpty>;
441 5
  delete(callback: DeleteCallback): void;
442 5
  delete(gaxOptions: CallOptions, callback: DeleteCallback): void;
443 5
  /**
444 5
   * Deletes a backup.
445 5
   *
446 5
   * @method Backup#delete
447 5
   * @param {object} [gaxOptions] Request configuration options, outlined here:
448 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
449 5
   * @param {DeleteBackupCallback} [callback] Callback function.
450 5
   * @returns {Promise<void>} When resolved, the backup will have been deleted.
451 5
   *
452 5
   * @example
453 5
   * const {Spanner} = require('@google-cloud/spanner');
454 5
   * const spanner = new Spanner();
455 5
   * const instance = spanner.instance('my-instance');
456 5
   * const backup = instance.backup('my-backup');
457 5
   * await backup.delete();
458 5
   */
459 5
  delete(
460 5
    gaxOptionsOrCallback?: CallOptions | DeleteCallback,
461 5
    cb?: DeleteCallback
462 5
  ): void | Promise<databaseAdmin.protobuf.IEmpty> {
463 5
    const callback =
464 5
      typeof gaxOptionsOrCallback === 'function'
465 5
        ? (gaxOptionsOrCallback as DeleteCallback)
466 5
        : cb;
467 5
    const gaxOpts =
468 5
      typeof gaxOptionsOrCallback === 'object'
469 5
        ? (gaxOptionsOrCallback as CallOptions)
470 5
        : {};
471 5
    const reqOpts: databaseAdmin.spanner.admin.database.v1.IDeleteBackupRequest = {
472 5
      name: this.formattedName_,
473 5
    };
474 5
    this.request<databaseAdmin.spanner.admin.database.v1.IBackup>(
475 5
      {
476 5
        client: 'DatabaseAdminClient',
477 5
        method: 'deleteBackup',
478 5
        reqOpts,
479 5
        gaxOpts,
480 5
        headers: this.resourceHeader_,
481 5
      },
482 5
      err => {
483 5
        callback!(err);
484 5
      }
485 5
    );
486 5
  }
487 5

488 5
  /**
489 5
   * Format the backup name to include the instance name.
490 5
   *
491 5
   * @private
492 5
   *
493 5
   * @param {string} instanceName The formatted instance name.
494 5
   * @param {string} name The table name.
495 5
   * @returns {string}
496 5
   *
497 5
   * @example
498 5
   * Backup.formatName_(
499 5
   *   'projects/grape-spaceship-123/instances/my-instance',
500 5
   *   'my-backup'
501 5
   * );
502 5
   * // 'projects/grape-spaceship-123/instances/my-instance/backups/my-backup'
503 5
   */
504 5
  static formatName_(instanceName: string, name: string) {
505 5
    if (name.indexOf('/') > -1) {
506 5
      return name;
507 5
    }
508 5
    const backupName = name.split('/').pop();
509 5
    return instanceName + '/backups/' + backupName;
510 5
  }
511 5
}
512 5

513 5
/*! Developer Documentation
514 5
 *
515 5
 * All async methods (except for streams) will return a Promise in the event
516 5
 * that a callback is omitted.
517 5
 */
518 5
promisifyAll(Backup, {
519 5
  exclude: ['getState', 'getExpireTime', 'exists'],
520 5
});
521 5

522 5
/*! Developer Documentation
523 5
 *
524 5
 * All async methods (except for streams) will return a Promise in the event
525 5
 * that a callback is omitted.
526 5
 */
527 5
callbackifyAll(Backup, {
528 5
  exclude: ['create', 'getMetadata', 'updateExpireTime', 'delete'],
529 5
});
530 5

531 5
/**
532 5
 * Reference to the {@link Backup} class.
533 5
 * @name module:@google-cloud/spanner.Backup
534 5
 * @see Backup
535 5
 */
536 5
export {Backup};

Read our documentation on viewing source code .

Loading