google-sheets-mapper 1.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  MapperOptions,
3
3
  MapperState,
4
4
  ApiResponse,
@@ -6,83 +6,90 @@ import {
6
6
  SheetsResponse,
7
7
  SheetFromResponse,
8
8
  ValueRangesResponse,
9
- } from './types';
9
+ SheetsOption,
10
+ } from "./types";
10
11
 
11
- const GOOGLE_API_URL = 'https://sheets.googleapis.com/v4/spreadsheets';
12
+ const GOOGLE_API_URL = "https://sheets.googleapis.com/v4/spreadsheets";
12
13
 
13
- const getRanges = (sheetNames: MapperOptions['sheetsNames'] = []): string => {
14
+ const getRanges = (sheetNames: string[] = []): string => {
14
15
  // ranges=Sheet1&ranges=Sheet2
15
- return sheetNames.map((sheetName) => `ranges=${sheetName}`).join('&');
16
+ return sheetNames.map((sheetName) => `ranges=${sheetName}`).join("&");
16
17
  };
17
18
 
18
19
  const getSheetsTitleUrl = (sheetId: string, apiKey: string): string => {
19
20
  return `${GOOGLE_API_URL}/${sheetId}?fields=sheets%2Fproperties%2Ftitle&key=${apiKey}`;
20
21
  };
21
22
 
22
- const getBatchUrl = (
23
- sheetId: string,
24
- ranges: Array<string>,
25
- apiKey: string,
26
- ): string => {
23
+ const getBatchUrl = (sheetId: string, ranges: Array<string>, apiKey: string): string => {
27
24
  const rangesQueryString = getRanges(ranges);
28
25
 
29
- return `${GOOGLE_API_URL}/${sheetId}/values:batchGet?${rangesQueryString}&key=${apiKey}`;
26
+ return `${GOOGLE_API_URL}/${sheetId}?${rangesQueryString}&key=${apiKey}&includeGridData=true`;
30
27
  };
31
28
 
32
29
  class ApiResponseError extends Error {
33
- constructor(message: string, public readonly response: ApiResponse) {
30
+ response: ApiResponse;
31
+ constructor(message: string, response: ApiResponse) {
34
32
  super(message);
35
33
  Object.setPrototypeOf(this, ApiResponseError.prototype);
36
34
  this.response = response;
37
- Error.captureStackTrace(this, ApiResponseError);
35
+ if (Error.captureStackTrace) {
36
+ Error.captureStackTrace(this, ApiResponseError);
37
+ }
38
38
  }
39
39
  }
40
40
 
41
- const makeFetch = async (url: string, config = {}): Promise<any> => {
42
- try {
43
- const response = await fetch(url, config);
44
-
45
- if (!response.ok) {
46
- throw new ApiResponseError(
47
- `Request to '${url}' failed with ${response.status}${
48
- response.statusText ? `: ${response.statusText}` : ''
49
- }`,
50
- {
51
- status: response.status,
52
- statusText: response.statusText,
53
- url: response.url,
54
- },
55
- );
56
- }
57
-
58
- return await response.json();
59
- } catch (error) {
60
- console.error(error);
61
- throw error;
41
+ const makeFetch = async <T>(url: string, config = {}): Promise<T> => {
42
+ const response = await fetch(url, config);
43
+
44
+ if (!response.ok) {
45
+ throw new ApiResponseError(
46
+ `Request to '${url}' failed with ${response.status}${
47
+ response.statusText ? `: ${response.statusText}` : ""
48
+ }`,
49
+ {
50
+ status: response.status,
51
+ statusText: response.statusText,
52
+ url: response.url,
53
+ },
54
+ );
62
55
  }
56
+
57
+ return await response.json();
63
58
  };
64
59
 
65
60
  const mapRecords = (
66
- records: ValueRange['values'],
67
- headerData: Array<string>,
68
- ) => {
61
+ records: ValueRange["values"],
62
+ headerData: string[],
63
+ ): Record<string, string>[] => {
69
64
  return records
70
- .filter((record: Array<string>) => record.length > 0)
71
- .map((record: Array<string>) => {
72
- return record.reduce((obj: any, item: string, index: number) => {
73
- obj[headerData[index]] = item;
65
+ .filter((record: string[]) => record.length > 0)
66
+ .map((record: string[]) =>
67
+ record.reduce((obj: Record<string, string>, item: string, index: number) => {
68
+ const key = headerData[index];
69
+ if (key !== undefined) {
70
+ obj[key] = item;
71
+ }
74
72
  return obj;
75
- }, {});
76
- });
73
+ }, {}),
74
+ );
77
75
  };
78
76
 
79
- export const mapData = (sheets: ValueRange[]): MapperState[] => {
77
+ export const mapData = ({
78
+ sheets,
79
+ sheetsOptions = [],
80
+ }: {
81
+ sheets: ValueRange[];
82
+ sheetsOptions?: SheetsOption[];
83
+ }): MapperState[] => {
80
84
  return sheets.map((sheet: ValueRange) => {
81
- const id = sheet.range.split('!')[0].replace(/'/g, '');
85
+ const id = sheet.range.split("!")[0].replace(/'/g, "");
82
86
  const rows = sheet.values || [];
83
87
 
84
88
  if (rows.length > 0) {
85
- const [header, ...records] = rows;
89
+ const sheetsOptionsSheet = sheetsOptions.find((option: SheetsOption) => option.id === id);
90
+ const headerRowIndex = sheetsOptionsSheet?.headerRowIndex ?? 0;
91
+ const header = rows[headerRowIndex];
92
+ const records = rows.filter((_, index: number) => index > headerRowIndex);
86
93
  const recordsData = mapRecords(records, header);
87
94
 
88
95
  return {
@@ -101,8 +108,9 @@ export const mapData = (sheets: ValueRange[]): MapperState[] => {
101
108
  export const fetchBatchData = async ({
102
109
  apiKey,
103
110
  sheetId,
104
- sheetsNames = [],
111
+ sheetsOptions = [],
105
112
  }: MapperOptions): Promise<ValueRangesResponse> => {
113
+ const sheetsNames = sheetsOptions.map((option: SheetsOption) => option.id);
106
114
  const url = getBatchUrl(sheetId, sheetsNames, apiKey);
107
115
 
108
116
  return await makeFetch(url);
@@ -114,9 +122,9 @@ export const fetchAllSheetsData = async ({
114
122
  }: MapperOptions): Promise<ValueRangesResponse> => {
115
123
  const urlTitles = getSheetsTitleUrl(sheetId, apiKey);
116
124
  const { sheets }: SheetsResponse = await makeFetch(urlTitles);
117
- const sheetsNames = sheets.map(
118
- (sheet: SheetFromResponse) => sheet.properties.title,
119
- );
125
+ const sheetsOptions = sheets.map((sheet: SheetFromResponse) => ({
126
+ id: sheet.properties.title,
127
+ }));
120
128
 
121
- return await fetchBatchData({ sheetId, sheetsNames, apiKey });
129
+ return await fetchBatchData({ apiKey, sheetId, sheetsOptions });
122
130
  };