File size: 2,567 Bytes
7dc28be
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { docs_v1 } from 'googleapis';
import { UserError } from 'fastmcp';
import * as GDocsHelpers from '../../googleDocsApiHelpers.js';
import { ExtractedTable } from './structureHelpers.js';

type Docs = docs_v1.Docs;

export function buildReplaceTableCellContentRequests(
  cell: ExtractedTable['cells'][number],
  nextValue: string,
  tabId?: string
): docs_v1.Schema$Request[] {
  const requests: docs_v1.Schema$Request[] = [];

  const insertionIndex = cell.contentStartIndex ?? cell.startIndex;
  if (insertionIndex == null) {
    throw new UserError(
      `Cell [row=${cell.rowIndex}, col=${cell.columnIndex}] does not have a writable insertion index.`
    );
  }

  if (
    cell.text &&
    cell.contentStartIndex !== null &&
    cell.contentEndIndex !== null &&
    cell.contentEndIndex - 1 > cell.contentStartIndex
  ) {
    const range: Record<string, unknown> = {
      startIndex: cell.contentStartIndex,
      endIndex: cell.contentEndIndex - 1,
    };
    if (tabId) range.tabId = tabId;
    requests.push({
      deleteContentRange: { range: range as docs_v1.Schema$Range },
    });
  }

  if (nextValue) {
    const location: Record<string, unknown> = { index: insertionIndex };
    if (tabId) location.tabId = tabId;
    requests.push({
      insertText: {
        location: location as docs_v1.Schema$Location,
        text: nextValue,
      },
    });
  }

  return requests;
}

export function buildReplaceTableRowRequests(
  table: ExtractedTable,
  rowIndex: number,
  values: string[],
  tabId?: string
): docs_v1.Schema$Request[] {
  if (rowIndex < 0 || rowIndex >= table.rowCount) {
    throw new UserError(
      `Row index ${rowIndex} is out of bounds for table ${table.tableId} with ${table.rowCount} rows.`
    );
  }

  if (values.length > table.columnCount) {
    throw new UserError(
      `Received ${values.length} values for table ${table.tableId}, but the table only has ${table.columnCount} columns.`
    );
  }

  return table.cells
    .filter((cell) => cell.rowIndex === rowIndex)
    .sort((a, b) => b.columnIndex - a.columnIndex)
    .flatMap((cell) =>
      buildReplaceTableCellContentRequests(cell, values[cell.columnIndex] ?? '', tabId)
    );
}

export async function replaceTableRowData(
  docs: Docs,
  documentId: string,
  table: ExtractedTable,
  rowIndex: number,
  values: string[],
  tabId?: string
): Promise<void> {
  const requests = buildReplaceTableRowRequests(table, rowIndex, values, tabId);
  if (requests.length === 0) return;
  await GDocsHelpers.executeBatchUpdate(docs, documentId, requests);
}