UNPKG

@google-cloud/bigtable

Version:
537 lines 20.8 kB
"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