@google-cloud/bigtable
Version:
Cloud Bigtable Client Library for Node.js
537 lines • 20.8 kB
JavaScript
"use strict";
// Copyright 2016 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.Row = exports.RowError = void 0;
const promisify_1 = require("@google-cloud/promisify");
const arrify = require("arrify");
const mutation_1 = require("./mutation");
const row_data_utils_1 = require("./row-data-utils");
const getRowsInternal_1 = require("./utils/getRowsInternal");
const client_side_metrics_attributes_1 = require("./client-side-metrics/client-side-metrics-attributes");
const mutateInternal_1 = require("./utils/mutateInternal");
/**
* @private
*/
class RowError extends Error {
code;
constructor(row) {
super();
this.name = 'RowError';
this.message = `Unknown row: ${row}.`;
this.code = 404;
}
}
exports.RowError = RowError;
/**
* getProperties returns the properties needed to make a request for a table.
*
* @param {Row} row The row to make a request for.
*/
function getProperties(row) {
return {
reqOpts: { tableName: row.table.name },
requestData: row,
};
}
/**
* Create a Row object to interact with your table rows.
*
* @class
* @param {Table} table The row's parent Table instance.
* @param {string} key The key for this row.
*
* @example
* ```
* const {Bigtable} = require('@google-cloud/bigtable');
* const bigtable = new Bigtable();
* const instance = bigtable.instance('my-instance');
* const table = instance.table('prezzy');
* const row = table.row('gwashington');
* ```
*/
class Row {
bigtable;
table;
id;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data;
key;
metadata;
constructor(table, key) {
this.bigtable = table.bigtable;
this.table = table;
this.id = key;
this.data = {};
}
/**
* Formats the row chunks into friendly format. Chunks contain 3 properties:
*
* `rowContents` The row contents, this essentially is all data pertaining
* to a single family.
*
* `commitRow` This is a boolean telling us the all previous chunks for this
* row are ok to consume.
*
* `resetRow` This is a boolean telling us that all the previous chunks are to
* be discarded.
*
* @private
*
* @param {chunk[]} chunks The list of chunks.
* @param {object} [options] Formatting options.
*
* @example
* ```
* Row.formatChunks_(chunks);
* // {
* // follows: {
* // gwashington: [
* // {
* // value: 2
* // }
* // ]
* // }
* // }
* ```
*/
static formatChunks_(chunks, options) {
const rows = [];
let familyName;
let qualifierName;
options = options || {};
chunks.reduce((row, chunk) => {
let family;
let qualifier;
row.data = row.data || {};
if (chunk.rowKey) {
row.key = mutation_1.Mutation.convertFromBytes(chunk.rowKey, {
userOptions: options,
});
}
if (chunk.familyName) {
familyName = chunk.familyName.value;
}
if (familyName) {
family = row.data[familyName] = row.data[familyName] || {};
}
if (chunk.qualifier) {
qualifierName = mutation_1.Mutation.convertFromBytes(chunk.qualifier.value, {
userOptions: options,
});
}
if (family && qualifierName) {
qualifier = family[qualifierName] = family[qualifierName] || [];
}
if (qualifier && chunk.value) {
qualifier.push({
value: mutation_1.Mutation.convertFromBytes(chunk.value, { userOptions: options }),
labels: chunk.labels,
timestamp: chunk.timestampMicros,
size: chunk.valueSize,
});
}
if (chunk.commitRow) {
rows.push(row);
}
if (chunk.commitRow || chunk.resetRow) {
familyName = qualifierName = null;
return {};
}
return row;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}, {});
return rows;
}
/**
* Formats a rowContents object into friendly format.
*
* @private
*
* @param {object[]} families The row families.
* @param {object} [options] Formatting options.
*
* @example
* ```
* const families = [
* {
* name: 'follows',
* columns: [
* {
* qualifier: 'gwashington',
* cells: [
* {
* value: 2
* }
* ]
* }
* ]
* }
* ];
*
* Row.formatFamilies_(families);
* // {
* // follows: {
* // gwashington: [
* // {
* // value: 2
* // }
* // ]
* // }
* // }
* ```
*/
static formatFamilies_(families, options) {
return row_data_utils_1.RowDataUtils.formatFamilies_Util(families, options);
}
/**
* Create a new row in your table.
*
* @param {object} [options] Configuration object.
* @param {object} [options.entry] An entry. See {@link Table#insert}.
* @param {object} [options.gaxOptions] Request configuration options, outlined
* here: https://googleapis.github.io/gax-nodejs/CallSettings.html.
* @param {function} callback The callback function.
* @param {?error} callback.err An error returned while making this
* request.
* @param {Row} callback.row The newly created row object.
* @param {object} callback.apiResponse The full API response.
*
* @example <caption>include:samples/api-reference-doc-snippets/row.js</caption>
* region_tag:bigtable_api_create_row
*/
create(optionsOrCallback, cb) {
const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
const entry = {
key: this.id,
data: options.entry,
method: mutation_1.Mutation.methods.INSERT,
};
this.data = {};
this.table.mutate(entry, options.gaxOptions, (err, apiResponse) => {
if (err) {
callback(err, null, apiResponse);
return;
}
callback(null, this, apiResponse);
});
}
/**
* Update a row with rules specifying how the row's contents are to be
* transformed into writes. Rules are applied in order, meaning that earlier
* rules will affect the results of later ones.
*
* @throws {error} If no rules are provided.
*
* @param {object|object[]} rules The rules to apply to this row.
* @param {object} [gaxOptions] Request configuration options, outlined here:
* https://googleapis.github.io/gax-nodejs/CallSettings.html.
* @param {function} callback The callback function.
* @param {?error} callback.err An error returned while making this
* request.
* @param {object} callback.apiResponse The full API response.
*
* @example <caption>include:samples/api-reference-doc-snippets/row.js</caption>
* region_tag:bigtable_api_create_rules
*/
createRules(rules, optionsOrCallback, cb) {
row_data_utils_1.RowDataUtils.createRulesUtil(rules, getProperties(this), optionsOrCallback, cb);
}
/**
* Deletes all cells in the row.
*
* @param {object} [gaxOptions] Request configuration options, outlined here:
* https://googleapis.github.io/gax-nodejs/CallSettings.html.
* @param {function} callback The callback function.
* @param {?error} callback.err An error returned while making this
* request.
* @param {object} callback.apiResponse The full API response.
*
* @example <caption>include:samples/api-reference-doc-snippets/row.js</caption>
* region_tag:bigtable_api_delete_all_cells
*/
delete(optionsOrCallback, cb) {
const gaxOptions = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
const mutation = {
key: this.id,
method: mutation_1.Mutation.methods.DELETE,
};
this.data = {};
this.table.mutate(mutation, gaxOptions, callback);
}
/**
* Delete specified cells from the row. See {@link Table#mutate}.
*
* @param {string[]} columns Column names for the cells to be deleted.
* @param {object} [gaxOptions] Request configuration options, outlined here:
* https://googleapis.github.io/gax-nodejs/CallSettings.html.
* @param {function} callback The callback function.
* @param {?error} callback.err An error returned while making this
* request.
* @param {object} callback.apiResponse The full API response.
*
* @example <caption>include:samples/api-reference-doc-snippets/row.js</caption>
* region_tag:bigtable_api_delete_particular_cells
*/
deleteCells(columns, optionsOrCallback, cb) {
const gaxOptions = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
const mutation = {
key: this.id,
data: arrify(columns),
method: mutation_1.Mutation.methods.DELETE,
};
this.data = {};
this.table.mutate(mutation, gaxOptions, callback);
}
/**
* Check if the table row exists.
*
* @param {object} [gaxOptions] Request configuration options, outlined here:
* https://googleapis.github.io/gax-nodejs/CallSettings.html.
* @param {function} callback The callback function.
* @param {?error} callback.err An error returned while making this
* request.
* @param {boolean} callback.exists Whether the row exists or not.
*
* @example <caption>include:samples/api-reference-doc-snippets/row.js</caption>
* region_tag:bigtable_api_row_exists
*/
exists(optionsOrCallback, cb) {
const gaxOptions = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
const options = Object.assign({
filter: [
{
row: {
cellLimit: 1,
},
},
{
value: {
strip: true,
},
},
],
}, gaxOptions);
this.getMetadata(options, err => {
if (err) {
if (err instanceof RowError) {
callback(null, false);
return;
}
callback(err);
return;
}
callback(null, true);
});
}
/**
* Mutates a row atomically based on the output of a filter. Depending on
* whether or not any results are yielded, either the `onMatch` or `onNoMatch`
* callback will be executed.
*
* @param {Filter} filter Filter to be applied to the contents of the row.
* @param {object} config Configuration object.
* @param {?object[]} config.onMatch A list of entries to be ran if a match is
* found.
* @param {object[]} [config.onNoMatch] A list of entries to be ran if no
* matches are found.
* @param {object} [config.gaxOptions] Request configuration options, outlined
* here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
* @param {function} callback The callback function.
* @param {?error} callback.err An error returned while making this
* request.
* @param {boolean} callback.matched Whether a match was found or not.
*
* @example <caption>include:samples/api-reference-doc-snippets/row.js</caption>
* region_tag:bigtable_api_row_filter
*/
filter(filter, configOrCallback, cb) {
row_data_utils_1.RowDataUtils.filterUtil(filter, getProperties(this), configOrCallback, cb);
}
/**
* Get the row data. See {@link Table#getRows}.
*
* @param {string[]} [columns] List of specific columns to retrieve.
* @param {object} [options] Configuration object.
* @param {boolean} [options.decode=true] If set to `false` it will not decode Buffer
* values returned from Bigtable.
* @param {object} [options.gaxOptions] Request configuration options, outlined
* here: https://googleapis.github.io/gax-nodejs/CallSettings.html.
* @param {function} callback The callback function.
* @param {?error} callback.err An error returned while making this
* request.
* @param {Row} callback.row The updated Row object.
*
* @example <caption>include:samples/api-reference-doc-snippets/row.js</caption>
* region_tag:bigtable_api_get_row
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
get(columnsOrOptionsOrCallback, optionsOrCallback, cb) {
let columns = Array.isArray(columnsOrOptionsOrCallback)
? columnsOrOptionsOrCallback
: [];
const options = typeof columnsOrOptionsOrCallback === 'object' &&
!Array.isArray(columnsOrOptionsOrCallback)
? columnsOrOptionsOrCallback
: typeof optionsOrCallback === 'object'
? optionsOrCallback
: {};
const callback = typeof columnsOrOptionsOrCallback === 'function'
? columnsOrOptionsOrCallback
: typeof optionsOrCallback === 'function'
? optionsOrCallback
: cb;
let filter;
columns = arrify(columns);
// if there is column filter
if (columns.length) {
const filters = columns.map(mutation_1.Mutation.parseColumnName).map(column => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const colmFilters = [{ family: column.family }];
if (column.qualifier) {
colmFilters.push({ column: column.qualifier });
}
return colmFilters;
});
// if there is more then one filter, make it type inteleave filter
if (filters.length > 1) {
filter = [
{
interleave: filters,
},
];
}
else {
filter = filters[0];
}
}
// if there is also a second option.filter append to filter array
if (options.filter) {
filter = arrify(filter).concat(options.filter);
}
const getRowsOptions = Object.assign({}, options, {
keys: [this.id],
filter,
});
const metricsCollector = this.table.bigtable._metricsConfigManager.createOperation(client_side_metrics_attributes_1.MethodName.READ_ROW, client_side_metrics_attributes_1.StreamingState.UNARY, this.table);
void (0, getRowsInternal_1.getRowsInternal)(this.table, metricsCollector, getRowsOptions, (err, rows) => {
if (err) {
callback(err);
return;
}
const row = rows[0];
if (!row) {
const e = new RowError(this.id);
callback(e);
return;
}
this.data = row.data;
// If the user specifies column names, we'll return back the row data
// we received. Otherwise, we'll return the row "this" in a typical
// GrpcServiceObject#get fashion.
if (columns.length > 0) {
callback(null, row.data);
}
else {
callback(null, this);
}
});
}
/**
* Get the row's metadata.
*
* @param {object} [options] Configuration object.
* @param {boolean} [options.decode=true] If set to `false` it will not decode
* Buffer values returned from Bigtable.
* @param {object} [options.gaxOptions] Request configuration options, outlined
* here: https://googleapis.github.io/gax-nodejs/CallSettings.html.
* @param {function} callback The callback function.
* @param {?error} callback.err An error returned while making this
* request.
* @param {object} callback.metadata The row's metadata.
*
* @example <caption>include:samples/api-reference-doc-snippets/row.js</caption>
* region_tag:bigtable_api_get_row_meta
*/
getMetadata(optionsOrCallback, cb) {
const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
this.get(options, (err, row) => {
if (err) {
callback(err);
return;
}
callback(null, row.metadata);
});
}
/**
* Increment a specific column within the row. If the column does not
* exist, it is automatically initialized to 0 before being incremented.
*
* @param {string} column The column we are incrementing a value in.
* @param {number} [value] The amount to increment by, defaults to 1.
* @param {object} [gaxOptions] Request configuration options, outlined here:
* https://googleapis.github.io/gax-nodejs/CallSettings.html.
* @param {function} callback The callback function.
* @param {?error} callback.err An error returned while making this
* request.
* @param {number} callback.value The updated value of the column.
* @param {object} callback.apiResponse The full API response.
*
* @example <caption>include:samples/api-reference-doc-snippets/row.js</caption>
* region_tag:bigtable_api_row_increment
*/
increment(column, valueOrOptionsOrCallback, optionsOrCallback, cb) {
row_data_utils_1.RowDataUtils.incrementUtils(column, getProperties(this), valueOrOptionsOrCallback, optionsOrCallback, cb);
}
/**
* Update the row cells.
*
* @param {object} key An entry object to be inserted into the row. See
* {@link Table#insert}.
* @param {object} [gaxOptions] Request configuration options, outlined here:
* https://googleapis.github.io/gax-nodejs/CallSettings.html.
* @param {function} callback The callback function.
* @param {?error} callback.err An error returned while making this
* request.
* @param {object} callback.apiResponse The full API response.
*
* @example <caption>include:samples/api-reference-doc-snippets/row.js</caption>
* region_tag:bigtable_api_row_save
*/
save(entry, optionsOrCallback, cb) {
const gaxOptions = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
const mutation = {
key: this.id,
data: entry,
method: mutation_1.Mutation.methods.INSERT,
};
this.data = {};
const metricsCollector = this.bigtable._metricsConfigManager.createOperation(client_side_metrics_attributes_1.MethodName.MUTATE_ROW, client_side_metrics_attributes_1.StreamingState.UNARY, this.table);
(0, mutateInternal_1.mutateInternal)(this.table, metricsCollector, mutation, gaxOptions, callback);
}
}
exports.Row = Row;
/*! Developer Documentation
*
* All async methods (except for streams) will return a Promise in the event
* that a callback is omitted.
*/
(0, promisify_1.promisifyAll)(Row);
//# sourceMappingURL=row.js.map