bodevops-features 1.0.3 → 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 +311 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -336,6 +336,317 @@ await sheetClient.updateValuesMultiRowsByCol({
|
|
|
336
336
|
|
|
337
337
|
---
|
|
338
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
|
+
```
|
|
378
|
+
|
|
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
|
+
|
|
339
650
|
## TypeScript Support
|
|
340
651
|
|
|
341
652
|
This library is written in TypeScript and provides full type definitions.
|
package/package.json
CHANGED