bodevops-features 1.0.0 → 1.0.8
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/README.md +699 -10
- package/dist/cjs/index.js +1702 -5
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +1681 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/types/gg-drive/config.d.ts +66 -0
- package/dist/types/gg-drive/google-drive.d.ts +214 -0
- package/dist/types/gg-drive/index.d.ts +29 -1
- package/dist/types/gg-drive/types.d.ts +176 -0
- package/dist/types/gg-drive/utils.d.ts +111 -0
- package/dist/types/gg-sheet/config.d.ts +65 -0
- package/dist/types/gg-sheet/google-sheet.d.ts +255 -0
- package/dist/types/gg-sheet/index.d.ts +35 -0
- package/dist/types/gg-sheet/types.d.ts +250 -0
- package/dist/types/gg-sheet/utils.d.ts +172 -0
- package/dist/types/index.d.ts +21 -0
- package/package.json +50 -44
package/README.md
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# BoDevOps Features
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A collection of framework-agnostic TypeScript utilities for Google Drive, Google Sheets, and iDrive e2 operations.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/bodevops-features)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🚀 **Framework-agnostic** - Works with any TypeScript/JavaScript project
|
|
11
|
+
- 📦 **Tree-shakeable** - Import only what you need
|
|
12
|
+
- 🔒 **Type-safe** - Full TypeScript support with no `any` types
|
|
13
|
+
- 📚 **Well-documented** - Comprehensive JSDoc comments in English
|
|
14
|
+
- ✨ **Easy to use** - Clean, intuitive API design
|
|
4
15
|
|
|
5
16
|
## Installation
|
|
6
17
|
|
|
@@ -8,21 +19,699 @@ BoDevOps features library - a collection of utilities for Google Drive, Google S
|
|
|
8
19
|
npm install bodevops-features
|
|
9
20
|
```
|
|
10
21
|
|
|
11
|
-
##
|
|
22
|
+
## Modules
|
|
23
|
+
|
|
24
|
+
### 🗂️ Google Drive (`GGDrive`)
|
|
25
|
+
|
|
26
|
+
Manage files and folders in Google Drive with ease.
|
|
27
|
+
|
|
28
|
+
**Features:**
|
|
29
|
+
|
|
30
|
+
- Upload files to Drive
|
|
31
|
+
- Create folder hierarchies
|
|
32
|
+
- Share files and folders
|
|
33
|
+
- Transfer ownership
|
|
34
|
+
- Get storage quota information
|
|
35
|
+
- List files in folders
|
|
36
|
+
- Delete files
|
|
37
|
+
|
|
38
|
+
### 📊 Google Sheets (`GGSheet`)
|
|
39
|
+
|
|
40
|
+
Read, write, and manage Google Spreadsheet data.
|
|
41
|
+
|
|
42
|
+
**Features:**
|
|
43
|
+
|
|
44
|
+
- Read sheet data
|
|
45
|
+
- Export data (Append/Overwrite modes)
|
|
46
|
+
- Update cells, rows, and columns
|
|
47
|
+
- Find row by value
|
|
48
|
+
- Delete rows
|
|
49
|
+
- Convert sheet data to typed objects
|
|
50
|
+
- Column name/index conversion utilities
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
### Google Drive
|
|
12
57
|
|
|
13
58
|
```typescript
|
|
14
59
|
import { GGDrive } from 'bodevops-features';
|
|
15
60
|
|
|
16
|
-
//
|
|
17
|
-
GGDrive.
|
|
61
|
+
// Initialize client
|
|
62
|
+
const driveClient = new GGDrive.GoogleDriveClient({
|
|
63
|
+
keyFilePath: './service-account.json',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Get storage information
|
|
67
|
+
const storage = await driveClient.getStorageInfo();
|
|
68
|
+
console.log(`Used: ${storage.formattedUsed} / ${storage.formattedTotal}`);
|
|
69
|
+
|
|
70
|
+
// Upload a file
|
|
71
|
+
const result = await driveClient.uploadFile({
|
|
72
|
+
localFilePath: './document.pdf',
|
|
73
|
+
driveFolder: 'MyFolder/SubFolder',
|
|
74
|
+
fileName: 'uploaded-document.pdf',
|
|
75
|
+
});
|
|
76
|
+
console.log(`View at: ${result.webViewLink}`);
|
|
77
|
+
|
|
78
|
+
// Upload and share with someone
|
|
79
|
+
const sharedResult = await driveClient.uploadFileAndShare({
|
|
80
|
+
localFilePath: './report.pdf',
|
|
81
|
+
driveFolder: 'SharedReports',
|
|
82
|
+
shareWithEmail: 'colleague@example.com',
|
|
83
|
+
role: 'writer',
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// List files in a folder
|
|
87
|
+
const files = await driveClient.listFilesInFolder({ folderId: 'root' });
|
|
88
|
+
for (const file of files) {
|
|
89
|
+
console.log(`${file.name} (${file.mimeType})`);
|
|
90
|
+
}
|
|
18
91
|
```
|
|
19
92
|
|
|
20
|
-
|
|
93
|
+
### Google Sheets
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { GGSheet } from 'bodevops-features';
|
|
97
|
+
|
|
98
|
+
// Initialize client
|
|
99
|
+
const sheetClient = new GGSheet.GoogleSheetClient({
|
|
100
|
+
keyFilePath: './service-account.json',
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Read data from a sheet
|
|
104
|
+
const data = await sheetClient.getValues({
|
|
105
|
+
sheetUrl: 'https://docs.google.com/spreadsheets/d/1abc123...',
|
|
106
|
+
sheetName: 'Sheet1',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Convert to typed objects
|
|
110
|
+
interface Person {
|
|
111
|
+
name: string;
|
|
112
|
+
email: string;
|
|
113
|
+
age: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const people = GGSheet.convertValueSheet<Person>({
|
|
117
|
+
values: data,
|
|
118
|
+
rowOffset: 0, // First row is header
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Export data (Overwrite mode)
|
|
122
|
+
await sheetClient.export({
|
|
123
|
+
sheetUrl: 'https://docs.google.com/spreadsheets/d/1abc123...',
|
|
124
|
+
sheetName: 'Sheet1',
|
|
125
|
+
listCols: ['Name', 'Email', 'Age'],
|
|
126
|
+
valsExport: [
|
|
127
|
+
['John Doe', 'john@example.com', '30'],
|
|
128
|
+
['Jane Smith', 'jane@example.com', '25'],
|
|
129
|
+
],
|
|
130
|
+
typeExport: GGSheet.ETypeExport.Overwrite,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Update specific cells
|
|
134
|
+
await sheetClient.updateValuesMultiCells({
|
|
135
|
+
sheetUrl: 'https://docs.google.com/spreadsheets/d/1abc123...',
|
|
136
|
+
sheetName: 'Sheet1',
|
|
137
|
+
cells: [
|
|
138
|
+
{ row: 0, col: 0, content: 'Updated Value' },
|
|
139
|
+
{ row: 1, col: 1, content: 'Another Update' },
|
|
140
|
+
],
|
|
141
|
+
rowOffset: 0,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Find a row by value
|
|
145
|
+
const rowIndex = await sheetClient.getIdxRow({
|
|
146
|
+
sheetUrl: 'https://docs.google.com/spreadsheets/d/1abc123...',
|
|
147
|
+
sheetName: 'Sheet1',
|
|
148
|
+
colName: 'A',
|
|
149
|
+
value: 'John Doe',
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Authentication
|
|
156
|
+
|
|
157
|
+
Both Google Drive and Google Sheets require a Google Service Account for authentication.
|
|
158
|
+
|
|
159
|
+
### Creating a Service Account
|
|
160
|
+
|
|
161
|
+
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
|
162
|
+
2. Create a new project or select an existing one
|
|
163
|
+
3. Enable the Google Drive API and Google Sheets API
|
|
164
|
+
4. Create a Service Account:
|
|
165
|
+
- Go to "IAM & Admin" → "Service Accounts"
|
|
166
|
+
- Click "Create Service Account"
|
|
167
|
+
- Fill in the details and create
|
|
168
|
+
5. Create a JSON key:
|
|
169
|
+
- Click on the created service account
|
|
170
|
+
- Go to "Keys" tab
|
|
171
|
+
- Click "Add Key" → "Create new key"
|
|
172
|
+
- Select "JSON" and download
|
|
173
|
+
|
|
174
|
+
### Using Credentials
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
// Option 1: Using key file path
|
|
178
|
+
const client = new GGDrive.GoogleDriveClient({
|
|
179
|
+
keyFilePath: './service-account.json',
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Option 2: Using credentials object
|
|
183
|
+
const client = new GGDrive.GoogleDriveClient({
|
|
184
|
+
credentials: {
|
|
185
|
+
type: 'service_account',
|
|
186
|
+
project_id: 'your-project-id',
|
|
187
|
+
private_key: '-----BEGIN PRIVATE KEY-----\n...',
|
|
188
|
+
client_email: 'service-account@project.iam.gserviceaccount.com',
|
|
189
|
+
// ... other fields
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## API Reference
|
|
197
|
+
|
|
198
|
+
### Google Drive
|
|
199
|
+
|
|
200
|
+
#### `GoogleDriveClient`
|
|
201
|
+
|
|
202
|
+
**Constructor:**
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
new GoogleDriveClient(config: IGoogleDriveConfig)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Methods:**
|
|
209
|
+
|
|
210
|
+
| Method | Description |
|
|
211
|
+
| ------------------------------- | ----------------------------------- |
|
|
212
|
+
| `getStorageInfo()` | Get Drive storage quota information |
|
|
213
|
+
| `uploadFile(params)` | Upload a file to Drive |
|
|
214
|
+
| `uploadFileAndShare(params)` | Upload and share with email |
|
|
215
|
+
| `deleteFile(params)` | Delete a file from Drive |
|
|
216
|
+
| `listFilesInFolder(params)` | List files in a folder |
|
|
217
|
+
| `makeFilePublic(params)` | Make file accessible via link |
|
|
218
|
+
| `transferFileOwnership(params)` | Transfer file to another user |
|
|
219
|
+
| `shareFolderWithEmail(params)` | Share folder with permissions |
|
|
220
|
+
| `getFolderIdByPath(params)` | Get folder ID from path string |
|
|
221
|
+
| `fileExistsInFolder(params)` | Check if file exists |
|
|
222
|
+
|
|
223
|
+
**Utility Functions:**
|
|
224
|
+
|
|
225
|
+
- `formatBytes({ bytes })` - Convert bytes to human-readable format
|
|
226
|
+
- `normalizeFilePath({ filePath })` - Normalize file path
|
|
227
|
+
- `validateFileExists({ filePath })` - Check if file exists
|
|
228
|
+
- `getFileInfo({ filePath })` - Get file metadata
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
### Google Sheets
|
|
233
|
+
|
|
234
|
+
#### `GoogleSheetClient`
|
|
235
|
+
|
|
236
|
+
**Constructor:**
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
new GoogleSheetClient(config: IGoogleSheetConfig)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Methods:**
|
|
243
|
+
|
|
244
|
+
| Method | Description |
|
|
245
|
+
| ---------------------------------------- | ------------------------------ |
|
|
246
|
+
| `getSheetInfo(params)` | Get spreadsheet metadata |
|
|
247
|
+
| `getValues(params)` | Read all values from sheet |
|
|
248
|
+
| `getIdxRow(params)` | Find row index by value |
|
|
249
|
+
| `export(params)` | Export data (Append/Overwrite) |
|
|
250
|
+
| `updateValuesMultiCells(params)` | Update specific cells |
|
|
251
|
+
| `updateValuesMultiColsByRow(params)` | Update columns in a row |
|
|
252
|
+
| `updateValuesMultiRowsByCol(params)` | Update rows in a column |
|
|
253
|
+
| `updateValuesMultiRowsMultiCols(params)` | Batch update range |
|
|
254
|
+
| `deleteRowSheet(params)` | Delete a row |
|
|
255
|
+
|
|
256
|
+
**Utility Functions:**
|
|
257
|
+
|
|
258
|
+
- `convertIndexToColumnName({ columnIndex })` - Convert 0 → "A", 26 → "AA"
|
|
259
|
+
- `convertColumnNameToIndex({ columnName })` - Convert "A" → 0, "AA" → 26
|
|
260
|
+
- `convertValueSheet({ values, rowOffset })` - Parse sheet to typed objects
|
|
261
|
+
- `getSheetIdFromUrl({ sheetUrl })` - Extract spreadsheet ID
|
|
262
|
+
- `calculateActualRow({ dataRowIndex, rowOffset })` - Calculate sheet row number
|
|
263
|
+
|
|
264
|
+
**Enums:**
|
|
265
|
+
|
|
266
|
+
- `ETypeExport.Append` - Append data to existing
|
|
267
|
+
- `ETypeExport.Overwrite` - Replace all data
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Advanced Examples
|
|
272
|
+
|
|
273
|
+
### Google Drive: Batch Upload with Progress
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
const files = ['file1.pdf', 'file2.pdf', 'file3.pdf'];
|
|
277
|
+
|
|
278
|
+
for (const file of files) {
|
|
279
|
+
const result = await driveClient.uploadFile({
|
|
280
|
+
localFilePath: `./documents/${file}`,
|
|
281
|
+
driveFolder: 'Uploads/2024',
|
|
282
|
+
fileName: file,
|
|
283
|
+
});
|
|
284
|
+
console.log(`✓ Uploaded: ${result.name}`);
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Google Sheets: Export Database Query Results
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { GGSheet } from 'bodevops-features';
|
|
292
|
+
|
|
293
|
+
// Assume you have query results
|
|
294
|
+
const users = await database.query('SELECT name, email, created_at FROM users');
|
|
295
|
+
|
|
296
|
+
// Map to column definitions
|
|
297
|
+
const colsMapping = {
|
|
298
|
+
name: 'Full Name',
|
|
299
|
+
email: 'Email Address',
|
|
300
|
+
created_at: 'Registration Date',
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
// Extract columns and values
|
|
304
|
+
const { listCols, valsExport } = GGSheet.getListColsAndValsExport({
|
|
305
|
+
colsForSheet: colsMapping,
|
|
306
|
+
resultItems: users,
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// Export to sheet
|
|
310
|
+
await sheetClient.export({
|
|
311
|
+
sheetUrl: 'https://docs.google.com/spreadsheets/d/...',
|
|
312
|
+
sheetName: 'Users',
|
|
313
|
+
listCols,
|
|
314
|
+
valsExport,
|
|
315
|
+
typeExport: GGSheet.ETypeExport.Overwrite,
|
|
316
|
+
});
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Google Sheets: Update Multiple Rows
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
// Update column C for rows 0-4
|
|
323
|
+
await sheetClient.updateValuesMultiRowsByCol({
|
|
324
|
+
sheetUrl: 'https://docs.google.com/spreadsheets/d/...',
|
|
325
|
+
sheetName: 'Sheet1',
|
|
326
|
+
col: 2, // Column C (0-based)
|
|
327
|
+
values: [
|
|
328
|
+
{ row: 0, content: 'Status: Complete' },
|
|
329
|
+
{ row: 1, content: 'Status: Pending' },
|
|
330
|
+
{ row: 2, content: 'Status: Complete' },
|
|
331
|
+
{ row: 3, content: 'Status: Failed' },
|
|
332
|
+
{ row: 4, content: 'Status: Complete' },
|
|
333
|
+
],
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Google Sheets Update & Delete Methods - Detailed Guide
|
|
340
|
+
|
|
341
|
+
### 📝 Understanding `rowOffset`
|
|
342
|
+
|
|
343
|
+
All update and delete methods support a `rowOffset` parameter to handle different sheet structures:
|
|
344
|
+
|
|
345
|
+
- **`rowOffset: 0`** (default): Header at row 1, data starts at row 2
|
|
346
|
+
- **`rowOffset: 1`**: Header at row 1, skip row 2, data starts at row 3
|
|
347
|
+
- **`rowOffset: 2`**: Header at row 1, skip rows 2-3, data starts at row 4
|
|
348
|
+
|
|
349
|
+
**Example Sheet Structure:**
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
Row 1: [Name, Email, Status] ← Header
|
|
353
|
+
Row 2: [John, john@example.com, Active] ← Data row 0 (with rowOffset=0)
|
|
354
|
+
Row 3: [Jane, jane@example.com, Pending] ← Data row 1 (with rowOffset=0)
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
### 1️⃣ `updateValuesMultiCells()` - Update Specific Cells
|
|
360
|
+
|
|
361
|
+
Update multiple cells at specific row and column positions.
|
|
362
|
+
|
|
363
|
+
**Use Case:** Update scattered cells across the sheet
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
await sheetClient.updateValuesMultiCells({
|
|
367
|
+
sheetUrl: 'https://docs.google.com/spreadsheets/d/...',
|
|
368
|
+
sheetName: 'Sheet1',
|
|
369
|
+
cells: [
|
|
370
|
+
{ row: 0, col: 0, content: 'John Doe' }, // A2
|
|
371
|
+
{ row: 0, col: 2, content: 'Active' }, // C2
|
|
372
|
+
{ row: 1, col: 1, content: 'jane@new.com' }, // B3
|
|
373
|
+
{ row: 5, col: 3, content: 'Updated' }, // D7
|
|
374
|
+
],
|
|
375
|
+
rowOffset: 0, // Optional, default is 0
|
|
376
|
+
});
|
|
377
|
+
```
|
|
21
378
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
379
|
+
**Parameters:**
|
|
380
|
+
|
|
381
|
+
- `cells`: Array of `{ row, col, content }` objects
|
|
382
|
+
- `row`: 0-based data row index
|
|
383
|
+
- `col`: 0-based column index (0=A, 1=B, 2=C, ...)
|
|
384
|
+
- `content`: String value to write
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
### 2️⃣ `updateValuesMultiColsByRow()` - Update Multiple Columns in One Row
|
|
389
|
+
|
|
390
|
+
Update several columns in a single row.
|
|
391
|
+
|
|
392
|
+
**Use Case:** Update a complete user record
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
// Update row 3 (data row index 2) - columns A, B, C
|
|
396
|
+
await sheetClient.updateValuesMultiColsByRow({
|
|
397
|
+
sheetUrl: 'https://docs.google.com/spreadsheets/d/...',
|
|
398
|
+
sheetName: 'Users',
|
|
399
|
+
row: 2, // Data row index (actual sheet row 4 with rowOffset=0)
|
|
400
|
+
values: [
|
|
401
|
+
{ col: 0, content: 'Updated Name' }, // Column A
|
|
402
|
+
{ col: 1, content: 'new@email.com' }, // Column B
|
|
403
|
+
{ col: 2, content: 'Active' }, // Column C
|
|
404
|
+
{ col: 4, content: '2026-01-07' }, // Column E
|
|
405
|
+
],
|
|
406
|
+
rowOffset: 0,
|
|
407
|
+
});
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
**Real-world Example:**
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
// Update user status and last login
|
|
414
|
+
await sheetClient.updateValuesMultiColsByRow({
|
|
415
|
+
sheetUrl: SHEET_URL,
|
|
416
|
+
sheetName: 'Users',
|
|
417
|
+
row: userId,
|
|
418
|
+
values: [
|
|
419
|
+
{ col: 5, content: 'Online' }, // Status column
|
|
420
|
+
{ col: 6, content: new Date().toISOString() }, // Last login column
|
|
421
|
+
],
|
|
422
|
+
});
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
### 3️⃣ `updateValuesMultiRowsByCol()` - Update Multiple Rows in One Column
|
|
428
|
+
|
|
429
|
+
Update several rows in a single column.
|
|
430
|
+
|
|
431
|
+
**Use Case:** Batch update status for multiple items
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
// Update status column (C) for multiple rows
|
|
435
|
+
await sheetClient.updateValuesMultiRowsByCol({
|
|
436
|
+
sheetUrl: 'https://docs.google.com/spreadsheets/d/...',
|
|
437
|
+
sheetName: 'Tasks',
|
|
438
|
+
col: 2, // Column C (0-based)
|
|
439
|
+
values: [
|
|
440
|
+
{ row: 0, content: 'Completed' },
|
|
441
|
+
{ row: 1, content: 'In Progress' },
|
|
442
|
+
{ row: 2, content: 'Completed' },
|
|
443
|
+
{ row: 5, content: 'Pending' },
|
|
444
|
+
{ row: 8, content: 'Completed' },
|
|
445
|
+
],
|
|
446
|
+
rowOffset: 0,
|
|
447
|
+
});
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
**Real-world Example:**
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
// Mark all selected tasks as completed
|
|
454
|
+
const completedTaskIds = [0, 3, 5, 7];
|
|
455
|
+
|
|
456
|
+
await sheetClient.updateValuesMultiRowsByCol({
|
|
457
|
+
sheetUrl: SHEET_URL,
|
|
458
|
+
sheetName: 'Tasks',
|
|
459
|
+
col: 3, // Status column
|
|
460
|
+
values: completedTaskIds.map((taskId) => ({
|
|
461
|
+
row: taskId,
|
|
462
|
+
content: 'Completed ✓',
|
|
463
|
+
})),
|
|
464
|
+
});
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
### 4️⃣ `updateValuesMultiRowsMultiCols()` - Batch Update a Range
|
|
470
|
+
|
|
471
|
+
Update a rectangular range of cells (multiple rows and columns).
|
|
472
|
+
|
|
473
|
+
**Use Case:** Update a table section or paste data block
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
// Update a 3x3 range starting at row 0, column 0
|
|
477
|
+
await sheetClient.updateValuesMultiRowsMultiCols({
|
|
478
|
+
sheetUrl: 'https://docs.google.com/spreadsheets/d/...',
|
|
479
|
+
sheetName: 'Data',
|
|
480
|
+
values: [
|
|
481
|
+
['A1', 'B1', 'C1'],
|
|
482
|
+
['A2', 'B2', 'C2'],
|
|
483
|
+
['A3', 'B3', 'C3'],
|
|
484
|
+
],
|
|
485
|
+
startRow: 0, // Start at data row 0 (sheet row 2)
|
|
486
|
+
startCol: 0, // Start at column A
|
|
487
|
+
rowOffset: 0,
|
|
488
|
+
});
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
**Advanced Example with Custom Range:**
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
// Update columns D-F (indices 3-5) for rows 10-15
|
|
495
|
+
await sheetClient.updateValuesMultiRowsMultiCols({
|
|
496
|
+
sheetUrl: SHEET_URL,
|
|
497
|
+
sheetName: 'Report',
|
|
498
|
+
values: [
|
|
499
|
+
['Q1', '1000', '95%'],
|
|
500
|
+
['Q2', '1200', '98%'],
|
|
501
|
+
['Q3', '1100', '96%'],
|
|
502
|
+
['Q4', '1300', '99%'],
|
|
503
|
+
],
|
|
504
|
+
startRow: 10, // Data row 10
|
|
505
|
+
endRow: 13, // Data row 13 (4 rows total)
|
|
506
|
+
startCol: 3, // Column D
|
|
507
|
+
rowOffset: 0,
|
|
508
|
+
});
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Paste Clipboard Data:**
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
// Paste a copied table from Excel/Sheets
|
|
515
|
+
const clipboardData = [
|
|
516
|
+
['Product', 'Price', 'Stock'],
|
|
517
|
+
['Item A', '100', '50'],
|
|
518
|
+
['Item B', '200', '30'],
|
|
519
|
+
['Item C', '150', '40'],
|
|
520
|
+
];
|
|
521
|
+
|
|
522
|
+
await sheetClient.updateValuesMultiRowsMultiCols({
|
|
523
|
+
sheetUrl: SHEET_URL,
|
|
524
|
+
sheetName: 'Inventory',
|
|
525
|
+
values: clipboardData,
|
|
526
|
+
startRow: 0,
|
|
527
|
+
startCol: 0,
|
|
528
|
+
});
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
### 5️⃣ `deleteRowSheet()` - Delete a Row
|
|
534
|
+
|
|
535
|
+
Delete a specific row from the sheet.
|
|
536
|
+
|
|
537
|
+
**Use Case:** Remove a record from the sheet
|
|
538
|
+
|
|
539
|
+
```typescript
|
|
540
|
+
// Delete data row 5 (actual sheet row 7 with rowOffset=0)
|
|
541
|
+
await sheetClient.deleteRowSheet({
|
|
542
|
+
sheetUrl: 'https://docs.google.com/spreadsheets/d/...',
|
|
543
|
+
sheetName: 'Users',
|
|
544
|
+
row: 5, // Data row index
|
|
545
|
+
rowOffset: 0,
|
|
546
|
+
});
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
**Real-world Example:**
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
// Delete user by finding their row first
|
|
553
|
+
const userEmail = 'user@example.com';
|
|
554
|
+
|
|
555
|
+
// Find the row
|
|
556
|
+
const rowIndex = await sheetClient.getIdxRow({
|
|
557
|
+
sheetUrl: SHEET_URL,
|
|
558
|
+
sheetName: 'Users',
|
|
559
|
+
colName: 'B', // Email column
|
|
560
|
+
value: userEmail,
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
if (rowIndex >= 0) {
|
|
564
|
+
// Delete the row
|
|
565
|
+
await sheetClient.deleteRowSheet({
|
|
566
|
+
sheetUrl: SHEET_URL,
|
|
567
|
+
sheetName: 'Users',
|
|
568
|
+
row: rowIndex,
|
|
569
|
+
});
|
|
570
|
+
console.log(`Deleted user: ${userEmail}`);
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
**⚠️ Important Notes:**
|
|
575
|
+
|
|
576
|
+
- Deleting a row shifts all rows below it up by one
|
|
577
|
+
- The row index is 0-based for data rows (excluding header)
|
|
578
|
+
- Cannot be undone - use with caution!
|
|
579
|
+
|
|
580
|
+
---
|
|
581
|
+
|
|
582
|
+
### 🎯 Method Selection Guide
|
|
583
|
+
|
|
584
|
+
| Scenario | Recommended Method |
|
|
585
|
+
| ----------------------------------- | ---------------------------------- |
|
|
586
|
+
| Update 1-2 specific cells | `updateValuesMultiCells()` |
|
|
587
|
+
| Update entire user record (one row) | `updateValuesMultiColsByRow()` |
|
|
588
|
+
| Batch update status column | `updateValuesMultiRowsByCol()` |
|
|
589
|
+
| Update a table section/range | `updateValuesMultiRowsMultiCols()` |
|
|
590
|
+
| Remove a record | `deleteRowSheet()` |
|
|
591
|
+
|
|
592
|
+
---
|
|
593
|
+
|
|
594
|
+
### 💡 Pro Tips
|
|
595
|
+
|
|
596
|
+
**1. Batch Operations for Performance:**
|
|
597
|
+
|
|
598
|
+
```typescript
|
|
599
|
+
// ❌ Bad: Multiple individual updates
|
|
600
|
+
for (const item of items) {
|
|
601
|
+
await sheetClient.updateValuesMultiCells({
|
|
602
|
+
sheetUrl: SHEET_URL,
|
|
603
|
+
sheetName: 'Data',
|
|
604
|
+
cells: [{ row: item.id, col: 2, content: item.status }],
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// ✅ Good: Single batch update
|
|
609
|
+
await sheetClient.updateValuesMultiRowsByCol({
|
|
610
|
+
sheetUrl: SHEET_URL,
|
|
611
|
+
sheetName: 'Data',
|
|
612
|
+
col: 2,
|
|
613
|
+
values: items.map((item) => ({ row: item.id, content: item.status })),
|
|
614
|
+
});
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
**2. Handle rowOffset Correctly:**
|
|
618
|
+
|
|
619
|
+
```typescript
|
|
620
|
+
// If your sheet has a description row after header:
|
|
621
|
+
// Row 1: [Name, Email, Status] ← Header
|
|
622
|
+
// Row 2: [Enter name, Enter email, ...] ← Description
|
|
623
|
+
// Row 3: [John, john@example.com, Active] ← First data row
|
|
624
|
+
|
|
625
|
+
await sheetClient.updateValuesMultiCells({
|
|
626
|
+
sheetUrl: SHEET_URL,
|
|
627
|
+
sheetName: 'Sheet1',
|
|
628
|
+
cells: [{ row: 0, col: 0, content: 'Updated' }],
|
|
629
|
+
rowOffset: 1, // Skip the description row
|
|
630
|
+
});
|
|
631
|
+
// This updates row 3 (first data row)
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
**3. Validate Before Delete:**
|
|
635
|
+
|
|
636
|
+
```typescript
|
|
637
|
+
// Always confirm before deleting
|
|
638
|
+
const confirmDelete = await getUserConfirmation();
|
|
639
|
+
if (confirmDelete) {
|
|
640
|
+
await sheetClient.deleteRowSheet({
|
|
641
|
+
sheetUrl: SHEET_URL,
|
|
642
|
+
sheetName: 'Users',
|
|
643
|
+
row: rowIndex,
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
## TypeScript Support
|
|
651
|
+
|
|
652
|
+
This library is written in TypeScript and provides full type definitions.
|
|
653
|
+
|
|
654
|
+
```typescript
|
|
655
|
+
import { GGDrive, GGSheet } from 'bodevops-features';
|
|
656
|
+
|
|
657
|
+
// All types are exported
|
|
658
|
+
type UploadResult = GGDrive.IUploadFileResult;
|
|
659
|
+
type SheetInfo = GGSheet.ISpreadsheetInfo;
|
|
660
|
+
type ExportMode = GGSheet.ETypeExport;
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
---
|
|
664
|
+
|
|
665
|
+
## Error Handling
|
|
666
|
+
|
|
667
|
+
All methods throw descriptive errors. Wrap calls in try-catch:
|
|
668
|
+
|
|
669
|
+
```typescript
|
|
670
|
+
try {
|
|
671
|
+
const result = await driveClient.uploadFile({
|
|
672
|
+
localFilePath: './document.pdf',
|
|
673
|
+
driveFolder: 'MyFolder',
|
|
674
|
+
});
|
|
675
|
+
} catch (error) {
|
|
676
|
+
console.error('Upload failed:', error.message);
|
|
677
|
+
// Handle error appropriately
|
|
678
|
+
}
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
---
|
|
682
|
+
|
|
683
|
+
## Contributing
|
|
684
|
+
|
|
685
|
+
Contributions are welcome! Please follow these guidelines:
|
|
686
|
+
|
|
687
|
+
1. Fork the repository
|
|
688
|
+
2. Create a feature branch
|
|
689
|
+
3. Write clean, documented code
|
|
690
|
+
4. Add tests if applicable
|
|
691
|
+
5. Submit a pull request
|
|
692
|
+
|
|
693
|
+
---
|
|
25
694
|
|
|
26
695
|
## License
|
|
27
696
|
|
|
28
|
-
MIT
|
|
697
|
+
MIT © [BoDevOps](https://github.com/HaiSonMin)
|
|
698
|
+
|
|
699
|
+
---
|
|
700
|
+
|
|
701
|
+
## Support
|
|
702
|
+
|
|
703
|
+
- 📧 Email: support@bodevops.com
|
|
704
|
+
- 🐛 Issues: [GitHub Issues](https://github.com/HaiSonMin/BoDevOpsFeature/issues)
|
|
705
|
+
- 📖 Documentation: [Full API Docs](https://github.com/HaiSonMin/BoDevOpsFeature#readme)
|
|
706
|
+
|
|
707
|
+
---
|
|
708
|
+
|
|
709
|
+
## Changelog
|
|
710
|
+
|
|
711
|
+
### v1.0.0 (2026-01-07)
|
|
712
|
+
|
|
713
|
+
- ✨ Initial release
|
|
714
|
+
- 🗂️ Google Drive module
|
|
715
|
+
- 📊 Google Sheets module
|
|
716
|
+
- 📚 Full TypeScript support
|
|
717
|
+
- 📝 Comprehensive documentation
|