From 0973c384f42220ba34d5b3bd86bb404098e0f68c Mon Sep 17 00:00:00 2001 From: Darragh Mc Kay Date: Thu, 2 Dec 2021 18:31:46 +0000 Subject: [PATCH 1/4] Developer metadata (#1) * Fetch developer metadata by Id and create for columns, rows and sheets * Add docs --- docs/classes/google-spreadsheet-cell.md | 13 ++++++ docs/classes/google-spreadsheet-row.md | 12 +++++ docs/classes/google-spreadsheet-worksheet.md | 14 ++++++ docs/classes/google-spreadsheet.md | 30 +++++++++++++ lib/GoogleSpreadsheet.js | 46 ++++++++++++++++++++ lib/GoogleSpreadsheetCell.js | 15 +++++++ lib/GoogleSpreadsheetRow.js | 15 +++++++ lib/GoogleSpreadsheetWorksheet.js | 5 ++- 8 files changed, 149 insertions(+), 1 deletion(-) diff --git a/docs/classes/google-spreadsheet-cell.md b/docs/classes/google-spreadsheet-cell.md index e7d13011..91d2323d 100644 --- a/docs/classes/google-spreadsheet-cell.md +++ b/docs/classes/google-spreadsheet-cell.md @@ -111,3 +111,16 @@ Property|Type|Description ?> Usually makes more sense to use `sheet.saveUpdatedCells()` to save many cell updates at once + + +### Developer Metadata + +#### `createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId)` (async) :id=fn-createSheetDeveloperMetadata +> Add a new developer metadata object to the column of the cell + +Param|Type|Required|Description +---|---|---|--- +`metadataKey`|String|✅|The metadata key +`metadataValue`|String|✅|Data associated with the metadata's key +`visibility`|String|-|Limits the visibility selected developer metadata
_One of (PROJECT or DOCUMENT) - defaults to unspecified_ +`metadataId`|Integer|-|Spreadsheet-scoped unique ID that identifies the metadata
_autogenerated by google if empty_ diff --git a/docs/classes/google-spreadsheet-row.md b/docs/classes/google-spreadsheet-row.md index c4564cc3..73ba6634 100644 --- a/docs/classes/google-spreadsheet-row.md +++ b/docs/classes/google-spreadsheet-row.md @@ -94,3 +94,15 @@ Param|Type|Required|Description _also available as `row.del()`_ + +### Developer Metadata + +#### `createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId)` (async) :id=fn-createSheetDeveloperMetadata +> Add a new developer metadata object to the row + +Param|Type|Required|Description +---|---|---|--- +`metadataKey`|String|✅|The metadata key +`metadataValue`|String|✅|Data associated with the metadata's key +`visibility`|String|-|Limits the visibility selected developer metadata
_One of (PROJECT or DOCUMENT) - defaults to unspecified_ +`metadataId`|Integer|-|Spreadsheet-scoped unique ID that identifies the metadata
_autogenerated by google if empty_ diff --git a/docs/classes/google-spreadsheet-worksheet.md b/docs/classes/google-spreadsheet-worksheet.md index a336bd2e..3c7ac76b 100644 --- a/docs/classes/google-spreadsheet-worksheet.md +++ b/docs/classes/google-spreadsheet-worksheet.md @@ -272,6 +272,20 @@ Param|Type|Required|Description - ✨ **Side effects** - new row(s) or column(s) are inserted into the sheet - 🚨 **Warning** - Does not update cached rows/cells, so be sure to reload rows/cells before trying to make any updates to sheet contents + +### Developer Metadata + +#### `createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId)` (async) :id=fn-createSheetDeveloperMetadata +> Add a new developer metadata object to the sheet + +Param|Type|Required|Description +---|---|---|--- +`metadataKey`|String|✅|The metadata key +`metadataValue`|String|✅|Data associated with the metadata's key +`visibility`|String|-|Limits the visibility selected developer metadata
_One of (PROJECT or DOCUMENT) - defaults to unspecified_ +`metadataId`|Integer|-|Spreadsheet-scoped unique ID that identifies the metadata
_autogenerated by google if empty_ + + ### Other #### `clear()` (async) :id=fn-clear diff --git a/docs/classes/google-spreadsheet.md b/docs/classes/google-spreadsheet.md index 55553fb1..681219f7 100644 --- a/docs/classes/google-spreadsheet.md +++ b/docs/classes/google-spreadsheet.md @@ -210,3 +210,33 @@ Param|Type|Required|Description `rangeId`|String|✅|ID of the range to remove +### Developer Metadata + +### `getMetadataById(metadataId)` (async) :id=fn-getMetadataById +> Get the developer metadata by ID + +Param|Type|Required|Description +---|---|---|--- +`metadataId`|Number|✅|The ID of the developer metadata object + +#### `createSheetDeveloperMetadata(metadataKey, metadataValue, sheetId, visibility, metadataId)` (async) :id=fn-createSheetDeveloperMetadata +> Add a new developer metadata object to a specific sheet + +Param|Type|Required|Description +---|---|---|--- +`metadataKey`|String|✅|The metadata key +`metadataValue`|String|✅|Data associated with the metadata's key +`sheetId`|String|-|The ID of the sheet to associate the metadata with +`visibility`|String|-|Limits the visibility selected developer metadata
_One of (PROJECT or DOCUMENT) - defaults to unspecified_ +`metadataId`|Integer|-|Spreadsheet-scoped unique ID that identifies the metadata
_autogenerated by google if empty_ + +#### `createRangeDeveloperMetadata(metadataKey, metadataValue, range, visibility, metadataId)` (async) :id=fn-createRangeDeveloperMetadata +> Add a new developer metadata object to a specific range (COLUMNS or ROWS) + +Param|Type|Required|Description +---|---|---|--- +`metadataKey`|String|✅|The metadata key +`metadataValue`|String|✅|Data associated with the metadata's key +`range`|String|✅||The dimensionRange object to associate the metadata with +`visibility`|String|-|Limits the visibility selected developer metadata
_One of (PROJECT or DOCUMENT) - defaults to unspecified_ +`metadataId`|Integer|-|Spreadsheet-scoped unique ID that identifies the metadata
_autogenerated by google if empty_ diff --git a/lib/GoogleSpreadsheet.js b/lib/GoogleSpreadsheet.js index 98d3a19d..ef2be364 100644 --- a/lib/GoogleSpreadsheet.js +++ b/lib/GoogleSpreadsheet.js @@ -332,6 +332,52 @@ class GoogleSpreadsheet { }); } + async getMetadataById(metadataId) { + // Request type = `developerMetadata` + // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.developerMetadata/get + return this.axios + .get(`/developerMetadata/${metadataId}`) + .then((response) => response.data); + } + + async _createDeveloperMetadata(metadataKey, metadataValue, location, visibility, metadataId) { + // Request type = `createDeveloperMetadata` + // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.developerMetadata#DeveloperMetadata + return this._makeSingleUpdateRequest('createDeveloperMetadata', { + developerMetadata: { + metadataKey, + metadataValue, + location, + visibility: visibility || 'PROJECT', + metadataId, + }, + }).then((data) => data.developerMetadata); + } + + async createSheetDeveloperMetadata(metadataKey, metadataValue, sheetId, visibility, metadataId) { + return this._createDeveloperMetadata( + metadataKey, + metadataValue, + { + sheetId: sheetId || 0, + }, + visibility, + metadataId + ); + } + + async createRangeDeveloperMetadata(metadataKey, metadataValue, range, visibility, metadataId) { + return this._createDeveloperMetadata( + metadataKey, + metadataValue, + { + dimensionRange: range, + }, + visibility, + metadataId + ); + } + async deleteNamedRange(namedRangeId) { return this._makeSingleUpdateRequest('deleteNamedRange', { namedRangeId }); } diff --git a/lib/GoogleSpreadsheetCell.js b/lib/GoogleSpreadsheetCell.js index 7d7f318b..1e2ae39d 100644 --- a/lib/GoogleSpreadsheetCell.js +++ b/lib/GoogleSpreadsheetCell.js @@ -174,6 +174,21 @@ class GoogleSpreadsheetCell { await this._sheet.saveUpdatedCells([this]); } + async createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId) { + return this._sheet._spreadsheet.createRangeDeveloperMetadata( + metadataKey, + metadataValue, + { + dimension: 'COLUMNS', + sheetId: this._sheet.sheetId, + startIndex: this._column, + endIndex: this._column + 1, + }, + visibility, + metadataId + ); + } + // used by worksheet when saving cells // returns an individual batchUpdate request to update the cell _getUpdateRequest() { diff --git a/lib/GoogleSpreadsheetRow.js b/lib/GoogleSpreadsheetRow.js index a1ff7603..8015347d 100644 --- a/lib/GoogleSpreadsheetRow.js +++ b/lib/GoogleSpreadsheetRow.js @@ -67,6 +67,21 @@ class GoogleSpreadsheetRow { return result; } async del() { return this.delete(); } // alias to mimic old version of this module + + async createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId) { + return this._sheet._spreadsheet.createRangeDeveloperMetadata( + metadataKey, + metadataValue, + { + dimension: 'ROWS', + sheetId: this._sheet.sheetId, + startIndex: this._rowNumber, + endIndex: this._rowNumber + 1, + }, + visibility, + metadataId + ); + } } module.exports = GoogleSpreadsheetRow; diff --git a/lib/GoogleSpreadsheetWorksheet.js b/lib/GoogleSpreadsheetWorksheet.js index 324e77c7..345b5631 100644 --- a/lib/GoogleSpreadsheetWorksheet.js +++ b/lib/GoogleSpreadsheetWorksheet.js @@ -782,9 +782,12 @@ class GoogleSpreadsheetWorksheet { // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteBandingRequest } - async createDeveloperMetadata() { + async createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId) { // Request type = `createDeveloperMetadata` // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CreateDeveloperMetadataRequest + return this._spreadsheet.createSheetDeveloperMetadata( + metadataKey, metadataValue, this.sheetId, visibility, metadataId + ); } async updateDeveloperMetadata() { From a4e016852394eea03852718a0fd9fdc5470b2a2c Mon Sep 17 00:00:00 2001 From: Darragh Mc Kay Date: Fri, 3 Dec 2021 12:24:27 +0000 Subject: [PATCH 2/4] Retry logic when rate-limited --- docs/classes/google-spreadsheet.md | 11 +++++++++++ lib/GoogleSpreadsheet.js | 24 +++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/classes/google-spreadsheet.md b/docs/classes/google-spreadsheet.md index 681219f7..f1d119e5 100644 --- a/docs/classes/google-spreadsheet.md +++ b/docs/classes/google-spreadsheet.md @@ -240,3 +240,14 @@ Param|Type|Required|Description `range`|String|✅||The dimensionRange object to associate the metadata with `visibility`|String|-|Limits the visibility selected developer metadata
_One of (PROJECT or DOCUMENT) - defaults to unspecified_ `metadataId`|Integer|-|Spreadsheet-scoped unique ID that identifies the metadata
_autogenerated by google if empty_ + +### Retry logic + +### `setRetryOptions(metadataId)` (async) :id=fn-setRetryOptions +> Set the retry options for when your requests are rate-limited (error 429) +> If these options are not set then requests won't be retried + +Param|Type|Required|Description +---|---|---|--- +`retries`|Number|✅|The number of times a request should be retried +`retryDelay`|Number|✅|The time to delay in miliseconds between retry attempts diff --git a/lib/GoogleSpreadsheet.js b/lib/GoogleSpreadsheet.js index ef2be364..ea4ad2f7 100644 --- a/lib/GoogleSpreadsheet.js +++ b/lib/GoogleSpreadsheet.js @@ -57,6 +57,9 @@ class GoogleSpreadsheet { this._handleAxiosErrors.bind(this) ); + this._retries = 0; + this._retryDelay = 3000; + return this; } @@ -122,6 +125,11 @@ class GoogleSpreadsheet { */ } + setRetryOptions(retries, retryDelay) { + this._retries = retries; + this._retryDelay = retryDelay; + } + // TODO: provide mechanism to share single JWT auth between docs? // INTERNAL UTILITY FUNCTIONS //////////////////////////////////////////////////////////////////// @@ -150,7 +158,21 @@ class GoogleSpreadsheet { async _handleAxiosResponse(response) { return response; } async _handleAxiosErrors(error) { - // console.log(error); + if (_.get(error, 'response.status') === 429) { + const config = error.config; + const retryCount = config.retryCount || 0; + + if (this._retries > 0 && retryCount < this._retries) { + config.retryCount = retryCount + 1; + + return new Promise((resolve) => { + setTimeout(() => { + resolve(this.axios(config)); + }, this._retryDelay); + }); + } + } + if (error.response && error.response.data) { // usually the error has a code and message, but occasionally not if (!error.response.data.error) throw error; From d001fbb1242b399db4f7f2b74d3da152af12cc5f Mon Sep 17 00:00:00 2001 From: Darragh Mc Kay Date: Fri, 3 Dec 2021 12:30:09 +0000 Subject: [PATCH 3/4] Reverse developer-metadata --- docs/classes/google-spreadsheet-cell.md | 13 -------- docs/classes/google-spreadsheet-row.md | 12 -------- docs/classes/google-spreadsheet-worksheet.md | 14 --------- docs/classes/google-spreadsheet.md | 31 -------------------- 4 files changed, 70 deletions(-) diff --git a/docs/classes/google-spreadsheet-cell.md b/docs/classes/google-spreadsheet-cell.md index 91d2323d..e7d13011 100644 --- a/docs/classes/google-spreadsheet-cell.md +++ b/docs/classes/google-spreadsheet-cell.md @@ -111,16 +111,3 @@ Property|Type|Description ?> Usually makes more sense to use `sheet.saveUpdatedCells()` to save many cell updates at once - - -### Developer Metadata - -#### `createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId)` (async) :id=fn-createSheetDeveloperMetadata -> Add a new developer metadata object to the column of the cell - -Param|Type|Required|Description ----|---|---|--- -`metadataKey`|String|✅|The metadata key -`metadataValue`|String|✅|Data associated with the metadata's key -`visibility`|String|-|Limits the visibility selected developer metadata
_One of (PROJECT or DOCUMENT) - defaults to unspecified_ -`metadataId`|Integer|-|Spreadsheet-scoped unique ID that identifies the metadata
_autogenerated by google if empty_ diff --git a/docs/classes/google-spreadsheet-row.md b/docs/classes/google-spreadsheet-row.md index 73ba6634..c4564cc3 100644 --- a/docs/classes/google-spreadsheet-row.md +++ b/docs/classes/google-spreadsheet-row.md @@ -94,15 +94,3 @@ Param|Type|Required|Description _also available as `row.del()`_ - -### Developer Metadata - -#### `createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId)` (async) :id=fn-createSheetDeveloperMetadata -> Add a new developer metadata object to the row - -Param|Type|Required|Description ----|---|---|--- -`metadataKey`|String|✅|The metadata key -`metadataValue`|String|✅|Data associated with the metadata's key -`visibility`|String|-|Limits the visibility selected developer metadata
_One of (PROJECT or DOCUMENT) - defaults to unspecified_ -`metadataId`|Integer|-|Spreadsheet-scoped unique ID that identifies the metadata
_autogenerated by google if empty_ diff --git a/docs/classes/google-spreadsheet-worksheet.md b/docs/classes/google-spreadsheet-worksheet.md index 3c7ac76b..a336bd2e 100644 --- a/docs/classes/google-spreadsheet-worksheet.md +++ b/docs/classes/google-spreadsheet-worksheet.md @@ -272,20 +272,6 @@ Param|Type|Required|Description - ✨ **Side effects** - new row(s) or column(s) are inserted into the sheet - 🚨 **Warning** - Does not update cached rows/cells, so be sure to reload rows/cells before trying to make any updates to sheet contents - -### Developer Metadata - -#### `createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId)` (async) :id=fn-createSheetDeveloperMetadata -> Add a new developer metadata object to the sheet - -Param|Type|Required|Description ----|---|---|--- -`metadataKey`|String|✅|The metadata key -`metadataValue`|String|✅|Data associated with the metadata's key -`visibility`|String|-|Limits the visibility selected developer metadata
_One of (PROJECT or DOCUMENT) - defaults to unspecified_ -`metadataId`|Integer|-|Spreadsheet-scoped unique ID that identifies the metadata
_autogenerated by google if empty_ - - ### Other #### `clear()` (async) :id=fn-clear diff --git a/docs/classes/google-spreadsheet.md b/docs/classes/google-spreadsheet.md index f1d119e5..ac7591b6 100644 --- a/docs/classes/google-spreadsheet.md +++ b/docs/classes/google-spreadsheet.md @@ -210,37 +210,6 @@ Param|Type|Required|Description `rangeId`|String|✅|ID of the range to remove -### Developer Metadata - -### `getMetadataById(metadataId)` (async) :id=fn-getMetadataById -> Get the developer metadata by ID - -Param|Type|Required|Description ----|---|---|--- -`metadataId`|Number|✅|The ID of the developer metadata object - -#### `createSheetDeveloperMetadata(metadataKey, metadataValue, sheetId, visibility, metadataId)` (async) :id=fn-createSheetDeveloperMetadata -> Add a new developer metadata object to a specific sheet - -Param|Type|Required|Description ----|---|---|--- -`metadataKey`|String|✅|The metadata key -`metadataValue`|String|✅|Data associated with the metadata's key -`sheetId`|String|-|The ID of the sheet to associate the metadata with -`visibility`|String|-|Limits the visibility selected developer metadata
_One of (PROJECT or DOCUMENT) - defaults to unspecified_ -`metadataId`|Integer|-|Spreadsheet-scoped unique ID that identifies the metadata
_autogenerated by google if empty_ - -#### `createRangeDeveloperMetadata(metadataKey, metadataValue, range, visibility, metadataId)` (async) :id=fn-createRangeDeveloperMetadata -> Add a new developer metadata object to a specific range (COLUMNS or ROWS) - -Param|Type|Required|Description ----|---|---|--- -`metadataKey`|String|✅|The metadata key -`metadataValue`|String|✅|Data associated with the metadata's key -`range`|String|✅||The dimensionRange object to associate the metadata with -`visibility`|String|-|Limits the visibility selected developer metadata
_One of (PROJECT or DOCUMENT) - defaults to unspecified_ -`metadataId`|Integer|-|Spreadsheet-scoped unique ID that identifies the metadata
_autogenerated by google if empty_ - ### Retry logic ### `setRetryOptions(metadataId)` (async) :id=fn-setRetryOptions From 9757e1f2c99ccda9d684c5789d7af2cd23bd4ba9 Mon Sep 17 00:00:00 2001 From: Darragh Mc Kay Date: Fri, 3 Dec 2021 12:31:36 +0000 Subject: [PATCH 4/4] Revert "Fetch developer metadata by Id and create for columns, rows and sheets" This reverts commit ec8bcc488403479d688d1ae225da3b86eee88e6c. --- lib/GoogleSpreadsheet.js | 46 ------------------------------- lib/GoogleSpreadsheetCell.js | 15 ---------- lib/GoogleSpreadsheetRow.js | 15 ---------- lib/GoogleSpreadsheetWorksheet.js | 5 +--- 4 files changed, 1 insertion(+), 80 deletions(-) diff --git a/lib/GoogleSpreadsheet.js b/lib/GoogleSpreadsheet.js index ea4ad2f7..742df5e0 100644 --- a/lib/GoogleSpreadsheet.js +++ b/lib/GoogleSpreadsheet.js @@ -354,52 +354,6 @@ class GoogleSpreadsheet { }); } - async getMetadataById(metadataId) { - // Request type = `developerMetadata` - // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.developerMetadata/get - return this.axios - .get(`/developerMetadata/${metadataId}`) - .then((response) => response.data); - } - - async _createDeveloperMetadata(metadataKey, metadataValue, location, visibility, metadataId) { - // Request type = `createDeveloperMetadata` - // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.developerMetadata#DeveloperMetadata - return this._makeSingleUpdateRequest('createDeveloperMetadata', { - developerMetadata: { - metadataKey, - metadataValue, - location, - visibility: visibility || 'PROJECT', - metadataId, - }, - }).then((data) => data.developerMetadata); - } - - async createSheetDeveloperMetadata(metadataKey, metadataValue, sheetId, visibility, metadataId) { - return this._createDeveloperMetadata( - metadataKey, - metadataValue, - { - sheetId: sheetId || 0, - }, - visibility, - metadataId - ); - } - - async createRangeDeveloperMetadata(metadataKey, metadataValue, range, visibility, metadataId) { - return this._createDeveloperMetadata( - metadataKey, - metadataValue, - { - dimensionRange: range, - }, - visibility, - metadataId - ); - } - async deleteNamedRange(namedRangeId) { return this._makeSingleUpdateRequest('deleteNamedRange', { namedRangeId }); } diff --git a/lib/GoogleSpreadsheetCell.js b/lib/GoogleSpreadsheetCell.js index 1e2ae39d..7d7f318b 100644 --- a/lib/GoogleSpreadsheetCell.js +++ b/lib/GoogleSpreadsheetCell.js @@ -174,21 +174,6 @@ class GoogleSpreadsheetCell { await this._sheet.saveUpdatedCells([this]); } - async createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId) { - return this._sheet._spreadsheet.createRangeDeveloperMetadata( - metadataKey, - metadataValue, - { - dimension: 'COLUMNS', - sheetId: this._sheet.sheetId, - startIndex: this._column, - endIndex: this._column + 1, - }, - visibility, - metadataId - ); - } - // used by worksheet when saving cells // returns an individual batchUpdate request to update the cell _getUpdateRequest() { diff --git a/lib/GoogleSpreadsheetRow.js b/lib/GoogleSpreadsheetRow.js index 8015347d..a1ff7603 100644 --- a/lib/GoogleSpreadsheetRow.js +++ b/lib/GoogleSpreadsheetRow.js @@ -67,21 +67,6 @@ class GoogleSpreadsheetRow { return result; } async del() { return this.delete(); } // alias to mimic old version of this module - - async createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId) { - return this._sheet._spreadsheet.createRangeDeveloperMetadata( - metadataKey, - metadataValue, - { - dimension: 'ROWS', - sheetId: this._sheet.sheetId, - startIndex: this._rowNumber, - endIndex: this._rowNumber + 1, - }, - visibility, - metadataId - ); - } } module.exports = GoogleSpreadsheetRow; diff --git a/lib/GoogleSpreadsheetWorksheet.js b/lib/GoogleSpreadsheetWorksheet.js index 345b5631..324e77c7 100644 --- a/lib/GoogleSpreadsheetWorksheet.js +++ b/lib/GoogleSpreadsheetWorksheet.js @@ -782,12 +782,9 @@ class GoogleSpreadsheetWorksheet { // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteBandingRequest } - async createDeveloperMetadata(metadataKey, metadataValue, visibility, metadataId) { + async createDeveloperMetadata() { // Request type = `createDeveloperMetadata` // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CreateDeveloperMetadataRequest - return this._spreadsheet.createSheetDeveloperMetadata( - metadataKey, metadataValue, this.sheetId, visibility, metadataId - ); } async updateDeveloperMetadata() {