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

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

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

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

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

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

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

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

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

73 4
type DeleteCallback = RequestCallback<databaseAdmin.protobuf.IEmpty>;
74 4

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

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

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

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

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

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

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

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

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

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

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

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

Read our documentation on viewing source code .

Loading