Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add data validation #691

Merged
merged 3 commits into from
May 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Full docs available at [https://theoephraim.github.io/node-google-spreadsheet](h

_The following examples are meant to give you an idea of just some of the things you can do_

> **IMPORTANT NOTE** - To keep the examples concise, I'm calling await [at the top level](https://v8.dev/features/top-level-await) which is not allowed by default in most versions of node. If you need to call await in a script at the root level, you must instead wrap it in an async function like so:
> **IMPORTANT NOTE** - To keep the examples concise, I'm calling await [at the top level](https://v8.dev/features/top-level-await) which is not allowed in some older versions of node. If you need to call await in a script at the root level and your environment does not support it, you must instead wrap it in an async function like so:

```javascript
(async function () {
Expand Down
18 changes: 18 additions & 0 deletions docs/classes/google-spreadsheet-worksheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,24 @@ Param|Type|Required|Description

?> The authentication method being used must have write access to the destination document as well


#### `setDataValidation(range, rule)` (async) :id=fn-setDataValidation
> Sets a data validation rule to every cell in the range

Param|Type|Required|Description
---|---|---|---
`range`|Object<br>[GridRange](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#GridRange)|✅|Range of cells to apply the rule to, sheetId not required!
`rule`|Object<br>[DataValidationRule](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/cells#DataValidationRule)<br>or `false`|✅|Object describing the validation rule<br/>Or `false` to unset the rule


- ✨ **Side Effects -** sheet is copied to the other doc

?> The authentication method being used must have write access to the destination document as well





### Exports

See [Exports guide](guides/exports) for more info.
Expand Down
20 changes: 16 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 17 additions & 3 deletions src/lib/GoogleSpreadsheetWorksheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
A1Range, SpreadsheetId, DimensionRangeIndexes, WorksheetDimension, WorksheetId, WorksheetProperties, A1Address,
RowIndex, ColumnIndex, DataFilterWithoutWorksheetId, DataFilter, GetValuesRequestOptions, WorksheetGridProperties,
WorksheetDimensionProperties, CellDataRange, AddRowOptions, GridRangeWithOptionalWorksheetId,
DataValidationRule,
} from './types/sheets-types';


Expand Down Expand Up @@ -819,9 +820,22 @@ export class GoogleSpreadsheetWorksheet {
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SortRangeRequest
}

async setDataValidation() {
// Request type = `setDataValidation`
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetDataValidationRequest
/**
* Sets (or unsets) a data validation rule to every cell in the range
* @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetDataValidationRequest
*/
async setDataValidation(
range: GridRangeWithOptionalWorksheetId,
/** data validation rule object, or set to false to clear an existing rule */
rule: DataValidationRule | false
) {
return this._makeSingleUpdateRequest('setDataValidation', {
range: {
sheetId: this.sheetId,
...range,
},
...rule && { rule },
});
}

async setBasicFilter() {
Expand Down
85 changes: 85 additions & 0 deletions src/lib/types/sheets-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,3 +526,88 @@ export type AddRowOptions = {
/** set to true to insert new rows in the sheet while adding this data */
insert?: boolean,
};

/**
* @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#ConditionType
*/
export type ConditionType =
| 'NUMBER_GREATER'
| 'NUMBER_GREATER_THAN_EQ'
| 'NUMBER_LESS'
| 'NUMBER_LESS_THAN_EQ'
| 'NUMBER_EQ'
| 'NUMBER_NOT_EQ'
| 'NUMBER_BETWEEN'
| 'NUMBER_NOT_BETWEEN'
| 'TEXT_CONTAINS'
| 'TEXT_NOT_CONTAINS'
| 'TEXT_STARTS_WITH'
| 'TEXT_ENDS_WITH'
| 'TEXT_EQ'
| 'TEXT_IS_EMAIL'
| 'TEXT_IS_URL'
| 'DATE_EQ'
| 'DATE_BEFORE'
| 'DATE_AFTER'
| 'DATE_ON_OR_BEFORE'
| 'DATE_ON_OR_AFTER'
| 'DATE_BETWEEN'
| 'DATE_NOT_BETWEEN'
| 'DATE_IS_VALID'
| 'ONE_OF_RANGE'
| 'ONE_OF_LIST'
| 'BLANK'
| 'NOT_BLANK'
| 'CUSTOM_FORMULA'
| 'BOOLEAN'
| 'TEXT_NOT_EQ'
| 'DATE_NOT_EQ'
| 'FILTER_EXPRESSION';

/**
* @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#relativedate
*/
export type RelativeDate =
| 'PAST_YEAR'
| 'PAST_MONTH'
| 'PAST_WEEK'
| 'YESTERDAY'
| 'TODAY'
| 'TOMORROW';

/**
* @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#ConditionValue
*/
export type ConditionValue =
| { relativeDate: RelativeDate, userEnteredValue?: undefined }
| { relativeDate?: undefined, userEnteredValue: string };

/**
* @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#BooleanCondition
*/
export type BooleanCondition = {
/** The type of condition. */
type: ConditionType;
/**
* The values of the condition.
* The number of supported values depends on the condition type. Some support zero values, others one or two values, and ConditionType.ONE_OF_LIST supports an arbitrary number of values.
*/
values: ConditionValue[];
};

/**
* @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/cells#DataValidationRule
*
* example:
* - https://stackoverflow.com/a/43442775/3068233
*/
export type DataValidationRule = {
/** The condition that data in the cell must match. */
condition: BooleanCondition;
/** A message to show the user when adding data to the cell. */
inputMessage?: string;
/** True if invalid data should be rejected. */
strict: boolean;
/** True if the UI should be customized based on the kind of condition. If true, "List" conditions will show a dropdown. */
showCustomUi: boolean;
};
54 changes: 54 additions & 0 deletions src/test/manage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,60 @@ describe('Managing doc info and sheets', () => {
});
});

describe.only('data validation rules', () => {
let sheet: GoogleSpreadsheetWorksheet;

beforeAll(async () => {
sheet = await doc.addSheet({ title: 'validation rules test' });
});
afterAll(async () => {
await sheet.delete();
});


it('can set data validation', async () => {
// add a dropdown; ref: https://stackoverflow.com/a/43442775/3068233
await sheet.setDataValidation(
{
startRowIndex: 2,
endRowIndex: 100,
startColumnIndex: 3,
endColumnIndex: 4,
},
{
condition: {
type: 'ONE_OF_LIST',
values: [
{
userEnteredValue: 'YES',
},
{
userEnteredValue: 'NO',
},
{
userEnteredValue: 'MAYBE',
},
],
},
showCustomUi: true,
strict: true,
}
);
});

it('can clear a data validation', async () => {
await sheet.setDataValidation(
{
startRowIndex: 2,
endRowIndex: 100,
startColumnIndex: 3,
endColumnIndex: 4,
},
false
);
});
});

describe('deleting a sheet', () => {
let sheet: GoogleSpreadsheetWorksheet;
let numSheets: number;
Expand Down