diff --git a/README.md b/README.md index d905678..42bba3b 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,35 @@ Cleared data will look like this: A5B5C5D5 +#### Special Features +When getting data you can set `firstRowAsHeader` as true to get data formatted as object with keys from first row. You can do it in constructor or in `get` method. + +Example normal response: +```typescript +[ + ["A1", "B1", "C1", "D1"], + ["A2", "B2", "C2", "D2"], + ["A3", "B3", "C3", "D3"], +] +``` +Response with firstRowAsHeader set to true +```typescript +[ + { + A1: "A2", + B1: "B2", + C1: "C2", + D1: "D2", + }, + { + A1: "A3", + B1: "B3", + C1: "C3", + D1: "D3", + }, +] +``` + # Development setup ### Install dependencies @@ -168,4 +197,4 @@ npm run test Compiled JavaScript will be placed in `/build` folder. -_Made by Michał Szajner_ \ No newline at end of file +_Made by [Michał Szajner](https://github.com/M1chalS)_ \ No newline at end of file diff --git a/package.json b/package.json index a7e97fc..503793a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sheets-simplified", - "version": "1.0.0", + "version": "1.0.1", "description": "TypeScript classes based package that eases and increases safety of working with Google Sheets API v4.", "main": "./build/index.js", "types": "./build/index.d.ts", diff --git a/src/config/configurations.ts b/src/config/configurations.ts index 45001c5..57f6ff9 100644 --- a/src/config/configurations.ts +++ b/src/config/configurations.ts @@ -6,6 +6,7 @@ export interface GetRequestConfiguration { majorDimension?: Dimension; valueRenderOption?: ValueRenderOption; dateTimeRenderOption?: DateTimeRenderOption; + firstRowAsHeader?: boolean; } export interface AppendRequestConfiguration { @@ -45,4 +46,5 @@ export interface Configuration { includeValuesInResponse?: boolean; responseDateTimeRenderOption?: DateTimeRenderOption; responseValueRenderOption?: ValueRenderOption; + firstRowAsHeader?: boolean; } diff --git a/src/index.ts b/src/index.ts index 396c090..2657088 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,3 @@ export * from "./auth/google-sheets-auth"; -export * from "./sheets/sheets-connection"; \ No newline at end of file +export * from "./sheets/sheets-connection" +export * from "./types/types"; \ No newline at end of file diff --git a/src/response-formatter/response-formatter.ts b/src/response-formatter/response-formatter.ts new file mode 100644 index 0000000..4792936 --- /dev/null +++ b/src/response-formatter/response-formatter.ts @@ -0,0 +1,16 @@ +export const responseFormatter = (res: any) => { + const {data, ...rest } = res; + + data.values = data.values.map((row: any[], index: number) => { + const newRow: any = {}; + row.forEach((value: any, index: number) => { + newRow[data.values[0][index]] = value; + }); + return newRow; + }).filter((val: any[], index: number) => index !== 0); + + return { + data, + ...rest + } +}; \ No newline at end of file diff --git a/src/sheets/__tests__/sheets-connection.test.ts b/src/sheets/__tests__/sheets-connection.test.ts index 3d83826..8652fbe 100644 --- a/src/sheets/__tests__/sheets-connection.test.ts +++ b/src/sheets/__tests__/sheets-connection.test.ts @@ -222,4 +222,111 @@ describe('Range logic checks', () => { await expect(sheetsConnection.get({sheet: "Sheet2"})).rejects.toThrowError("Specify range or sheet in method or in constructor"); }); +}); + +describe('Response formatter checks', () => { + + test('Expect response to not be formatted', async () => { + const sheetsConnection = new SheetsConnection({ + spreadsheetId: process.env.SHEET_ID!, + auth: googleAuthWrapper, + sheet: "Sheet1", + range: "A1:B" + }); + + await sheetsConnection.append([[ + "test1", + "test2" + ], [ + "test3", + "test4" + ]]); + + const res = await sheetsConnection.get(); + + expect(res.data.values[0][0] === "test1").toBeTruthy(); + expect(res.data.values[0][1] === "test2").toBeTruthy(); + expect(res.data.values[1][0] === "test3").toBeTruthy(); + expect(res.data.values[1][1] === "test4").toBeTruthy(); + + await sheetsConnection.clear(); + }); + + test('Expect response to be formatted (set in constructor)', async () => { + const sheetsConnection = new SheetsConnection({ + spreadsheetId: process.env.SHEET_ID!, + auth: googleAuthWrapper, + sheet: "Sheet1", + range: "A1:B", + firstRowAsHeader: true + }); + + await sheetsConnection.append([[ + "test1", + "test2" + ], [ + "test3", + "test4" + ]]); + + const res = await sheetsConnection.get(); + + expect(res.data.values[0].test1 === "test3").toBeTruthy(); + expect(res.data.values[0].test2 === "test4").toBeTruthy(); + + await sheetsConnection.clear(); + }); + + test('Expect response to be formatted (set in method)', async () => { + const sheetsConnection = new SheetsConnection({ + spreadsheetId: process.env.SHEET_ID!, + auth: googleAuthWrapper, + sheet: "Sheet1", + range: "A1:B", + }); + + await sheetsConnection.append([[ + "test1", + "test2" + ], [ + "test3", + "test4" + ]]); + + const res = await sheetsConnection.get({ + firstRowAsHeader: true + }); + + expect(res.data.values[0].test1 === "test3").toBeTruthy(); + expect(res.data.values[0].test2 === "test4").toBeTruthy(); + + await sheetsConnection.clear(); + }); + + test('Expect response to be formatted (set in both)', async () => { + const sheetsConnection = new SheetsConnection({ + spreadsheetId: process.env.SHEET_ID!, + auth: googleAuthWrapper, + sheet: "Sheet1", + range: "A1:B", + firstRowAsHeader: true + }); + + await sheetsConnection.append([[ + "test1", + "test2" + ], [ + "test3", + "test4" + ]]); + + const res = await sheetsConnection.get({ + firstRowAsHeader: true + }); + + expect(res.data.values[0].test1 === "test3").toBeTruthy(); + expect(res.data.values[0].test2 === "test4").toBeTruthy(); + + await sheetsConnection.clear(); + }); }); \ No newline at end of file diff --git a/src/sheets/sheets-connection.ts b/src/sheets/sheets-connection.ts index 0b34d6f..07174b7 100644 --- a/src/sheets/sheets-connection.ts +++ b/src/sheets/sheets-connection.ts @@ -8,6 +8,7 @@ import { GetRequestConfiguration, UpdateRequestConfiguration } from "../config/configurations"; +import {responseFormatter} from "../response-formatter/response-formatter"; export class SheetsConnection { private sheets: sheets_v4.Sheets = google.sheets("v4"); @@ -24,6 +25,7 @@ export class SheetsConnection { private readonly includeValuesInResponse: boolean; private readonly responseDateTimeRenderOption: DateTimeRenderOption; private readonly responseValueRenderOption: ValueRenderOption; + private readonly firstRowAsHeader: boolean; public constructor(cfg: Configuration) { this.spreadsheetId = cfg.spreadsheetId; @@ -38,6 +40,7 @@ export class SheetsConnection { this.includeValuesInResponse = cfg.includeValuesInResponse ?? false; this.responseDateTimeRenderOption = cfg.responseDateTimeRenderOption ?? DateTimeRenderOption.FORMATTED_STRING; this.responseValueRenderOption = cfg.responseValueRenderOption ?? ValueRenderOption.FORMATTED_VALUE; + this.firstRowAsHeader = cfg.firstRowAsHeader ?? false; if (this.sheet && this.range) { this.sheetRange = `${this.sheet}!${this.range}`; @@ -47,7 +50,9 @@ export class SheetsConnection { } public get = async (cfg?: GetRequestConfiguration) => { - return await this.sheets.spreadsheets.values.get(this.getRequestPayload(cfg)); + const res = await this.sheets.spreadsheets.values.get(this.getRequestPayload(cfg)); + + return (this.firstRowAsHeader || cfg?.firstRowAsHeader) ? responseFormatter(res) : res; }; public append = async (data: any[], cfg?: AppendRequestConfiguration) => {