tamar-file-hub-client 0.0.7__py3-none-any.whl → 0.0.8__py3-none-any.whl
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.
- file_hub_client/services/taple/async_taple_service.py +2291 -2281
- file_hub_client/services/taple/sync_taple_service.py +14 -4
- {tamar_file_hub_client-0.0.7.dist-info → tamar_file_hub_client-0.0.8.dist-info}/METADATA +1 -1
- {tamar_file_hub_client-0.0.7.dist-info → tamar_file_hub_client-0.0.8.dist-info}/RECORD +6 -6
- {tamar_file_hub_client-0.0.7.dist-info → tamar_file_hub_client-0.0.8.dist-info}/WHEEL +0 -0
- {tamar_file_hub_client-0.0.7.dist-info → tamar_file_hub_client-0.0.8.dist-info}/top_level.txt +0 -0
@@ -1,2281 +1,2291 @@
|
|
1
|
-
"""
|
2
|
-
异步 Taple 服务
|
3
|
-
"""
|
4
|
-
import json
|
5
|
-
import traceback
|
6
|
-
|
7
|
-
import grpc
|
8
|
-
import tempfile
|
9
|
-
import os
|
10
|
-
from pathlib import Path
|
11
|
-
from typing import Optional, List, Dict, Any, Union, Callable
|
12
|
-
import uuid
|
13
|
-
import aiofiles
|
14
|
-
import asyncio
|
15
|
-
|
16
|
-
from .base_taple_service import BaseTapleService
|
17
|
-
from ...rpc.async_client import AsyncGrpcClient
|
18
|
-
from ...schemas.taple import (
|
19
|
-
TableResponse, SheetResponse, ColumnResponse, RowResponse, CellResponse,
|
20
|
-
ListSheetsResponse, CloneTableDataResponse, ExportTableDataResponse
|
21
|
-
)
|
22
|
-
from ...enums.export_format import ExportFormat
|
23
|
-
from ...errors import ValidationError
|
24
|
-
from ...utils.retry import retry_with_backoff, retry_on_lock_conflict
|
25
|
-
from ...utils.converter import timestamp_to_datetime
|
26
|
-
|
27
|
-
|
28
|
-
class AsyncTapleService(BaseTapleService):
|
29
|
-
"""异步 Taple 服务"""
|
30
|
-
|
31
|
-
def __init__(self, client: AsyncGrpcClient):
|
32
|
-
"""
|
33
|
-
初始化 Taple 服务
|
34
|
-
|
35
|
-
Args:
|
36
|
-
client: 异步 gRPC 客户端
|
37
|
-
"""
|
38
|
-
self.client = client
|
39
|
-
|
40
|
-
# Table operations
|
41
|
-
@retry_with_backoff(max_retries=3)
|
42
|
-
async def create_table(
|
43
|
-
self,
|
44
|
-
name: str,
|
45
|
-
*,
|
46
|
-
folder_id: Optional[str] = None,
|
47
|
-
description: Optional[str] = None,
|
48
|
-
idempotency_key: Optional[str] = None,
|
49
|
-
request_id: Optional[str] = None,
|
50
|
-
**metadata
|
51
|
-
) -> TableResponse:
|
52
|
-
"""
|
53
|
-
创建表格
|
54
|
-
|
55
|
-
Args:
|
56
|
-
name: 表格名称
|
57
|
-
folder_id: 父文件夹ID(可选,默认为"我的文件夹")
|
58
|
-
description: 表格描述
|
59
|
-
idempotency_key: 幂等性键(可选)
|
60
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
61
|
-
**metadata: 额外的元数据
|
62
|
-
|
63
|
-
Returns:
|
64
|
-
创建的表格信息
|
65
|
-
"""
|
66
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
67
|
-
|
68
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
69
|
-
|
70
|
-
request = taple_service_pb2.CreateTableRequest(name=name)
|
71
|
-
|
72
|
-
if folder_id:
|
73
|
-
request.folder_id = folder_id
|
74
|
-
if description:
|
75
|
-
request.description = description
|
76
|
-
if idempotency_key is not None:
|
77
|
-
request.idempotency_key = idempotency_key
|
78
|
-
|
79
|
-
response = await stub.CreateTable(request,
|
80
|
-
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
81
|
-
return TableResponse(table=self._convert_table(response.table))
|
82
|
-
|
83
|
-
@retry_with_backoff(max_retries=3)
|
84
|
-
async def get_table(
|
85
|
-
self,
|
86
|
-
*,
|
87
|
-
table_id: Optional[str] = None,
|
88
|
-
file_id: Optional[str] = None,
|
89
|
-
request_id: Optional[str] = None,
|
90
|
-
**metadata
|
91
|
-
) -> TableResponse:
|
92
|
-
"""
|
93
|
-
获取表格信息
|
94
|
-
|
95
|
-
Args:
|
96
|
-
table_id: 表格ID
|
97
|
-
file_id: 文件ID
|
98
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
99
|
-
**metadata: 额外的元数据
|
100
|
-
|
101
|
-
Returns:
|
102
|
-
表格信息
|
103
|
-
"""
|
104
|
-
if not table_id and not file_id:
|
105
|
-
raise ValidationError("table_id 或 file_id 必须提供一个")
|
106
|
-
|
107
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
108
|
-
|
109
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
110
|
-
|
111
|
-
request = taple_service_pb2.GetTableRequest()
|
112
|
-
if table_id:
|
113
|
-
request.table_id = table_id
|
114
|
-
if file_id:
|
115
|
-
request.file_id = file_id
|
116
|
-
|
117
|
-
response = await stub.GetTable(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
118
|
-
return TableResponse(table=self._convert_table(response.table))
|
119
|
-
|
120
|
-
@retry_with_backoff(max_retries=3)
|
121
|
-
async def update_table(
|
122
|
-
self,
|
123
|
-
table_id: str,
|
124
|
-
*,
|
125
|
-
name: Optional[str] = None,
|
126
|
-
description: Optional[str] = None,
|
127
|
-
idempotency_key: Optional[str] = None,
|
128
|
-
request_id: Optional[str] = None,
|
129
|
-
**metadata
|
130
|
-
) -> TableResponse:
|
131
|
-
"""
|
132
|
-
更新表格信息
|
133
|
-
|
134
|
-
Args:
|
135
|
-
table_id: 表格ID
|
136
|
-
name: 表格名称
|
137
|
-
description: 表格描述
|
138
|
-
idempotency_key: 幂等性键(可选)
|
139
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
140
|
-
**metadata: 额外的元数据
|
141
|
-
|
142
|
-
Returns:
|
143
|
-
更新后的表格信息
|
144
|
-
"""
|
145
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
146
|
-
|
147
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
148
|
-
|
149
|
-
request = taple_service_pb2.UpdateTableRequest(table_id=table_id)
|
150
|
-
|
151
|
-
if name is not None:
|
152
|
-
request.name = name
|
153
|
-
if description is not None:
|
154
|
-
request.description = description
|
155
|
-
if idempotency_key is not None:
|
156
|
-
request.idempotency_key = idempotency_key
|
157
|
-
|
158
|
-
response = await stub.UpdateTable(request,
|
159
|
-
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
160
|
-
return TableResponse(table=self._convert_table(response.table))
|
161
|
-
|
162
|
-
@retry_with_backoff(max_retries=3)
|
163
|
-
async def delete_table(self, table_id: str, *, idempotency_key: Optional[str] = None,
|
164
|
-
request_id: Optional[str] = None,
|
165
|
-
**metadata) -> None:
|
166
|
-
"""
|
167
|
-
删除表格
|
168
|
-
|
169
|
-
Args:
|
170
|
-
table_id: 表格ID
|
171
|
-
idempotency_key: 幂等性键(可选)
|
172
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
173
|
-
**metadata: 额外的元数据
|
174
|
-
"""
|
175
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
176
|
-
|
177
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
178
|
-
|
179
|
-
request = taple_service_pb2.DeleteTableRequest(table_id=table_id)
|
180
|
-
|
181
|
-
if idempotency_key is not None:
|
182
|
-
request.idempotency_key = idempotency_key
|
183
|
-
|
184
|
-
await stub.DeleteTable(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
185
|
-
|
186
|
-
# Sheet operations
|
187
|
-
@retry_with_backoff(max_retries=3)
|
188
|
-
async def create_sheet(
|
189
|
-
self,
|
190
|
-
table_id: str,
|
191
|
-
name: str,
|
192
|
-
*,
|
193
|
-
description: Optional[str] = None,
|
194
|
-
position: Optional[int] = None,
|
195
|
-
idempotency_key: Optional[str] = None,
|
196
|
-
request_id: Optional[str] = None,
|
197
|
-
**metadata
|
198
|
-
) -> SheetResponse:
|
199
|
-
"""
|
200
|
-
创建工作表
|
201
|
-
|
202
|
-
Args:
|
203
|
-
table_id: 表格ID
|
204
|
-
name: 工作表名称
|
205
|
-
description: 工作表描述
|
206
|
-
position: 工作表位置
|
207
|
-
idempotency_key: 幂等性键(可选)
|
208
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
209
|
-
**metadata: 额外的元数据
|
210
|
-
|
211
|
-
Returns:
|
212
|
-
创建的工作表信息
|
213
|
-
"""
|
214
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
215
|
-
|
216
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
217
|
-
|
218
|
-
request = taple_service_pb2.CreateSheetRequest(
|
219
|
-
table_id=table_id,
|
220
|
-
name=name
|
221
|
-
)
|
222
|
-
|
223
|
-
if description:
|
224
|
-
request.description = description
|
225
|
-
if position is not None:
|
226
|
-
request.position = position
|
227
|
-
if idempotency_key is not None:
|
228
|
-
request.idempotency_key = idempotency_key
|
229
|
-
|
230
|
-
response = await stub.CreateSheet(request,
|
231
|
-
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
232
|
-
return SheetResponse(sheet=self._convert_sheet(response.sheet))
|
233
|
-
|
234
|
-
@retry_with_backoff(max_retries=3)
|
235
|
-
async def get_sheet(self, sheet_id: str, request_id: Optional[str] = None,
|
236
|
-
**metadata) -> SheetResponse:
|
237
|
-
"""
|
238
|
-
获取工作表信息
|
239
|
-
|
240
|
-
Args:
|
241
|
-
sheet_id: 工作表ID
|
242
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
243
|
-
**metadata: 额外的元数据
|
244
|
-
|
245
|
-
Returns:
|
246
|
-
工作表信息
|
247
|
-
"""
|
248
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
249
|
-
|
250
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
251
|
-
|
252
|
-
request = taple_service_pb2.GetSheetRequest(sheet_id=sheet_id)
|
253
|
-
response = await stub.GetSheet(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
254
|
-
return SheetResponse(sheet=self._convert_sheet(response.sheet))
|
255
|
-
|
256
|
-
@retry_with_backoff(max_retries=3)
|
257
|
-
async def list_sheets(self, table_id: str, request_id: Optional[str] = None,
|
258
|
-
**metadata) -> ListSheetsResponse:
|
259
|
-
"""
|
260
|
-
列出工作表
|
261
|
-
|
262
|
-
Args:
|
263
|
-
table_id: 表格ID
|
264
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
265
|
-
**metadata: 额外的元数据
|
266
|
-
|
267
|
-
Returns:
|
268
|
-
工作表列表
|
269
|
-
"""
|
270
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
271
|
-
|
272
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
273
|
-
|
274
|
-
request = taple_service_pb2.ListSheetsRequest(table_id=table_id)
|
275
|
-
response = await stub.ListSheets(request,
|
276
|
-
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
277
|
-
|
278
|
-
sheets = [self._convert_sheet(sheet) for sheet in response.sheets]
|
279
|
-
return ListSheetsResponse(sheets=sheets)
|
280
|
-
|
281
|
-
@retry_with_backoff(max_retries=3)
|
282
|
-
async def update_sheet(
|
283
|
-
self,
|
284
|
-
sheet_id: str,
|
285
|
-
*,
|
286
|
-
name: Optional[str] = None,
|
287
|
-
description: Optional[str] = None,
|
288
|
-
position: Optional[int] = None,
|
289
|
-
idempotency_key: Optional[str] = None,
|
290
|
-
request_id: Optional[str] = None,
|
291
|
-
**metadata
|
292
|
-
) -> SheetResponse:
|
293
|
-
"""
|
294
|
-
更新工作表
|
295
|
-
|
296
|
-
Args:
|
297
|
-
sheet_id: 工作表ID
|
298
|
-
name: 工作表名称
|
299
|
-
description: 工作表描述
|
300
|
-
position: 工作表位置
|
301
|
-
idempotency_key: 幂等性键(可选)
|
302
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
303
|
-
**metadata: 额外的元数据
|
304
|
-
|
305
|
-
Returns:
|
306
|
-
更新后的工作表信息
|
307
|
-
"""
|
308
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
309
|
-
|
310
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
311
|
-
|
312
|
-
request = taple_service_pb2.UpdateSheetRequest(sheet_id=sheet_id)
|
313
|
-
|
314
|
-
if name is not None:
|
315
|
-
request.name = name
|
316
|
-
if description is not None:
|
317
|
-
request.description = description
|
318
|
-
if position is not None:
|
319
|
-
request.position = position
|
320
|
-
if idempotency_key is not None:
|
321
|
-
request.idempotency_key = idempotency_key
|
322
|
-
|
323
|
-
response = await stub.UpdateSheet(request,
|
324
|
-
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
325
|
-
return SheetResponse(sheet=self._convert_sheet(response.sheet))
|
326
|
-
|
327
|
-
@retry_with_backoff(max_retries=3)
|
328
|
-
async def delete_sheet(self, sheet_id: str, *, idempotency_key: Optional[str] = None,
|
329
|
-
request_id: Optional[str] = None,
|
330
|
-
**metadata) -> None:
|
331
|
-
"""
|
332
|
-
删除工作表
|
333
|
-
|
334
|
-
Args:
|
335
|
-
sheet_id: 工作表ID
|
336
|
-
idempotency_key: 幂等性键(可选)
|
337
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
338
|
-
**metadata: 额外的元数据
|
339
|
-
"""
|
340
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
341
|
-
|
342
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
343
|
-
|
344
|
-
request = taple_service_pb2.DeleteSheetRequest(sheet_id=sheet_id)
|
345
|
-
|
346
|
-
if idempotency_key is not None:
|
347
|
-
request.idempotency_key = idempotency_key
|
348
|
-
|
349
|
-
await stub.DeleteSheet(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
350
|
-
|
351
|
-
# Column operations
|
352
|
-
@retry_with_backoff(max_retries=3)
|
353
|
-
@retry_on_lock_conflict()
|
354
|
-
async def create_column(
|
355
|
-
self,
|
356
|
-
sheet_id: str,
|
357
|
-
name: str,
|
358
|
-
column_type: str = "text",
|
359
|
-
*,
|
360
|
-
sheet_version: Optional[int] = None,
|
361
|
-
client_id: Optional[str] = None,
|
362
|
-
position: Optional[int] = None,
|
363
|
-
width: Optional[int] = None,
|
364
|
-
description: Optional[str] = None,
|
365
|
-
properties: Optional[Dict[str, Any]] = None,
|
366
|
-
idempotency_key: Optional[str] = None,
|
367
|
-
request_id: Optional[str] = None,
|
368
|
-
**metadata
|
369
|
-
) -> ColumnResponse:
|
370
|
-
"""
|
371
|
-
创建列
|
372
|
-
|
373
|
-
Args:
|
374
|
-
sheet_id: 工作表ID
|
375
|
-
name: 列名称
|
376
|
-
column_type: 列类型
|
377
|
-
sheet_version: 版本号(可选,不传则自动获取)
|
378
|
-
client_id: 客户端ID(可选,不传则自动生成)
|
379
|
-
position: 列位置
|
380
|
-
width: 列宽度
|
381
|
-
description: 列描述信息
|
382
|
-
properties: 列属性
|
383
|
-
idempotency_key: 幂等性键(可选)
|
384
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
385
|
-
**metadata: 额外的元数据
|
386
|
-
|
387
|
-
Returns:
|
388
|
-
创建的列信息
|
389
|
-
"""
|
390
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
391
|
-
import uuid
|
392
|
-
|
393
|
-
# 如果没有提供sheet_version,自动获取
|
394
|
-
if sheet_version is None:
|
395
|
-
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
396
|
-
sheet_version = version_result.version
|
397
|
-
|
398
|
-
# 如果没有提供client_id,自动生成
|
399
|
-
if client_id is None:
|
400
|
-
client_id = str(uuid.uuid4())
|
401
|
-
|
402
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
403
|
-
|
404
|
-
request = taple_service_pb2.CreateColumnRequest(
|
405
|
-
sheet_id=sheet_id,
|
406
|
-
sheet_version=sheet_version,
|
407
|
-
client_id=client_id,
|
408
|
-
name=name,
|
409
|
-
column_type=column_type
|
410
|
-
)
|
411
|
-
|
412
|
-
if position is not None:
|
413
|
-
request.position = position
|
414
|
-
if width is not None:
|
415
|
-
request.width = width
|
416
|
-
if description is not None:
|
417
|
-
request.description = description
|
418
|
-
if properties:
|
419
|
-
request.properties.CopyFrom(self._convert_dict_to_struct(properties))
|
420
|
-
if idempotency_key is not None:
|
421
|
-
request.idempotency_key = idempotency_key
|
422
|
-
|
423
|
-
response = await stub.CreateColumn(request,
|
424
|
-
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
425
|
-
|
426
|
-
from ...schemas.taple import ColumnResponse
|
427
|
-
return ColumnResponse(
|
428
|
-
column=self._convert_column(response.column) if response.column else None,
|
429
|
-
current_version=response.current_version if hasattr(response, 'current_version') else None,
|
430
|
-
applied_immediately=response.applied_immediately if hasattr(response, 'applied_immediately') else None
|
431
|
-
)
|
432
|
-
|
433
|
-
@retry_with_backoff(max_retries=3)
|
434
|
-
@retry_on_lock_conflict()
|
435
|
-
async def update_column(
|
436
|
-
self,
|
437
|
-
sheet_id: str,
|
438
|
-
column_key: str,
|
439
|
-
*,
|
440
|
-
sheet_version: Optional[int] = None,
|
441
|
-
client_id: Optional[str] = None,
|
442
|
-
name: Optional[str] = None,
|
443
|
-
column_type: Optional[str] = None,
|
444
|
-
width: Optional[int] = None,
|
445
|
-
hidden: Optional[bool] = None,
|
446
|
-
description: Optional[str] = None,
|
447
|
-
properties: Optional[Dict[str, Any]] = None,
|
448
|
-
idempotency_key: Optional[str] = None,
|
449
|
-
request_id: Optional[str] = None,
|
450
|
-
**metadata
|
451
|
-
) -> ColumnResponse:
|
452
|
-
"""
|
453
|
-
更新列
|
454
|
-
|
455
|
-
Args:
|
456
|
-
sheet_id: 工作表ID
|
457
|
-
column_key: 列key
|
458
|
-
sheet_version: 版本号(可选,不传则自动获取)
|
459
|
-
client_id: 客户端ID(可选,不传则自动生成)
|
460
|
-
name: 列名称
|
461
|
-
column_type: 列类型
|
462
|
-
width: 列宽度
|
463
|
-
hidden: 是否隐藏
|
464
|
-
description: 列描述信息
|
465
|
-
properties: 列属性
|
466
|
-
idempotency_key: 幂等性键(可选)
|
467
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
468
|
-
**metadata: 额外的元数据
|
469
|
-
|
470
|
-
Returns:
|
471
|
-
更新后的列信息
|
472
|
-
"""
|
473
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
474
|
-
import uuid
|
475
|
-
|
476
|
-
# 如果没有提供sheet_version,自动获取
|
477
|
-
if sheet_version is None:
|
478
|
-
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
479
|
-
sheet_version = version_result.version
|
480
|
-
|
481
|
-
# 如果没有提供client_id,自动生成
|
482
|
-
if client_id is None:
|
483
|
-
client_id = str(uuid.uuid4())
|
484
|
-
|
485
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
486
|
-
|
487
|
-
request = taple_service_pb2.UpdateColumnRequest(
|
488
|
-
sheet_id=sheet_id,
|
489
|
-
sheet_version=sheet_version,
|
490
|
-
client_id=client_id,
|
491
|
-
column_key=column_key
|
492
|
-
)
|
493
|
-
|
494
|
-
if name is not None:
|
495
|
-
request.name = name
|
496
|
-
if column_type is not None:
|
497
|
-
request.column_type = column_type
|
498
|
-
if width is not None:
|
499
|
-
request.width = width
|
500
|
-
if hidden is not None:
|
501
|
-
request.hidden = hidden
|
502
|
-
if description is not None:
|
503
|
-
request.description = description
|
504
|
-
if properties:
|
505
|
-
request.properties.CopyFrom(self._convert_dict_to_struct(properties))
|
506
|
-
if idempotency_key is not None:
|
507
|
-
request.idempotency_key = idempotency_key
|
508
|
-
|
509
|
-
response = await stub.UpdateColumn(request,
|
510
|
-
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
511
|
-
|
512
|
-
from ...schemas.taple import ColumnResponse
|
513
|
-
return ColumnResponse(
|
514
|
-
column=self._convert_column(response.column) if response.column else None,
|
515
|
-
current_version=response.current_version if hasattr(response, 'current_version') else None,
|
516
|
-
applied_immediately=response.applied_immediately if hasattr(response, 'applied_immediately') else None
|
517
|
-
)
|
518
|
-
|
519
|
-
@retry_with_backoff(max_retries=3)
|
520
|
-
@retry_on_lock_conflict()
|
521
|
-
async def delete_column(
|
522
|
-
self,
|
523
|
-
sheet_id: str,
|
524
|
-
column_key: str,
|
525
|
-
*,
|
526
|
-
sheet_version: Optional[int] = None,
|
527
|
-
client_id: Optional[str] = None,
|
528
|
-
idempotency_key: Optional[str] = None,
|
529
|
-
request_id: Optional[str] = None,
|
530
|
-
**metadata
|
531
|
-
) -> None:
|
532
|
-
"""
|
533
|
-
删除列
|
534
|
-
|
535
|
-
Args:
|
536
|
-
sheet_id: 工作表ID
|
537
|
-
column_key: 列key
|
538
|
-
sheet_version: 版本号(可选,不传则自动获取)
|
539
|
-
client_id: 客户端ID(可选,不传则自动生成)
|
540
|
-
idempotency_key: 幂等性键(可选)
|
541
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
542
|
-
**metadata: 额外的元数据
|
543
|
-
"""
|
544
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
545
|
-
import uuid
|
546
|
-
|
547
|
-
# 如果没有提供sheet_version,自动获取
|
548
|
-
if sheet_version is None:
|
549
|
-
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
550
|
-
sheet_version = version_result.version
|
551
|
-
|
552
|
-
# 如果没有提供client_id,自动生成
|
553
|
-
if client_id is None:
|
554
|
-
client_id = str(uuid.uuid4())
|
555
|
-
|
556
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
557
|
-
|
558
|
-
request = taple_service_pb2.DeleteColumnRequest(
|
559
|
-
sheet_id=sheet_id,
|
560
|
-
sheet_version=sheet_version,
|
561
|
-
client_id=client_id,
|
562
|
-
column_key=column_key
|
563
|
-
)
|
564
|
-
|
565
|
-
if idempotency_key is not None:
|
566
|
-
request.idempotency_key = idempotency_key
|
567
|
-
|
568
|
-
await stub.DeleteColumn(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
569
|
-
|
570
|
-
# 以下是在 proto 中定义的方法
|
571
|
-
@retry_with_backoff(max_retries=3)
|
572
|
-
async def get_sheet_version(
|
573
|
-
self,
|
574
|
-
sheet_id: str,
|
575
|
-
request_id: Optional[str] = None,
|
576
|
-
**metadata
|
577
|
-
) -> Any:
|
578
|
-
"""
|
579
|
-
Get sheet version (lightweight).
|
580
|
-
|
581
|
-
Args:
|
582
|
-
sheet_id: Sheet ID
|
583
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
584
|
-
**metadata: Extra metadata
|
585
|
-
|
586
|
-
Returns:
|
587
|
-
GetSheetVersionResponse
|
588
|
-
"""
|
589
|
-
if not sheet_id:
|
590
|
-
raise ValidationError("sheet_id 不能为空")
|
591
|
-
|
592
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
593
|
-
|
594
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
595
|
-
|
596
|
-
request = taple_service_pb2.GetSheetVersionRequest(sheet_id=sheet_id)
|
597
|
-
response = await stub.GetSheetVersion(request,
|
598
|
-
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
599
|
-
|
600
|
-
from ...schemas.taple import GetSheetVersionResponse
|
601
|
-
return GetSheetVersionResponse(
|
602
|
-
sheet_id=response.sheet_id,
|
603
|
-
version=response.version,
|
604
|
-
metadata=self._convert_sheet(response.metadata) if response.metadata else None
|
605
|
-
)
|
606
|
-
|
607
|
-
@retry_with_backoff(max_retries=3)
|
608
|
-
async def get_sheet_data(
|
609
|
-
self,
|
610
|
-
sheet_id: str,
|
611
|
-
version: Optional[int] = None,
|
612
|
-
request_id: Optional[str] = None,
|
613
|
-
**metadata
|
614
|
-
) -> Any:
|
615
|
-
"""
|
616
|
-
Get complete sheet data.
|
617
|
-
|
618
|
-
Args:
|
619
|
-
sheet_id: Sheet ID
|
620
|
-
version: Optional version to get changes since
|
621
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
622
|
-
**metadata: Extra metadata
|
623
|
-
|
624
|
-
Returns:
|
625
|
-
GetSheetDataResponse
|
626
|
-
"""
|
627
|
-
if not sheet_id:
|
628
|
-
raise ValidationError("sheet_id 不能为空")
|
629
|
-
|
630
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
631
|
-
|
632
|
-
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
633
|
-
|
634
|
-
request = taple_service_pb2.GetSheetDataRequest(sheet_id=sheet_id)
|
635
|
-
if version is not None:
|
636
|
-
request.version = version
|
637
|
-
|
638
|
-
response = await stub.GetSheetData(request,
|
639
|
-
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
640
|
-
|
641
|
-
from ...schemas.taple import GetSheetDataResponse
|
642
|
-
return GetSheetDataResponse(
|
643
|
-
sheet_id=response.sheet_id,
|
644
|
-
version=response.version,
|
645
|
-
metadata=self._convert_sheet(response.metadata) if response.metadata else None,
|
646
|
-
columns=[self._convert_column(col) for col in response.columns] if response.columns else [],
|
647
|
-
rows=[self._convert_row(row) for row in response.rows] if response.rows else [],
|
648
|
-
cells=[self._convert_cell(cell) for cell in response.cells] if response.cells else [],
|
649
|
-
last_updated=timestamp_to_datetime(response.last_updated) if response.last_updated else None
|
650
|
-
)
|
651
|
-
|
652
|
-
@retry_with_backoff(max_retries=3)
|
653
|
-
@retry_on_lock_conflict()
|
654
|
-
async def batch_edit_sheet(
|
655
|
-
self,
|
656
|
-
sheet_id: str,
|
657
|
-
operations: List[Any],
|
658
|
-
sheet_version: int,
|
659
|
-
client_id: str,
|
660
|
-
*,
|
661
|
-
idempotency_key: Optional[str] = None,
|
662
|
-
request_id: Optional[str] = None,
|
663
|
-
**metadata
|
664
|
-
) -> Any:
|
665
|
-
"""
|
666
|
-
Execute batch operations on a sheet.
|
667
|
-
|
668
|
-
Args:
|
669
|
-
sheet_id: Sheet ID
|
670
|
-
operations: List of operations
|
671
|
-
sheet_version: Current version for optimistic locking
|
672
|
-
client_id: Client ID
|
673
|
-
idempotency_key: Idempotency key (optional)
|
674
|
-
request_id: 请求ID(可选,如果不提供则自动生成)
|
675
|
-
**metadata: Extra metadata
|
676
|
-
|
677
|
-
Returns:
|
678
|
-
BatchEditSheetResponse
|
679
|
-
"""
|
680
|
-
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
sheet_id=sheet_id,
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
sheet_id=sheet_id,
|
766
|
-
sheet_version=
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
if
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
sheet_id=sheet_id,
|
852
|
-
sheet_version=
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
if
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
sheet_id=sheet_id,
|
930
|
-
sheet_version=
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
Cell
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
sheet_id=sheet_id,
|
996
|
-
sheet_version=
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
if
|
1013
|
-
request.
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
if
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
sheet_id=sheet_id,
|
1081
|
-
sheet_version=
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
if '
|
1160
|
-
|
1161
|
-
if '
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
if '
|
1170
|
-
update_data.
|
1171
|
-
if '
|
1172
|
-
update_data.
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
'
|
1221
|
-
'
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
if '
|
1284
|
-
row_op.
|
1285
|
-
if '
|
1286
|
-
row_op.
|
1287
|
-
|
1288
|
-
elif '
|
1289
|
-
# Set fields directly on the nested message
|
1290
|
-
row_op.
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
'
|
1332
|
-
'
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
'
|
1453
|
-
'
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1503
|
-
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
sheet_id:
|
1546
|
-
column_key:
|
1547
|
-
row_key:
|
1548
|
-
request_id:
|
1549
|
-
**metadata
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
1566
|
-
|
1567
|
-
|
1568
|
-
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
|
1573
|
-
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1597
|
-
|
1598
|
-
|
1599
|
-
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
1614
|
-
|
1615
|
-
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
1637
|
-
|
1638
|
-
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
1642
|
-
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
1659
|
-
|
1660
|
-
|
1661
|
-
|
1662
|
-
|
1663
|
-
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1669
|
-
|
1670
|
-
|
1671
|
-
|
1672
|
-
|
1673
|
-
|
1674
|
-
|
1675
|
-
|
1676
|
-
|
1677
|
-
|
1678
|
-
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
1688
|
-
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
if '
|
1698
|
-
export_options.
|
1699
|
-
if '
|
1700
|
-
export_options.
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1729
|
-
|
1730
|
-
|
1731
|
-
|
1732
|
-
|
1733
|
-
|
1734
|
-
|
1735
|
-
|
1736
|
-
|
1737
|
-
|
1738
|
-
|
1739
|
-
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
1751
|
-
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
1755
|
-
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1765
|
-
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1777
|
-
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
1791
|
-
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
1795
|
-
|
1796
|
-
if
|
1797
|
-
|
1798
|
-
|
1799
|
-
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1805
|
-
|
1806
|
-
|
1807
|
-
request
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
1812
|
-
|
1813
|
-
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1817
|
-
|
1818
|
-
|
1819
|
-
|
1820
|
-
|
1821
|
-
|
1822
|
-
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1833
|
-
'
|
1834
|
-
'
|
1835
|
-
'
|
1836
|
-
'
|
1837
|
-
|
1838
|
-
|
1839
|
-
|
1840
|
-
|
1841
|
-
|
1842
|
-
|
1843
|
-
|
1844
|
-
|
1845
|
-
|
1846
|
-
|
1847
|
-
|
1848
|
-
|
1849
|
-
|
1850
|
-
|
1851
|
-
|
1852
|
-
|
1853
|
-
|
1854
|
-
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1858
|
-
|
1859
|
-
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
|
1866
|
-
|
1867
|
-
|
1868
|
-
|
1869
|
-
|
1870
|
-
|
1871
|
-
|
1872
|
-
|
1873
|
-
|
1874
|
-
|
1875
|
-
|
1876
|
-
|
1877
|
-
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
1890
|
-
|
1891
|
-
|
1892
|
-
|
1893
|
-
|
1894
|
-
|
1895
|
-
|
1896
|
-
|
1897
|
-
|
1898
|
-
|
1899
|
-
|
1900
|
-
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
|
1905
|
-
|
1906
|
-
|
1907
|
-
|
1908
|
-
|
1909
|
-
|
1910
|
-
|
1911
|
-
|
1912
|
-
|
1913
|
-
|
1914
|
-
|
1915
|
-
|
1916
|
-
|
1917
|
-
|
1918
|
-
|
1919
|
-
|
1920
|
-
|
1921
|
-
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
1925
|
-
|
1926
|
-
|
1927
|
-
|
1928
|
-
|
1929
|
-
|
1930
|
-
|
1931
|
-
|
1932
|
-
|
1933
|
-
**metadata
|
1934
|
-
|
1935
|
-
|
1936
|
-
|
1937
|
-
|
1938
|
-
|
1939
|
-
|
1940
|
-
|
1941
|
-
|
1942
|
-
|
1943
|
-
|
1944
|
-
|
1945
|
-
"""
|
1946
|
-
|
1947
|
-
|
1948
|
-
|
1949
|
-
|
1950
|
-
|
1951
|
-
|
1952
|
-
|
1953
|
-
|
1954
|
-
|
1955
|
-
|
1956
|
-
|
1957
|
-
|
1958
|
-
|
1959
|
-
|
1960
|
-
|
1961
|
-
|
1962
|
-
|
1963
|
-
|
1964
|
-
|
1965
|
-
|
1966
|
-
|
1967
|
-
|
1968
|
-
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
1973
|
-
|
1974
|
-
table_id:
|
1975
|
-
sheet_id:
|
1976
|
-
view_type:
|
1977
|
-
request_id:
|
1978
|
-
**metadata
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1994
|
-
|
1995
|
-
|
1996
|
-
|
1997
|
-
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
|
2004
|
-
|
2005
|
-
|
2006
|
-
|
2007
|
-
|
2008
|
-
|
2009
|
-
|
2010
|
-
|
2011
|
-
|
2012
|
-
|
2013
|
-
self,
|
2014
|
-
|
2015
|
-
|
2016
|
-
|
2017
|
-
|
2018
|
-
|
2019
|
-
|
2020
|
-
|
2021
|
-
|
2022
|
-
|
2023
|
-
|
2024
|
-
|
2025
|
-
|
2026
|
-
|
2027
|
-
|
2028
|
-
|
2029
|
-
|
2030
|
-
|
2031
|
-
|
2032
|
-
|
2033
|
-
|
2034
|
-
|
2035
|
-
|
2036
|
-
|
2037
|
-
|
2038
|
-
|
2039
|
-
|
2040
|
-
|
2041
|
-
|
2042
|
-
|
2043
|
-
|
2044
|
-
|
2045
|
-
|
2046
|
-
|
2047
|
-
|
2048
|
-
|
2049
|
-
|
2050
|
-
|
2051
|
-
|
2052
|
-
|
2053
|
-
|
2054
|
-
|
2055
|
-
|
2056
|
-
|
2057
|
-
|
2058
|
-
|
2059
|
-
|
2060
|
-
|
2061
|
-
|
2062
|
-
|
2063
|
-
|
2064
|
-
|
2065
|
-
|
2066
|
-
|
2067
|
-
|
2068
|
-
|
2069
|
-
|
2070
|
-
|
2071
|
-
request.
|
2072
|
-
if
|
2073
|
-
request.
|
2074
|
-
|
2075
|
-
|
2076
|
-
|
2077
|
-
|
2078
|
-
|
2079
|
-
|
2080
|
-
|
2081
|
-
|
2082
|
-
|
2083
|
-
|
2084
|
-
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2089
|
-
|
2090
|
-
|
2091
|
-
|
2092
|
-
|
2093
|
-
|
2094
|
-
|
2095
|
-
|
2096
|
-
|
2097
|
-
|
2098
|
-
|
2099
|
-
|
2100
|
-
|
2101
|
-
|
2102
|
-
|
2103
|
-
|
2104
|
-
view_id:
|
2105
|
-
|
2106
|
-
|
2107
|
-
|
2108
|
-
|
2109
|
-
|
2110
|
-
|
2111
|
-
|
2112
|
-
|
2113
|
-
|
2114
|
-
|
2115
|
-
|
2116
|
-
|
2117
|
-
metadata
|
2118
|
-
|
2119
|
-
|
2120
|
-
|
2121
|
-
|
2122
|
-
|
2123
|
-
|
2124
|
-
|
2125
|
-
|
2126
|
-
|
2127
|
-
request_id
|
2128
|
-
|
2129
|
-
|
2130
|
-
|
2131
|
-
|
2132
|
-
|
2133
|
-
|
2134
|
-
|
2135
|
-
|
2136
|
-
idempotency_key:
|
2137
|
-
request_id:
|
2138
|
-
**metadata
|
2139
|
-
|
2140
|
-
|
2141
|
-
|
2142
|
-
|
2143
|
-
|
2144
|
-
|
2145
|
-
|
2146
|
-
|
2147
|
-
|
2148
|
-
|
2149
|
-
|
2150
|
-
|
2151
|
-
|
2152
|
-
|
2153
|
-
|
2154
|
-
|
2155
|
-
|
2156
|
-
|
2157
|
-
|
2158
|
-
|
2159
|
-
|
2160
|
-
|
2161
|
-
|
2162
|
-
|
2163
|
-
|
2164
|
-
|
2165
|
-
|
2166
|
-
|
2167
|
-
|
2168
|
-
|
2169
|
-
|
2170
|
-
|
2171
|
-
|
2172
|
-
|
2173
|
-
|
2174
|
-
|
2175
|
-
|
2176
|
-
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2186
|
-
#
|
2187
|
-
|
2188
|
-
|
2189
|
-
|
2190
|
-
|
2191
|
-
|
2192
|
-
|
2193
|
-
|
2194
|
-
|
2195
|
-
|
2196
|
-
|
2197
|
-
|
2198
|
-
|
2199
|
-
|
2200
|
-
|
2201
|
-
|
2202
|
-
|
2203
|
-
|
2204
|
-
|
2205
|
-
|
2206
|
-
|
2207
|
-
|
2208
|
-
|
2209
|
-
|
2210
|
-
|
2211
|
-
|
2212
|
-
|
2213
|
-
|
2214
|
-
|
2215
|
-
|
2216
|
-
sheet_id:
|
2217
|
-
views:
|
2218
|
-
|
2219
|
-
|
2220
|
-
|
2221
|
-
|
2222
|
-
|
2223
|
-
|
2224
|
-
|
2225
|
-
|
2226
|
-
|
2227
|
-
|
2228
|
-
|
2229
|
-
|
2230
|
-
|
2231
|
-
|
2232
|
-
|
2233
|
-
|
2234
|
-
|
2235
|
-
|
2236
|
-
|
2237
|
-
|
2238
|
-
|
2239
|
-
|
2240
|
-
|
2241
|
-
|
2242
|
-
|
2243
|
-
|
2244
|
-
|
2245
|
-
|
2246
|
-
|
2247
|
-
|
2248
|
-
|
2249
|
-
|
2250
|
-
|
2251
|
-
|
2252
|
-
|
2253
|
-
|
2254
|
-
|
2255
|
-
|
2256
|
-
|
2257
|
-
|
2258
|
-
|
2259
|
-
|
2260
|
-
|
2261
|
-
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
2265
|
-
|
2266
|
-
|
2267
|
-
|
2268
|
-
|
2269
|
-
|
2270
|
-
|
2271
|
-
|
2272
|
-
|
2273
|
-
|
2274
|
-
|
2275
|
-
|
2276
|
-
|
2277
|
-
|
2278
|
-
|
2279
|
-
|
2280
|
-
|
2281
|
-
|
1
|
+
"""
|
2
|
+
异步 Taple 服务
|
3
|
+
"""
|
4
|
+
import json
|
5
|
+
import traceback
|
6
|
+
|
7
|
+
import grpc
|
8
|
+
import tempfile
|
9
|
+
import os
|
10
|
+
from pathlib import Path
|
11
|
+
from typing import Optional, List, Dict, Any, Union, Callable
|
12
|
+
import uuid
|
13
|
+
import aiofiles
|
14
|
+
import asyncio
|
15
|
+
|
16
|
+
from .base_taple_service import BaseTapleService
|
17
|
+
from ...rpc.async_client import AsyncGrpcClient
|
18
|
+
from ...schemas.taple import (
|
19
|
+
TableResponse, SheetResponse, ColumnResponse, RowResponse, CellResponse,
|
20
|
+
ListSheetsResponse, CloneTableDataResponse, ExportTableDataResponse
|
21
|
+
)
|
22
|
+
from ...enums.export_format import ExportFormat
|
23
|
+
from ...errors import ValidationError
|
24
|
+
from ...utils.retry import retry_with_backoff, retry_on_lock_conflict
|
25
|
+
from ...utils.converter import timestamp_to_datetime
|
26
|
+
|
27
|
+
|
28
|
+
class AsyncTapleService(BaseTapleService):
|
29
|
+
"""异步 Taple 服务"""
|
30
|
+
|
31
|
+
def __init__(self, client: AsyncGrpcClient):
|
32
|
+
"""
|
33
|
+
初始化 Taple 服务
|
34
|
+
|
35
|
+
Args:
|
36
|
+
client: 异步 gRPC 客户端
|
37
|
+
"""
|
38
|
+
self.client = client
|
39
|
+
|
40
|
+
# Table operations
|
41
|
+
@retry_with_backoff(max_retries=3)
|
42
|
+
async def create_table(
|
43
|
+
self,
|
44
|
+
name: str,
|
45
|
+
*,
|
46
|
+
folder_id: Optional[str] = None,
|
47
|
+
description: Optional[str] = None,
|
48
|
+
idempotency_key: Optional[str] = None,
|
49
|
+
request_id: Optional[str] = None,
|
50
|
+
**metadata
|
51
|
+
) -> TableResponse:
|
52
|
+
"""
|
53
|
+
创建表格
|
54
|
+
|
55
|
+
Args:
|
56
|
+
name: 表格名称
|
57
|
+
folder_id: 父文件夹ID(可选,默认为"我的文件夹")
|
58
|
+
description: 表格描述
|
59
|
+
idempotency_key: 幂等性键(可选)
|
60
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
61
|
+
**metadata: 额外的元数据
|
62
|
+
|
63
|
+
Returns:
|
64
|
+
创建的表格信息
|
65
|
+
"""
|
66
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
67
|
+
|
68
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
69
|
+
|
70
|
+
request = taple_service_pb2.CreateTableRequest(name=name)
|
71
|
+
|
72
|
+
if folder_id:
|
73
|
+
request.folder_id = folder_id
|
74
|
+
if description:
|
75
|
+
request.description = description
|
76
|
+
if idempotency_key is not None:
|
77
|
+
request.idempotency_key = idempotency_key
|
78
|
+
|
79
|
+
response = await stub.CreateTable(request,
|
80
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
81
|
+
return TableResponse(table=self._convert_table(response.table))
|
82
|
+
|
83
|
+
@retry_with_backoff(max_retries=3)
|
84
|
+
async def get_table(
|
85
|
+
self,
|
86
|
+
*,
|
87
|
+
table_id: Optional[str] = None,
|
88
|
+
file_id: Optional[str] = None,
|
89
|
+
request_id: Optional[str] = None,
|
90
|
+
**metadata
|
91
|
+
) -> TableResponse:
|
92
|
+
"""
|
93
|
+
获取表格信息
|
94
|
+
|
95
|
+
Args:
|
96
|
+
table_id: 表格ID
|
97
|
+
file_id: 文件ID
|
98
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
99
|
+
**metadata: 额外的元数据
|
100
|
+
|
101
|
+
Returns:
|
102
|
+
表格信息
|
103
|
+
"""
|
104
|
+
if not table_id and not file_id:
|
105
|
+
raise ValidationError("table_id 或 file_id 必须提供一个")
|
106
|
+
|
107
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
108
|
+
|
109
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
110
|
+
|
111
|
+
request = taple_service_pb2.GetTableRequest()
|
112
|
+
if table_id:
|
113
|
+
request.table_id = table_id
|
114
|
+
if file_id:
|
115
|
+
request.file_id = file_id
|
116
|
+
|
117
|
+
response = await stub.GetTable(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
118
|
+
return TableResponse(table=self._convert_table(response.table))
|
119
|
+
|
120
|
+
@retry_with_backoff(max_retries=3)
|
121
|
+
async def update_table(
|
122
|
+
self,
|
123
|
+
table_id: str,
|
124
|
+
*,
|
125
|
+
name: Optional[str] = None,
|
126
|
+
description: Optional[str] = None,
|
127
|
+
idempotency_key: Optional[str] = None,
|
128
|
+
request_id: Optional[str] = None,
|
129
|
+
**metadata
|
130
|
+
) -> TableResponse:
|
131
|
+
"""
|
132
|
+
更新表格信息
|
133
|
+
|
134
|
+
Args:
|
135
|
+
table_id: 表格ID
|
136
|
+
name: 表格名称
|
137
|
+
description: 表格描述
|
138
|
+
idempotency_key: 幂等性键(可选)
|
139
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
140
|
+
**metadata: 额外的元数据
|
141
|
+
|
142
|
+
Returns:
|
143
|
+
更新后的表格信息
|
144
|
+
"""
|
145
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
146
|
+
|
147
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
148
|
+
|
149
|
+
request = taple_service_pb2.UpdateTableRequest(table_id=table_id)
|
150
|
+
|
151
|
+
if name is not None:
|
152
|
+
request.name = name
|
153
|
+
if description is not None:
|
154
|
+
request.description = description
|
155
|
+
if idempotency_key is not None:
|
156
|
+
request.idempotency_key = idempotency_key
|
157
|
+
|
158
|
+
response = await stub.UpdateTable(request,
|
159
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
160
|
+
return TableResponse(table=self._convert_table(response.table))
|
161
|
+
|
162
|
+
@retry_with_backoff(max_retries=3)
|
163
|
+
async def delete_table(self, table_id: str, *, idempotency_key: Optional[str] = None,
|
164
|
+
request_id: Optional[str] = None,
|
165
|
+
**metadata) -> None:
|
166
|
+
"""
|
167
|
+
删除表格
|
168
|
+
|
169
|
+
Args:
|
170
|
+
table_id: 表格ID
|
171
|
+
idempotency_key: 幂等性键(可选)
|
172
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
173
|
+
**metadata: 额外的元数据
|
174
|
+
"""
|
175
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
176
|
+
|
177
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
178
|
+
|
179
|
+
request = taple_service_pb2.DeleteTableRequest(table_id=table_id)
|
180
|
+
|
181
|
+
if idempotency_key is not None:
|
182
|
+
request.idempotency_key = idempotency_key
|
183
|
+
|
184
|
+
await stub.DeleteTable(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
185
|
+
|
186
|
+
# Sheet operations
|
187
|
+
@retry_with_backoff(max_retries=3)
|
188
|
+
async def create_sheet(
|
189
|
+
self,
|
190
|
+
table_id: str,
|
191
|
+
name: str,
|
192
|
+
*,
|
193
|
+
description: Optional[str] = None,
|
194
|
+
position: Optional[int] = None,
|
195
|
+
idempotency_key: Optional[str] = None,
|
196
|
+
request_id: Optional[str] = None,
|
197
|
+
**metadata
|
198
|
+
) -> SheetResponse:
|
199
|
+
"""
|
200
|
+
创建工作表
|
201
|
+
|
202
|
+
Args:
|
203
|
+
table_id: 表格ID
|
204
|
+
name: 工作表名称
|
205
|
+
description: 工作表描述
|
206
|
+
position: 工作表位置
|
207
|
+
idempotency_key: 幂等性键(可选)
|
208
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
209
|
+
**metadata: 额外的元数据
|
210
|
+
|
211
|
+
Returns:
|
212
|
+
创建的工作表信息
|
213
|
+
"""
|
214
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
215
|
+
|
216
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
217
|
+
|
218
|
+
request = taple_service_pb2.CreateSheetRequest(
|
219
|
+
table_id=table_id,
|
220
|
+
name=name
|
221
|
+
)
|
222
|
+
|
223
|
+
if description:
|
224
|
+
request.description = description
|
225
|
+
if position is not None:
|
226
|
+
request.position = position
|
227
|
+
if idempotency_key is not None:
|
228
|
+
request.idempotency_key = idempotency_key
|
229
|
+
|
230
|
+
response = await stub.CreateSheet(request,
|
231
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
232
|
+
return SheetResponse(sheet=self._convert_sheet(response.sheet))
|
233
|
+
|
234
|
+
@retry_with_backoff(max_retries=3)
|
235
|
+
async def get_sheet(self, sheet_id: str, request_id: Optional[str] = None,
|
236
|
+
**metadata) -> SheetResponse:
|
237
|
+
"""
|
238
|
+
获取工作表信息
|
239
|
+
|
240
|
+
Args:
|
241
|
+
sheet_id: 工作表ID
|
242
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
243
|
+
**metadata: 额外的元数据
|
244
|
+
|
245
|
+
Returns:
|
246
|
+
工作表信息
|
247
|
+
"""
|
248
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
249
|
+
|
250
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
251
|
+
|
252
|
+
request = taple_service_pb2.GetSheetRequest(sheet_id=sheet_id)
|
253
|
+
response = await stub.GetSheet(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
254
|
+
return SheetResponse(sheet=self._convert_sheet(response.sheet))
|
255
|
+
|
256
|
+
@retry_with_backoff(max_retries=3)
|
257
|
+
async def list_sheets(self, table_id: str, request_id: Optional[str] = None,
|
258
|
+
**metadata) -> ListSheetsResponse:
|
259
|
+
"""
|
260
|
+
列出工作表
|
261
|
+
|
262
|
+
Args:
|
263
|
+
table_id: 表格ID
|
264
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
265
|
+
**metadata: 额外的元数据
|
266
|
+
|
267
|
+
Returns:
|
268
|
+
工作表列表
|
269
|
+
"""
|
270
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
271
|
+
|
272
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
273
|
+
|
274
|
+
request = taple_service_pb2.ListSheetsRequest(table_id=table_id)
|
275
|
+
response = await stub.ListSheets(request,
|
276
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
277
|
+
|
278
|
+
sheets = [self._convert_sheet(sheet) for sheet in response.sheets]
|
279
|
+
return ListSheetsResponse(sheets=sheets)
|
280
|
+
|
281
|
+
@retry_with_backoff(max_retries=3)
|
282
|
+
async def update_sheet(
|
283
|
+
self,
|
284
|
+
sheet_id: str,
|
285
|
+
*,
|
286
|
+
name: Optional[str] = None,
|
287
|
+
description: Optional[str] = None,
|
288
|
+
position: Optional[int] = None,
|
289
|
+
idempotency_key: Optional[str] = None,
|
290
|
+
request_id: Optional[str] = None,
|
291
|
+
**metadata
|
292
|
+
) -> SheetResponse:
|
293
|
+
"""
|
294
|
+
更新工作表
|
295
|
+
|
296
|
+
Args:
|
297
|
+
sheet_id: 工作表ID
|
298
|
+
name: 工作表名称
|
299
|
+
description: 工作表描述
|
300
|
+
position: 工作表位置
|
301
|
+
idempotency_key: 幂等性键(可选)
|
302
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
303
|
+
**metadata: 额外的元数据
|
304
|
+
|
305
|
+
Returns:
|
306
|
+
更新后的工作表信息
|
307
|
+
"""
|
308
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
309
|
+
|
310
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
311
|
+
|
312
|
+
request = taple_service_pb2.UpdateSheetRequest(sheet_id=sheet_id)
|
313
|
+
|
314
|
+
if name is not None:
|
315
|
+
request.name = name
|
316
|
+
if description is not None:
|
317
|
+
request.description = description
|
318
|
+
if position is not None:
|
319
|
+
request.position = position
|
320
|
+
if idempotency_key is not None:
|
321
|
+
request.idempotency_key = idempotency_key
|
322
|
+
|
323
|
+
response = await stub.UpdateSheet(request,
|
324
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
325
|
+
return SheetResponse(sheet=self._convert_sheet(response.sheet))
|
326
|
+
|
327
|
+
@retry_with_backoff(max_retries=3)
|
328
|
+
async def delete_sheet(self, sheet_id: str, *, idempotency_key: Optional[str] = None,
|
329
|
+
request_id: Optional[str] = None,
|
330
|
+
**metadata) -> None:
|
331
|
+
"""
|
332
|
+
删除工作表
|
333
|
+
|
334
|
+
Args:
|
335
|
+
sheet_id: 工作表ID
|
336
|
+
idempotency_key: 幂等性键(可选)
|
337
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
338
|
+
**metadata: 额外的元数据
|
339
|
+
"""
|
340
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
341
|
+
|
342
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
343
|
+
|
344
|
+
request = taple_service_pb2.DeleteSheetRequest(sheet_id=sheet_id)
|
345
|
+
|
346
|
+
if idempotency_key is not None:
|
347
|
+
request.idempotency_key = idempotency_key
|
348
|
+
|
349
|
+
await stub.DeleteSheet(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
350
|
+
|
351
|
+
# Column operations
|
352
|
+
@retry_with_backoff(max_retries=3)
|
353
|
+
@retry_on_lock_conflict()
|
354
|
+
async def create_column(
|
355
|
+
self,
|
356
|
+
sheet_id: str,
|
357
|
+
name: str,
|
358
|
+
column_type: str = "text",
|
359
|
+
*,
|
360
|
+
sheet_version: Optional[int] = None,
|
361
|
+
client_id: Optional[str] = None,
|
362
|
+
position: Optional[int] = None,
|
363
|
+
width: Optional[int] = None,
|
364
|
+
description: Optional[str] = None,
|
365
|
+
properties: Optional[Dict[str, Any]] = None,
|
366
|
+
idempotency_key: Optional[str] = None,
|
367
|
+
request_id: Optional[str] = None,
|
368
|
+
**metadata
|
369
|
+
) -> ColumnResponse:
|
370
|
+
"""
|
371
|
+
创建列
|
372
|
+
|
373
|
+
Args:
|
374
|
+
sheet_id: 工作表ID
|
375
|
+
name: 列名称
|
376
|
+
column_type: 列类型
|
377
|
+
sheet_version: 版本号(可选,不传则自动获取)
|
378
|
+
client_id: 客户端ID(可选,不传则自动生成)
|
379
|
+
position: 列位置
|
380
|
+
width: 列宽度
|
381
|
+
description: 列描述信息
|
382
|
+
properties: 列属性
|
383
|
+
idempotency_key: 幂等性键(可选)
|
384
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
385
|
+
**metadata: 额外的元数据
|
386
|
+
|
387
|
+
Returns:
|
388
|
+
创建的列信息
|
389
|
+
"""
|
390
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
391
|
+
import uuid
|
392
|
+
|
393
|
+
# 如果没有提供sheet_version,自动获取
|
394
|
+
if sheet_version is None:
|
395
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
396
|
+
sheet_version = version_result.version
|
397
|
+
|
398
|
+
# 如果没有提供client_id,自动生成
|
399
|
+
if client_id is None:
|
400
|
+
client_id = str(uuid.uuid4())
|
401
|
+
|
402
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
403
|
+
|
404
|
+
request = taple_service_pb2.CreateColumnRequest(
|
405
|
+
sheet_id=sheet_id,
|
406
|
+
sheet_version=sheet_version,
|
407
|
+
client_id=client_id,
|
408
|
+
name=name,
|
409
|
+
column_type=column_type
|
410
|
+
)
|
411
|
+
|
412
|
+
if position is not None:
|
413
|
+
request.position = position
|
414
|
+
if width is not None:
|
415
|
+
request.width = width
|
416
|
+
if description is not None:
|
417
|
+
request.description = description
|
418
|
+
if properties:
|
419
|
+
request.properties.CopyFrom(self._convert_dict_to_struct(properties))
|
420
|
+
if idempotency_key is not None:
|
421
|
+
request.idempotency_key = idempotency_key
|
422
|
+
|
423
|
+
response = await stub.CreateColumn(request,
|
424
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
425
|
+
|
426
|
+
from ...schemas.taple import ColumnResponse
|
427
|
+
return ColumnResponse(
|
428
|
+
column=self._convert_column(response.column) if response.column else None,
|
429
|
+
current_version=response.current_version if hasattr(response, 'current_version') else None,
|
430
|
+
applied_immediately=response.applied_immediately if hasattr(response, 'applied_immediately') else None
|
431
|
+
)
|
432
|
+
|
433
|
+
@retry_with_backoff(max_retries=3)
|
434
|
+
@retry_on_lock_conflict()
|
435
|
+
async def update_column(
|
436
|
+
self,
|
437
|
+
sheet_id: str,
|
438
|
+
column_key: str,
|
439
|
+
*,
|
440
|
+
sheet_version: Optional[int] = None,
|
441
|
+
client_id: Optional[str] = None,
|
442
|
+
name: Optional[str] = None,
|
443
|
+
column_type: Optional[str] = None,
|
444
|
+
width: Optional[int] = None,
|
445
|
+
hidden: Optional[bool] = None,
|
446
|
+
description: Optional[str] = None,
|
447
|
+
properties: Optional[Dict[str, Any]] = None,
|
448
|
+
idempotency_key: Optional[str] = None,
|
449
|
+
request_id: Optional[str] = None,
|
450
|
+
**metadata
|
451
|
+
) -> ColumnResponse:
|
452
|
+
"""
|
453
|
+
更新列
|
454
|
+
|
455
|
+
Args:
|
456
|
+
sheet_id: 工作表ID
|
457
|
+
column_key: 列key
|
458
|
+
sheet_version: 版本号(可选,不传则自动获取)
|
459
|
+
client_id: 客户端ID(可选,不传则自动生成)
|
460
|
+
name: 列名称
|
461
|
+
column_type: 列类型
|
462
|
+
width: 列宽度
|
463
|
+
hidden: 是否隐藏
|
464
|
+
description: 列描述信息
|
465
|
+
properties: 列属性
|
466
|
+
idempotency_key: 幂等性键(可选)
|
467
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
468
|
+
**metadata: 额外的元数据
|
469
|
+
|
470
|
+
Returns:
|
471
|
+
更新后的列信息
|
472
|
+
"""
|
473
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
474
|
+
import uuid
|
475
|
+
|
476
|
+
# 如果没有提供sheet_version,自动获取
|
477
|
+
if sheet_version is None:
|
478
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
479
|
+
sheet_version = version_result.version
|
480
|
+
|
481
|
+
# 如果没有提供client_id,自动生成
|
482
|
+
if client_id is None:
|
483
|
+
client_id = str(uuid.uuid4())
|
484
|
+
|
485
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
486
|
+
|
487
|
+
request = taple_service_pb2.UpdateColumnRequest(
|
488
|
+
sheet_id=sheet_id,
|
489
|
+
sheet_version=sheet_version,
|
490
|
+
client_id=client_id,
|
491
|
+
column_key=column_key
|
492
|
+
)
|
493
|
+
|
494
|
+
if name is not None:
|
495
|
+
request.name = name
|
496
|
+
if column_type is not None:
|
497
|
+
request.column_type = column_type
|
498
|
+
if width is not None:
|
499
|
+
request.width = width
|
500
|
+
if hidden is not None:
|
501
|
+
request.hidden = hidden
|
502
|
+
if description is not None:
|
503
|
+
request.description = description
|
504
|
+
if properties:
|
505
|
+
request.properties.CopyFrom(self._convert_dict_to_struct(properties))
|
506
|
+
if idempotency_key is not None:
|
507
|
+
request.idempotency_key = idempotency_key
|
508
|
+
|
509
|
+
response = await stub.UpdateColumn(request,
|
510
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
511
|
+
|
512
|
+
from ...schemas.taple import ColumnResponse
|
513
|
+
return ColumnResponse(
|
514
|
+
column=self._convert_column(response.column) if response.column else None,
|
515
|
+
current_version=response.current_version if hasattr(response, 'current_version') else None,
|
516
|
+
applied_immediately=response.applied_immediately if hasattr(response, 'applied_immediately') else None
|
517
|
+
)
|
518
|
+
|
519
|
+
@retry_with_backoff(max_retries=3)
|
520
|
+
@retry_on_lock_conflict()
|
521
|
+
async def delete_column(
|
522
|
+
self,
|
523
|
+
sheet_id: str,
|
524
|
+
column_key: str,
|
525
|
+
*,
|
526
|
+
sheet_version: Optional[int] = None,
|
527
|
+
client_id: Optional[str] = None,
|
528
|
+
idempotency_key: Optional[str] = None,
|
529
|
+
request_id: Optional[str] = None,
|
530
|
+
**metadata
|
531
|
+
) -> None:
|
532
|
+
"""
|
533
|
+
删除列
|
534
|
+
|
535
|
+
Args:
|
536
|
+
sheet_id: 工作表ID
|
537
|
+
column_key: 列key
|
538
|
+
sheet_version: 版本号(可选,不传则自动获取)
|
539
|
+
client_id: 客户端ID(可选,不传则自动生成)
|
540
|
+
idempotency_key: 幂等性键(可选)
|
541
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
542
|
+
**metadata: 额外的元数据
|
543
|
+
"""
|
544
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
545
|
+
import uuid
|
546
|
+
|
547
|
+
# 如果没有提供sheet_version,自动获取
|
548
|
+
if sheet_version is None:
|
549
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
550
|
+
sheet_version = version_result.version
|
551
|
+
|
552
|
+
# 如果没有提供client_id,自动生成
|
553
|
+
if client_id is None:
|
554
|
+
client_id = str(uuid.uuid4())
|
555
|
+
|
556
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
557
|
+
|
558
|
+
request = taple_service_pb2.DeleteColumnRequest(
|
559
|
+
sheet_id=sheet_id,
|
560
|
+
sheet_version=sheet_version,
|
561
|
+
client_id=client_id,
|
562
|
+
column_key=column_key
|
563
|
+
)
|
564
|
+
|
565
|
+
if idempotency_key is not None:
|
566
|
+
request.idempotency_key = idempotency_key
|
567
|
+
|
568
|
+
await stub.DeleteColumn(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
569
|
+
|
570
|
+
# 以下是在 proto 中定义的方法
|
571
|
+
@retry_with_backoff(max_retries=3)
|
572
|
+
async def get_sheet_version(
|
573
|
+
self,
|
574
|
+
sheet_id: str,
|
575
|
+
request_id: Optional[str] = None,
|
576
|
+
**metadata
|
577
|
+
) -> Any:
|
578
|
+
"""
|
579
|
+
Get sheet version (lightweight).
|
580
|
+
|
581
|
+
Args:
|
582
|
+
sheet_id: Sheet ID
|
583
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
584
|
+
**metadata: Extra metadata
|
585
|
+
|
586
|
+
Returns:
|
587
|
+
GetSheetVersionResponse
|
588
|
+
"""
|
589
|
+
if not sheet_id:
|
590
|
+
raise ValidationError("sheet_id 不能为空")
|
591
|
+
|
592
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
593
|
+
|
594
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
595
|
+
|
596
|
+
request = taple_service_pb2.GetSheetVersionRequest(sheet_id=sheet_id)
|
597
|
+
response = await stub.GetSheetVersion(request,
|
598
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
599
|
+
|
600
|
+
from ...schemas.taple import GetSheetVersionResponse
|
601
|
+
return GetSheetVersionResponse(
|
602
|
+
sheet_id=response.sheet_id,
|
603
|
+
version=response.version,
|
604
|
+
metadata=self._convert_sheet(response.metadata) if response.metadata else None
|
605
|
+
)
|
606
|
+
|
607
|
+
@retry_with_backoff(max_retries=3)
|
608
|
+
async def get_sheet_data(
|
609
|
+
self,
|
610
|
+
sheet_id: str,
|
611
|
+
version: Optional[int] = None,
|
612
|
+
request_id: Optional[str] = None,
|
613
|
+
**metadata
|
614
|
+
) -> Any:
|
615
|
+
"""
|
616
|
+
Get complete sheet data.
|
617
|
+
|
618
|
+
Args:
|
619
|
+
sheet_id: Sheet ID
|
620
|
+
version: Optional version to get changes since
|
621
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
622
|
+
**metadata: Extra metadata
|
623
|
+
|
624
|
+
Returns:
|
625
|
+
GetSheetDataResponse
|
626
|
+
"""
|
627
|
+
if not sheet_id:
|
628
|
+
raise ValidationError("sheet_id 不能为空")
|
629
|
+
|
630
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
631
|
+
|
632
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
633
|
+
|
634
|
+
request = taple_service_pb2.GetSheetDataRequest(sheet_id=sheet_id)
|
635
|
+
if version is not None:
|
636
|
+
request.version = version
|
637
|
+
|
638
|
+
response = await stub.GetSheetData(request,
|
639
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
640
|
+
|
641
|
+
from ...schemas.taple import GetSheetDataResponse
|
642
|
+
return GetSheetDataResponse(
|
643
|
+
sheet_id=response.sheet_id,
|
644
|
+
version=response.version,
|
645
|
+
metadata=self._convert_sheet(response.metadata) if response.metadata else None,
|
646
|
+
columns=[self._convert_column(col) for col in response.columns] if response.columns else [],
|
647
|
+
rows=[self._convert_row(row) for row in response.rows] if response.rows else [],
|
648
|
+
cells=[self._convert_cell(cell) for cell in response.cells] if response.cells else [],
|
649
|
+
last_updated=timestamp_to_datetime(response.last_updated) if response.last_updated else None
|
650
|
+
)
|
651
|
+
|
652
|
+
@retry_with_backoff(max_retries=3)
|
653
|
+
@retry_on_lock_conflict()
|
654
|
+
async def batch_edit_sheet(
|
655
|
+
self,
|
656
|
+
sheet_id: str,
|
657
|
+
operations: List[Any],
|
658
|
+
sheet_version: Optional[int] = None,
|
659
|
+
client_id: Optional[str] = None,
|
660
|
+
*,
|
661
|
+
idempotency_key: Optional[str] = None,
|
662
|
+
request_id: Optional[str] = None,
|
663
|
+
**metadata
|
664
|
+
) -> Any:
|
665
|
+
"""
|
666
|
+
Execute batch operations on a sheet.
|
667
|
+
|
668
|
+
Args:
|
669
|
+
sheet_id: Sheet ID
|
670
|
+
operations: List of operations
|
671
|
+
sheet_version: Current version for optimistic locking (optional, auto-fetched if not provided)
|
672
|
+
client_id: Client ID (optional, auto-generated if not provided)
|
673
|
+
idempotency_key: Idempotency key (optional)
|
674
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
675
|
+
**metadata: Extra metadata
|
676
|
+
|
677
|
+
Returns:
|
678
|
+
BatchEditSheetResponse
|
679
|
+
"""
|
680
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
681
|
+
import uuid
|
682
|
+
|
683
|
+
# 如果没有提供sheet_version,自动获取
|
684
|
+
if sheet_version is None:
|
685
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
686
|
+
sheet_version = version_result.version
|
687
|
+
|
688
|
+
# 如果没有提供client_id,自动生成
|
689
|
+
if client_id is None:
|
690
|
+
client_id = str(uuid.uuid4())
|
691
|
+
|
692
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
693
|
+
|
694
|
+
request = taple_service_pb2.BatchEditSheetRequest(
|
695
|
+
sheet_id=sheet_id,
|
696
|
+
operations=operations,
|
697
|
+
sheet_version=sheet_version,
|
698
|
+
client_id=client_id
|
699
|
+
)
|
700
|
+
|
701
|
+
if idempotency_key is not None:
|
702
|
+
request.idempotency_key = idempotency_key
|
703
|
+
|
704
|
+
response = await stub.BatchEditSheet(request,
|
705
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
706
|
+
|
707
|
+
from ...schemas.taple import BatchEditSheetResponse, ConflictInfo
|
708
|
+
|
709
|
+
conflict_info = None
|
710
|
+
if response.conflict_info:
|
711
|
+
conflict_info = ConflictInfo(
|
712
|
+
has_conflict=response.conflict_info.has_conflict,
|
713
|
+
server_version=response.conflict_info.server_version,
|
714
|
+
conflict_type=response.conflict_info.conflict_type,
|
715
|
+
conflicted_columns=list(response.conflict_info.conflicted_columns),
|
716
|
+
resolution_suggestion=response.conflict_info.resolution_suggestion
|
717
|
+
)
|
718
|
+
|
719
|
+
return BatchEditSheetResponse(
|
720
|
+
success=response.success,
|
721
|
+
batch_id=response.batch_id,
|
722
|
+
current_version=response.current_version,
|
723
|
+
results=list(response.results),
|
724
|
+
error_message=response.error_message,
|
725
|
+
conflict_info=conflict_info
|
726
|
+
)
|
727
|
+
|
728
|
+
@retry_with_backoff(max_retries=3)
|
729
|
+
@retry_on_lock_conflict()
|
730
|
+
async def create_row(
|
731
|
+
self,
|
732
|
+
sheet_id: str,
|
733
|
+
*,
|
734
|
+
sheet_version: Optional[int] = None,
|
735
|
+
client_id: Optional[str] = None,
|
736
|
+
position: Optional[int] = None,
|
737
|
+
height: Optional[int] = None,
|
738
|
+
hidden: Optional[bool] = None,
|
739
|
+
idempotency_key: Optional[str] = None,
|
740
|
+
request_id: Optional[str] = None,
|
741
|
+
**metadata
|
742
|
+
) -> RowResponse:
|
743
|
+
"""
|
744
|
+
Create a row with version control.
|
745
|
+
|
746
|
+
Args:
|
747
|
+
sheet_id: Sheet ID
|
748
|
+
sheet_version: Version for optimistic locking (optional, auto-fetched if not provided)
|
749
|
+
client_id: Client ID (optional, auto-generated if not provided)
|
750
|
+
position: Row position
|
751
|
+
height: Row height
|
752
|
+
hidden: Whether row is hidden
|
753
|
+
idempotency_key: Idempotency key (optional)
|
754
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
755
|
+
**metadata: Extra metadata
|
756
|
+
|
757
|
+
Returns:
|
758
|
+
Created row info
|
759
|
+
"""
|
760
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
761
|
+
import uuid
|
762
|
+
|
763
|
+
# 如果没有提供sheet_version,自动获取
|
764
|
+
if sheet_version is None:
|
765
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
766
|
+
sheet_version = version_result.version
|
767
|
+
|
768
|
+
# 如果没有提供client_id,自动生成
|
769
|
+
if client_id is None:
|
770
|
+
client_id = str(uuid.uuid4())
|
771
|
+
|
772
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
773
|
+
|
774
|
+
request = taple_service_pb2.CreateRowRequest(
|
775
|
+
sheet_id=sheet_id,
|
776
|
+
sheet_version=sheet_version,
|
777
|
+
client_id=client_id
|
778
|
+
)
|
779
|
+
|
780
|
+
if position is not None:
|
781
|
+
request.position = position
|
782
|
+
if height is not None:
|
783
|
+
request.height = height
|
784
|
+
if hidden is not None:
|
785
|
+
request.hidden = hidden
|
786
|
+
if idempotency_key is not None:
|
787
|
+
request.idempotency_key = idempotency_key
|
788
|
+
|
789
|
+
response = await stub.CreateRow(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
790
|
+
|
791
|
+
from ...schemas.taple import RowResponse, ConflictInfo
|
792
|
+
|
793
|
+
conflict_info = None
|
794
|
+
if hasattr(response, 'conflict_info') and response.conflict_info:
|
795
|
+
conflict_info = ConflictInfo(
|
796
|
+
has_conflict=response.conflict_info.has_conflict,
|
797
|
+
server_version=response.conflict_info.server_version,
|
798
|
+
conflict_type=response.conflict_info.conflict_type,
|
799
|
+
conflicted_columns=list(response.conflict_info.conflicted_columns),
|
800
|
+
resolution_suggestion=response.conflict_info.resolution_suggestion
|
801
|
+
)
|
802
|
+
|
803
|
+
return RowResponse(
|
804
|
+
row=self._convert_row(response.row) if response.row else None,
|
805
|
+
current_version=response.current_version if hasattr(response, 'current_version') else None,
|
806
|
+
applied_immediately=response.applied_immediately if hasattr(response, 'applied_immediately') else None,
|
807
|
+
success=response.success if hasattr(response, 'success') else None,
|
808
|
+
error_message=response.error_message if hasattr(response, 'error_message') else None,
|
809
|
+
conflict_info=conflict_info
|
810
|
+
)
|
811
|
+
|
812
|
+
@retry_with_backoff(max_retries=3)
|
813
|
+
@retry_on_lock_conflict()
|
814
|
+
async def update_row(
|
815
|
+
self,
|
816
|
+
sheet_id: str,
|
817
|
+
row_key: str,
|
818
|
+
*,
|
819
|
+
sheet_version: Optional[int] = None,
|
820
|
+
client_id: Optional[str] = None,
|
821
|
+
position: Optional[int] = None,
|
822
|
+
height: Optional[int] = None,
|
823
|
+
hidden: Optional[bool] = None,
|
824
|
+
idempotency_key: Optional[str] = None,
|
825
|
+
request_id: Optional[str] = None,
|
826
|
+
**metadata
|
827
|
+
) -> RowResponse:
|
828
|
+
"""
|
829
|
+
Update a row with version control.
|
830
|
+
|
831
|
+
Args:
|
832
|
+
sheet_id: Sheet ID
|
833
|
+
row_key: Row key to update
|
834
|
+
sheet_version: Version for optimistic locking (optional, auto-fetched if not provided)
|
835
|
+
client_id: Client ID (optional, auto-generated if not provided)
|
836
|
+
position: New row position
|
837
|
+
height: New row height
|
838
|
+
hidden: Whether row is hidden
|
839
|
+
idempotency_key: Idempotency key (optional)
|
840
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
841
|
+
**metadata: Extra metadata
|
842
|
+
|
843
|
+
Returns:
|
844
|
+
Updated row info
|
845
|
+
"""
|
846
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
847
|
+
import uuid
|
848
|
+
|
849
|
+
# 如果没有提供sheet_version,自动获取
|
850
|
+
if sheet_version is None:
|
851
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
852
|
+
sheet_version = version_result.version
|
853
|
+
|
854
|
+
# 如果没有提供client_id,自动生成
|
855
|
+
if client_id is None:
|
856
|
+
client_id = str(uuid.uuid4())
|
857
|
+
|
858
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
859
|
+
|
860
|
+
request = taple_service_pb2.UpdateRowRequest(
|
861
|
+
sheet_id=sheet_id,
|
862
|
+
sheet_version=sheet_version,
|
863
|
+
client_id=client_id,
|
864
|
+
row_key=row_key
|
865
|
+
)
|
866
|
+
|
867
|
+
if position is not None:
|
868
|
+
request.position = position
|
869
|
+
if height is not None:
|
870
|
+
request.height = height
|
871
|
+
if hidden is not None:
|
872
|
+
request.hidden = hidden
|
873
|
+
if idempotency_key is not None:
|
874
|
+
request.idempotency_key = idempotency_key
|
875
|
+
|
876
|
+
response = await stub.UpdateRow(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
877
|
+
|
878
|
+
from ...schemas.taple import RowResponse, ConflictInfo
|
879
|
+
|
880
|
+
conflict_info = None
|
881
|
+
if hasattr(response, 'conflict_info') and response.conflict_info:
|
882
|
+
conflict_info = ConflictInfo(
|
883
|
+
has_conflict=response.conflict_info.has_conflict,
|
884
|
+
server_version=response.conflict_info.server_version,
|
885
|
+
conflict_type=response.conflict_info.conflict_type,
|
886
|
+
conflicted_columns=list(response.conflict_info.conflicted_columns),
|
887
|
+
resolution_suggestion=response.conflict_info.resolution_suggestion
|
888
|
+
)
|
889
|
+
|
890
|
+
return RowResponse(
|
891
|
+
row=self._convert_row(response.row) if response.row else None,
|
892
|
+
current_version=response.current_version if hasattr(response, 'current_version') else None,
|
893
|
+
applied_immediately=response.applied_immediately if hasattr(response, 'applied_immediately') else None,
|
894
|
+
success=response.success if hasattr(response, 'success') else None,
|
895
|
+
error_message=response.error_message if hasattr(response, 'error_message') else None,
|
896
|
+
conflict_info=conflict_info
|
897
|
+
)
|
898
|
+
|
899
|
+
@retry_with_backoff(max_retries=3)
|
900
|
+
@retry_on_lock_conflict()
|
901
|
+
async def delete_row(
|
902
|
+
self,
|
903
|
+
sheet_id: str,
|
904
|
+
row_key: str,
|
905
|
+
*,
|
906
|
+
sheet_version: Optional[int] = None,
|
907
|
+
client_id: Optional[str] = None,
|
908
|
+
idempotency_key: Optional[str] = None,
|
909
|
+
request_id: Optional[str] = None,
|
910
|
+
**metadata
|
911
|
+
) -> None:
|
912
|
+
"""
|
913
|
+
Delete a row with version control.
|
914
|
+
|
915
|
+
Args:
|
916
|
+
sheet_id: Sheet ID
|
917
|
+
row_key: Row key to delete
|
918
|
+
sheet_version: Version for optimistic locking (optional, auto-fetched if not provided)
|
919
|
+
client_id: Client ID (optional, auto-generated if not provided)
|
920
|
+
idempotency_key: Idempotency key (optional)
|
921
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
922
|
+
**metadata: Extra metadata
|
923
|
+
"""
|
924
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
925
|
+
import uuid
|
926
|
+
|
927
|
+
# 如果没有提供sheet_version,自动获取
|
928
|
+
if sheet_version is None:
|
929
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
930
|
+
sheet_version = version_result.version
|
931
|
+
|
932
|
+
# 如果没有提供client_id,自动生成
|
933
|
+
if client_id is None:
|
934
|
+
client_id = str(uuid.uuid4())
|
935
|
+
|
936
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
937
|
+
|
938
|
+
request = taple_service_pb2.DeleteRowRequest(
|
939
|
+
sheet_id=sheet_id,
|
940
|
+
sheet_version=sheet_version,
|
941
|
+
client_id=client_id,
|
942
|
+
row_key=row_key
|
943
|
+
)
|
944
|
+
|
945
|
+
if idempotency_key is not None:
|
946
|
+
request.idempotency_key = idempotency_key
|
947
|
+
|
948
|
+
await stub.DeleteRow(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
949
|
+
|
950
|
+
@retry_with_backoff(max_retries=3)
|
951
|
+
@retry_on_lock_conflict()
|
952
|
+
async def edit_cell(
|
953
|
+
self,
|
954
|
+
sheet_id: str,
|
955
|
+
column_key: str,
|
956
|
+
row_key: str,
|
957
|
+
*,
|
958
|
+
sheet_version: Optional[int] = None,
|
959
|
+
client_id: Optional[str] = None,
|
960
|
+
raw_value: Optional[str] = None,
|
961
|
+
formatted_value: Optional[str] = None,
|
962
|
+
formula: Optional[str] = None,
|
963
|
+
data_type: Optional[str] = None,
|
964
|
+
styles: Optional[Dict[str, Any]] = None,
|
965
|
+
idempotency_key: Optional[str] = None,
|
966
|
+
request_id: Optional[str] = None,
|
967
|
+
**metadata
|
968
|
+
) -> CellResponse:
|
969
|
+
"""
|
970
|
+
Edit a cell with version control (create or update).
|
971
|
+
|
972
|
+
Args:
|
973
|
+
sheet_id: Sheet ID
|
974
|
+
column_key: Column key
|
975
|
+
row_key: Row key
|
976
|
+
sheet_version: Version for optimistic locking (optional, auto-fetched if not provided)
|
977
|
+
client_id: Client ID (optional, auto-generated if not provided)
|
978
|
+
raw_value: Cell value
|
979
|
+
formatted_value: Formatted value
|
980
|
+
formula: Cell formula
|
981
|
+
data_type: Data type
|
982
|
+
styles: Cell styles
|
983
|
+
idempotency_key: Idempotency key (optional)
|
984
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
985
|
+
**metadata: Extra metadata
|
986
|
+
|
987
|
+
Returns:
|
988
|
+
Cell response with updated info
|
989
|
+
"""
|
990
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
991
|
+
import uuid
|
992
|
+
|
993
|
+
# 如果没有提供sheet_version,自动获取
|
994
|
+
if sheet_version is None:
|
995
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
996
|
+
sheet_version = version_result.version
|
997
|
+
|
998
|
+
# 如果没有提供client_id,自动生成
|
999
|
+
if client_id is None:
|
1000
|
+
client_id = str(uuid.uuid4())
|
1001
|
+
|
1002
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1003
|
+
|
1004
|
+
request = taple_service_pb2.EditCellRequest(
|
1005
|
+
sheet_id=sheet_id,
|
1006
|
+
sheet_version=sheet_version,
|
1007
|
+
client_id=client_id,
|
1008
|
+
column_key=column_key,
|
1009
|
+
row_key=row_key
|
1010
|
+
)
|
1011
|
+
|
1012
|
+
if raw_value is not None:
|
1013
|
+
request.raw_value = raw_value
|
1014
|
+
if formatted_value is not None:
|
1015
|
+
request.formatted_value = formatted_value
|
1016
|
+
if formula is not None:
|
1017
|
+
request.formula = formula
|
1018
|
+
if data_type is not None:
|
1019
|
+
request.data_type = data_type
|
1020
|
+
if styles:
|
1021
|
+
request.styles.CopyFrom(self._convert_dict_to_struct(styles))
|
1022
|
+
if idempotency_key is not None:
|
1023
|
+
request.idempotency_key = idempotency_key
|
1024
|
+
|
1025
|
+
response = await stub.EditCell(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
1026
|
+
|
1027
|
+
from ...schemas.taple import CellResponse, ConflictInfo
|
1028
|
+
|
1029
|
+
conflict_info = None
|
1030
|
+
if hasattr(response, 'conflict_info') and response.conflict_info:
|
1031
|
+
conflict_info = ConflictInfo(
|
1032
|
+
has_conflict=response.conflict_info.has_conflict,
|
1033
|
+
server_version=response.conflict_info.server_version,
|
1034
|
+
conflict_type=response.conflict_info.conflict_type,
|
1035
|
+
conflicted_columns=list(response.conflict_info.conflicted_columns),
|
1036
|
+
resolution_suggestion=response.conflict_info.resolution_suggestion
|
1037
|
+
)
|
1038
|
+
|
1039
|
+
return CellResponse(
|
1040
|
+
cell=self._convert_cell(response.cell) if response.cell else None,
|
1041
|
+
current_version=response.current_version if hasattr(response, 'current_version') else None,
|
1042
|
+
applied_immediately=response.applied_immediately if hasattr(response, 'applied_immediately') else None,
|
1043
|
+
success=response.success if hasattr(response, 'success') else None,
|
1044
|
+
error_message=response.error_message if hasattr(response, 'error_message') else None,
|
1045
|
+
conflict_info=conflict_info
|
1046
|
+
)
|
1047
|
+
|
1048
|
+
@retry_with_backoff(max_retries=3)
|
1049
|
+
@retry_on_lock_conflict()
|
1050
|
+
async def delete_cell(
|
1051
|
+
self,
|
1052
|
+
sheet_id: str,
|
1053
|
+
column_key: str,
|
1054
|
+
row_key: str,
|
1055
|
+
*,
|
1056
|
+
sheet_version: Optional[int] = None,
|
1057
|
+
client_id: Optional[str] = None,
|
1058
|
+
idempotency_key: Optional[str] = None,
|
1059
|
+
request_id: Optional[str] = None,
|
1060
|
+
**metadata
|
1061
|
+
) -> None:
|
1062
|
+
"""
|
1063
|
+
Delete a cell with version control.
|
1064
|
+
|
1065
|
+
Args:
|
1066
|
+
sheet_id: Sheet ID
|
1067
|
+
column_key: Column key
|
1068
|
+
row_key: Row key
|
1069
|
+
sheet_version: Version for optimistic locking (optional, auto-fetched if not provided)
|
1070
|
+
client_id: Client ID (optional, auto-generated if not provided)
|
1071
|
+
idempotency_key: Idempotency key (optional)
|
1072
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1073
|
+
**metadata: Extra metadata
|
1074
|
+
"""
|
1075
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1076
|
+
import uuid
|
1077
|
+
|
1078
|
+
# 如果没有提供sheet_version,自动获取
|
1079
|
+
if sheet_version is None:
|
1080
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
1081
|
+
sheet_version = version_result.version
|
1082
|
+
|
1083
|
+
# 如果没有提供client_id,自动生成
|
1084
|
+
if client_id is None:
|
1085
|
+
client_id = str(uuid.uuid4())
|
1086
|
+
|
1087
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1088
|
+
|
1089
|
+
request = taple_service_pb2.DeleteCellRequest(
|
1090
|
+
sheet_id=sheet_id,
|
1091
|
+
sheet_version=sheet_version,
|
1092
|
+
client_id=client_id,
|
1093
|
+
column_key=column_key,
|
1094
|
+
row_key=row_key
|
1095
|
+
)
|
1096
|
+
|
1097
|
+
if idempotency_key is not None:
|
1098
|
+
request.idempotency_key = idempotency_key
|
1099
|
+
|
1100
|
+
await stub.DeleteCell(request, metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
1101
|
+
|
1102
|
+
@retry_with_backoff(max_retries=3)
|
1103
|
+
@retry_on_lock_conflict()
|
1104
|
+
async def batch_edit_columns(
|
1105
|
+
self,
|
1106
|
+
sheet_id: str,
|
1107
|
+
operations: List[Dict[str, Any]],
|
1108
|
+
*,
|
1109
|
+
sheet_version: Optional[int] = None,
|
1110
|
+
client_id: Optional[str] = None,
|
1111
|
+
idempotency_key: Optional[str] = None,
|
1112
|
+
request_id: Optional[str] = None,
|
1113
|
+
**metadata
|
1114
|
+
) -> Any:
|
1115
|
+
"""
|
1116
|
+
Execute batch column operations.
|
1117
|
+
|
1118
|
+
Args:
|
1119
|
+
sheet_id: Sheet ID
|
1120
|
+
operations: List of column operations
|
1121
|
+
sheet_version: Version for optimistic locking (optional, auto-fetched if not provided)
|
1122
|
+
client_id: Client ID (optional, auto-generated if not provided)
|
1123
|
+
idempotency_key: Idempotency key (optional)
|
1124
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1125
|
+
**metadata: Extra metadata
|
1126
|
+
|
1127
|
+
Returns:
|
1128
|
+
BatchEditColumnsResponse
|
1129
|
+
"""
|
1130
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1131
|
+
import uuid
|
1132
|
+
|
1133
|
+
# 如果没有提供sheet_version,自动获取
|
1134
|
+
if sheet_version is None:
|
1135
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
1136
|
+
sheet_version = version_result.version
|
1137
|
+
|
1138
|
+
# 如果没有提供client_id,自动生成
|
1139
|
+
if client_id is None:
|
1140
|
+
client_id = str(uuid.uuid4())
|
1141
|
+
|
1142
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1143
|
+
|
1144
|
+
# Convert operations to proto format
|
1145
|
+
proto_operations = []
|
1146
|
+
for op in operations:
|
1147
|
+
column_op = taple_service_pb2.ColumnOperation()
|
1148
|
+
|
1149
|
+
if 'create' in op:
|
1150
|
+
create_data = taple_service_pb2.CreateColumnData(
|
1151
|
+
name=op['create']['name']
|
1152
|
+
)
|
1153
|
+
if 'column_type' in op['create']:
|
1154
|
+
create_data.column_type = op['create']['column_type']
|
1155
|
+
if 'position' in op['create']:
|
1156
|
+
create_data.position = op['create']['position']
|
1157
|
+
if 'width' in op['create']:
|
1158
|
+
create_data.width = op['create']['width']
|
1159
|
+
if 'description' in op['create']:
|
1160
|
+
create_data.description = op['create']['description']
|
1161
|
+
if 'properties' in op['create']:
|
1162
|
+
create_data.properties.CopyFrom(self._convert_dict_to_struct(op['create']['properties']))
|
1163
|
+
column_op.create.CopyFrom(create_data)
|
1164
|
+
|
1165
|
+
elif 'update' in op:
|
1166
|
+
update_data = taple_service_pb2.UpdateColumnData(
|
1167
|
+
column_key=op['update']['column_key']
|
1168
|
+
)
|
1169
|
+
if 'name' in op['update']:
|
1170
|
+
update_data.name = op['update']['name']
|
1171
|
+
if 'column_type' in op['update']:
|
1172
|
+
update_data.column_type = op['update']['column_type']
|
1173
|
+
if 'position' in op['update']:
|
1174
|
+
update_data.position = op['update']['position']
|
1175
|
+
if 'width' in op['update']:
|
1176
|
+
update_data.width = op['update']['width']
|
1177
|
+
if 'hidden' in op['update']:
|
1178
|
+
update_data.hidden = op['update']['hidden']
|
1179
|
+
if 'description' in op['update']:
|
1180
|
+
update_data.description = op['update']['description']
|
1181
|
+
if 'properties' in op['update']:
|
1182
|
+
update_data.properties.CopyFrom(self._convert_dict_to_struct(op['update']['properties']))
|
1183
|
+
column_op.update.CopyFrom(update_data)
|
1184
|
+
|
1185
|
+
elif 'delete' in op:
|
1186
|
+
delete_data = taple_service_pb2.DeleteColumnData(
|
1187
|
+
column_key=op['delete']['column_key']
|
1188
|
+
)
|
1189
|
+
column_op.delete.CopyFrom(delete_data)
|
1190
|
+
|
1191
|
+
proto_operations.append(column_op)
|
1192
|
+
|
1193
|
+
request = taple_service_pb2.BatchEditColumnsRequest(
|
1194
|
+
sheet_id=sheet_id,
|
1195
|
+
sheet_version=sheet_version,
|
1196
|
+
client_id=client_id,
|
1197
|
+
operations=proto_operations
|
1198
|
+
)
|
1199
|
+
|
1200
|
+
if idempotency_key is not None:
|
1201
|
+
request.idempotency_key = idempotency_key
|
1202
|
+
|
1203
|
+
response = await stub.BatchEditColumns(request,
|
1204
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
1205
|
+
|
1206
|
+
from ...schemas.taple import ConflictInfo
|
1207
|
+
|
1208
|
+
conflict_info = None
|
1209
|
+
if response.conflict_info:
|
1210
|
+
conflict_info = ConflictInfo(
|
1211
|
+
has_conflict=response.conflict_info.has_conflict,
|
1212
|
+
server_version=response.conflict_info.server_version,
|
1213
|
+
conflict_type=response.conflict_info.conflict_type,
|
1214
|
+
conflicted_columns=list(response.conflict_info.conflicted_columns),
|
1215
|
+
resolution_suggestion=response.conflict_info.resolution_suggestion
|
1216
|
+
)
|
1217
|
+
|
1218
|
+
# Return raw response for now, can create proper schema later
|
1219
|
+
return {
|
1220
|
+
'success': response.success,
|
1221
|
+
'current_version': response.current_version,
|
1222
|
+
'results': [
|
1223
|
+
{
|
1224
|
+
'success': result.success,
|
1225
|
+
'column': self._convert_column(result.column) if result.column else None,
|
1226
|
+
'error_message': result.error_message,
|
1227
|
+
'operation_type': result.operation_type
|
1228
|
+
} for result in response.results
|
1229
|
+
],
|
1230
|
+
'error_message': response.error_message,
|
1231
|
+
'conflict_info': conflict_info
|
1232
|
+
}
|
1233
|
+
|
1234
|
+
@retry_with_backoff(max_retries=3)
|
1235
|
+
@retry_on_lock_conflict()
|
1236
|
+
async def batch_edit_rows(
|
1237
|
+
self,
|
1238
|
+
sheet_id: str,
|
1239
|
+
operations: List[Dict[str, Any]],
|
1240
|
+
*,
|
1241
|
+
sheet_version: Optional[int] = None,
|
1242
|
+
client_id: Optional[str] = None,
|
1243
|
+
idempotency_key: Optional[str] = None,
|
1244
|
+
request_id: Optional[str] = None,
|
1245
|
+
**metadata
|
1246
|
+
) -> Any:
|
1247
|
+
"""
|
1248
|
+
Execute batch row operations.
|
1249
|
+
|
1250
|
+
Args:
|
1251
|
+
sheet_id: Sheet ID
|
1252
|
+
operations: List of row operations
|
1253
|
+
sheet_version: Version for optimistic locking (optional, auto-fetched if not provided)
|
1254
|
+
client_id: Client ID (optional, auto-generated if not provided)
|
1255
|
+
idempotency_key: Idempotency key (optional)
|
1256
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1257
|
+
**metadata: Extra metadata
|
1258
|
+
|
1259
|
+
Returns:
|
1260
|
+
BatchEditRowsResponse
|
1261
|
+
"""
|
1262
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1263
|
+
import uuid
|
1264
|
+
|
1265
|
+
# 如果没有提供sheet_version,自动获取
|
1266
|
+
if sheet_version is None:
|
1267
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
1268
|
+
sheet_version = version_result.version
|
1269
|
+
|
1270
|
+
# 如果没有提供client_id,自动生成
|
1271
|
+
if client_id is None:
|
1272
|
+
client_id = str(uuid.uuid4())
|
1273
|
+
|
1274
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1275
|
+
|
1276
|
+
# Convert operations to proto format
|
1277
|
+
proto_operations = []
|
1278
|
+
for op in operations:
|
1279
|
+
row_op = taple_service_pb2.RowOperation()
|
1280
|
+
|
1281
|
+
if 'create' in op:
|
1282
|
+
# Set fields directly on the nested message
|
1283
|
+
if 'position' in op['create']:
|
1284
|
+
row_op.create.position = op['create']['position']
|
1285
|
+
if 'height' in op['create']:
|
1286
|
+
row_op.create.height = op['create']['height']
|
1287
|
+
|
1288
|
+
elif 'update' in op:
|
1289
|
+
# Set fields directly on the nested message
|
1290
|
+
row_op.update.row_key = op['update']['row_key']
|
1291
|
+
if 'position' in op['update']:
|
1292
|
+
row_op.update.position = op['update']['position']
|
1293
|
+
if 'height' in op['update']:
|
1294
|
+
row_op.update.height = op['update']['height']
|
1295
|
+
if 'hidden' in op['update']:
|
1296
|
+
row_op.update.hidden = op['update']['hidden']
|
1297
|
+
|
1298
|
+
elif 'delete' in op:
|
1299
|
+
# Set fields directly on the nested message
|
1300
|
+
row_op.delete.row_key = op['delete']['row_key']
|
1301
|
+
|
1302
|
+
proto_operations.append(row_op)
|
1303
|
+
|
1304
|
+
request = taple_service_pb2.BatchEditRowsRequest(
|
1305
|
+
sheet_id=sheet_id,
|
1306
|
+
sheet_version=sheet_version,
|
1307
|
+
client_id=client_id,
|
1308
|
+
operations=proto_operations
|
1309
|
+
)
|
1310
|
+
|
1311
|
+
if idempotency_key is not None:
|
1312
|
+
request.idempotency_key = idempotency_key
|
1313
|
+
|
1314
|
+
response = await stub.BatchEditRows(request,
|
1315
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
1316
|
+
|
1317
|
+
from ...schemas.taple import ConflictInfo
|
1318
|
+
|
1319
|
+
conflict_info = None
|
1320
|
+
if response.conflict_info:
|
1321
|
+
conflict_info = ConflictInfo(
|
1322
|
+
has_conflict=response.conflict_info.has_conflict,
|
1323
|
+
server_version=response.conflict_info.server_version,
|
1324
|
+
conflict_type=response.conflict_info.conflict_type,
|
1325
|
+
conflicted_columns=list(response.conflict_info.conflicted_columns),
|
1326
|
+
resolution_suggestion=response.conflict_info.resolution_suggestion
|
1327
|
+
)
|
1328
|
+
|
1329
|
+
# Return raw response for now, can create proper schema later
|
1330
|
+
return {
|
1331
|
+
'success': response.success,
|
1332
|
+
'current_version': response.current_version,
|
1333
|
+
'results': [
|
1334
|
+
{
|
1335
|
+
'success': result.success,
|
1336
|
+
'row': self._convert_row(result.row) if result.row else None,
|
1337
|
+
'error_message': result.error_message,
|
1338
|
+
'operation_type': result.operation_type
|
1339
|
+
} for result in response.results
|
1340
|
+
],
|
1341
|
+
'error_message': response.error_message,
|
1342
|
+
'conflict_info': conflict_info
|
1343
|
+
}
|
1344
|
+
|
1345
|
+
@retry_with_backoff(max_retries=3)
|
1346
|
+
@retry_on_lock_conflict()
|
1347
|
+
async def batch_edit_cells(
|
1348
|
+
self,
|
1349
|
+
sheet_id: str,
|
1350
|
+
operations: List[Dict[str, Any]],
|
1351
|
+
*,
|
1352
|
+
sheet_version: Optional[int] = None,
|
1353
|
+
client_id: Optional[str] = None,
|
1354
|
+
idempotency_key: Optional[str] = None,
|
1355
|
+
request_id: Optional[str] = None,
|
1356
|
+
**metadata
|
1357
|
+
) -> Any:
|
1358
|
+
"""
|
1359
|
+
Execute batch cell operations.
|
1360
|
+
|
1361
|
+
Args:
|
1362
|
+
sheet_id: Sheet ID
|
1363
|
+
operations: List of cell operations
|
1364
|
+
sheet_version: Version for optimistic locking (optional, auto-fetched if not provided)
|
1365
|
+
client_id: Client ID (optional, auto-generated if not provided)
|
1366
|
+
idempotency_key: Idempotency key (optional)
|
1367
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1368
|
+
**metadata: Extra metadata
|
1369
|
+
|
1370
|
+
Returns:
|
1371
|
+
BatchEditCellsResponse
|
1372
|
+
"""
|
1373
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1374
|
+
import uuid
|
1375
|
+
|
1376
|
+
# 如果没有提供sheet_version,自动获取
|
1377
|
+
if sheet_version is None:
|
1378
|
+
version_result = await self.get_sheet_version(sheet_id=sheet_id, **metadata)
|
1379
|
+
sheet_version = version_result.version
|
1380
|
+
|
1381
|
+
# 如果没有提供client_id,自动生成
|
1382
|
+
if client_id is None:
|
1383
|
+
client_id = str(uuid.uuid4())
|
1384
|
+
|
1385
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1386
|
+
|
1387
|
+
# Convert operations to proto format
|
1388
|
+
proto_operations = []
|
1389
|
+
for op in operations:
|
1390
|
+
cell_op = taple_service_pb2.CellOperation()
|
1391
|
+
|
1392
|
+
if 'edit' in op:
|
1393
|
+
edit_data = taple_service_pb2.EditCellData(
|
1394
|
+
column_key=op['edit']['column_key'],
|
1395
|
+
row_key=op['edit']['row_key']
|
1396
|
+
)
|
1397
|
+
if 'raw_value' in op['edit']:
|
1398
|
+
edit_data.raw_value = op['edit']['raw_value']
|
1399
|
+
if 'formatted_value' in op['edit']:
|
1400
|
+
edit_data.formatted_value = op['edit']['formatted_value']
|
1401
|
+
if 'formula' in op['edit']:
|
1402
|
+
edit_data.formula = op['edit']['formula']
|
1403
|
+
if 'data_type' in op['edit']:
|
1404
|
+
edit_data.data_type = op['edit']['data_type']
|
1405
|
+
if 'styles' in op['edit']:
|
1406
|
+
edit_data.styles.CopyFrom(self._convert_dict_to_struct(op['edit']['styles']))
|
1407
|
+
cell_op.edit.CopyFrom(edit_data)
|
1408
|
+
|
1409
|
+
elif 'clear' in op:
|
1410
|
+
clear_data = taple_service_pb2.ClearCellData(
|
1411
|
+
column_key=op['clear']['column_key'],
|
1412
|
+
row_key=op['clear']['row_key']
|
1413
|
+
)
|
1414
|
+
cell_op.clear.CopyFrom(clear_data)
|
1415
|
+
|
1416
|
+
elif 'delete' in op:
|
1417
|
+
delete_data = taple_service_pb2.DeleteCellData(
|
1418
|
+
column_key=op['delete']['column_key'],
|
1419
|
+
row_key=op['delete']['row_key']
|
1420
|
+
)
|
1421
|
+
cell_op.delete.CopyFrom(delete_data)
|
1422
|
+
|
1423
|
+
proto_operations.append(cell_op)
|
1424
|
+
|
1425
|
+
request = taple_service_pb2.BatchEditCellsRequest(
|
1426
|
+
sheet_id=sheet_id,
|
1427
|
+
sheet_version=sheet_version,
|
1428
|
+
client_id=client_id,
|
1429
|
+
operations=proto_operations
|
1430
|
+
)
|
1431
|
+
|
1432
|
+
if idempotency_key is not None:
|
1433
|
+
request.idempotency_key = idempotency_key
|
1434
|
+
|
1435
|
+
response = await stub.BatchEditCells(request,
|
1436
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
1437
|
+
|
1438
|
+
from ...schemas.taple import ConflictInfo
|
1439
|
+
|
1440
|
+
conflict_info = None
|
1441
|
+
if response.conflict_info:
|
1442
|
+
conflict_info = ConflictInfo(
|
1443
|
+
has_conflict=response.conflict_info.has_conflict,
|
1444
|
+
server_version=response.conflict_info.server_version,
|
1445
|
+
conflict_type=response.conflict_info.conflict_type,
|
1446
|
+
conflicted_columns=list(response.conflict_info.conflicted_columns),
|
1447
|
+
resolution_suggestion=response.conflict_info.resolution_suggestion
|
1448
|
+
)
|
1449
|
+
|
1450
|
+
# Return raw response for now, can create proper schema later
|
1451
|
+
return {
|
1452
|
+
'success': response.success,
|
1453
|
+
'current_version': response.current_version,
|
1454
|
+
'results': [
|
1455
|
+
{
|
1456
|
+
'success': result.success,
|
1457
|
+
'cell': self._convert_cell(result.cell) if result.cell else None,
|
1458
|
+
'error_message': result.error_message,
|
1459
|
+
'operation_type': result.operation_type
|
1460
|
+
} for result in response.results
|
1461
|
+
],
|
1462
|
+
'error_message': response.error_message,
|
1463
|
+
'conflict_info': conflict_info
|
1464
|
+
}
|
1465
|
+
|
1466
|
+
@retry_with_backoff(max_retries=3)
|
1467
|
+
async def get_column_data(
|
1468
|
+
self,
|
1469
|
+
sheet_id: str,
|
1470
|
+
column_key: str,
|
1471
|
+
request_id: Optional[str] = None,
|
1472
|
+
**metadata
|
1473
|
+
) -> Any:
|
1474
|
+
"""
|
1475
|
+
Get column data including all cells in the column.
|
1476
|
+
|
1477
|
+
Args:
|
1478
|
+
sheet_id: Sheet ID
|
1479
|
+
column_key: Column key
|
1480
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1481
|
+
**metadata: Extra metadata
|
1482
|
+
|
1483
|
+
Returns:
|
1484
|
+
ColumnDataResponse with column info and cells
|
1485
|
+
"""
|
1486
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1487
|
+
|
1488
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1489
|
+
|
1490
|
+
request = taple_service_pb2.GetColumnDataRequest(
|
1491
|
+
sheet_id=sheet_id,
|
1492
|
+
column_key=column_key
|
1493
|
+
)
|
1494
|
+
|
1495
|
+
response = await stub.GetColumnData(request,
|
1496
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
1497
|
+
|
1498
|
+
# Return raw response for now, can create proper schema later
|
1499
|
+
return {
|
1500
|
+
'column': self._convert_column(response.column) if response.column else None,
|
1501
|
+
'cells': [self._convert_cell(cell) for cell in response.cells]
|
1502
|
+
}
|
1503
|
+
|
1504
|
+
@retry_with_backoff(max_retries=3)
|
1505
|
+
async def get_row_data(
|
1506
|
+
self,
|
1507
|
+
sheet_id: str,
|
1508
|
+
row_key: str,
|
1509
|
+
request_id: Optional[str] = None,
|
1510
|
+
**metadata
|
1511
|
+
) -> Any:
|
1512
|
+
"""
|
1513
|
+
Get row data including all cells in the row.
|
1514
|
+
|
1515
|
+
Args:
|
1516
|
+
sheet_id: Sheet ID
|
1517
|
+
row_key: Row key
|
1518
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1519
|
+
**metadata: Extra metadata
|
1520
|
+
|
1521
|
+
Returns:
|
1522
|
+
RowDataResponse with row info and cells
|
1523
|
+
"""
|
1524
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1525
|
+
|
1526
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1527
|
+
|
1528
|
+
request = taple_service_pb2.GetRowDataRequest(
|
1529
|
+
sheet_id=sheet_id,
|
1530
|
+
row_key=row_key
|
1531
|
+
)
|
1532
|
+
|
1533
|
+
response = await stub.GetRowData(request,
|
1534
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
1535
|
+
|
1536
|
+
# Return raw response for now, can create proper schema later
|
1537
|
+
return {
|
1538
|
+
'row': self._convert_row(response.row) if response.row else None,
|
1539
|
+
'cells': [self._convert_cell(cell) for cell in response.cells]
|
1540
|
+
}
|
1541
|
+
|
1542
|
+
@retry_with_backoff(max_retries=3)
|
1543
|
+
async def get_cell_data(
|
1544
|
+
self,
|
1545
|
+
sheet_id: str,
|
1546
|
+
column_key: str,
|
1547
|
+
row_key: str,
|
1548
|
+
request_id: Optional[str] = None,
|
1549
|
+
**metadata
|
1550
|
+
) -> Any:
|
1551
|
+
"""
|
1552
|
+
Get cell data.
|
1553
|
+
|
1554
|
+
Args:
|
1555
|
+
sheet_id: Sheet ID
|
1556
|
+
column_key: Column key
|
1557
|
+
row_key: Row key
|
1558
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1559
|
+
**metadata: Extra metadata
|
1560
|
+
|
1561
|
+
Returns:
|
1562
|
+
CellDataResponse with cell info
|
1563
|
+
"""
|
1564
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1565
|
+
|
1566
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1567
|
+
|
1568
|
+
request = taple_service_pb2.GetCellDataRequest(
|
1569
|
+
sheet_id=sheet_id,
|
1570
|
+
column_key=column_key,
|
1571
|
+
row_key=row_key
|
1572
|
+
)
|
1573
|
+
|
1574
|
+
response = await stub.GetCellData(request,
|
1575
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
1576
|
+
|
1577
|
+
# Return raw response for now, can create proper schema later
|
1578
|
+
return {
|
1579
|
+
'cell': self._convert_cell(response.cell) if response.cell else None
|
1580
|
+
}
|
1581
|
+
|
1582
|
+
@retry_with_backoff(max_retries=3)
|
1583
|
+
async def clone_table_data(
|
1584
|
+
self,
|
1585
|
+
source_table_id: str,
|
1586
|
+
target_org_id: str,
|
1587
|
+
target_user_id: str,
|
1588
|
+
*,
|
1589
|
+
target_folder_id: Optional[str] = None,
|
1590
|
+
new_table_name: Optional[str] = None,
|
1591
|
+
include_views: bool = False,
|
1592
|
+
idempotency_key: Optional[str] = None,
|
1593
|
+
request_id: Optional[str] = None,
|
1594
|
+
**metadata
|
1595
|
+
) -> 'CloneTableDataResponse':
|
1596
|
+
"""
|
1597
|
+
Clone table data to another organization.
|
1598
|
+
|
1599
|
+
Args:
|
1600
|
+
source_table_id: Source table ID
|
1601
|
+
target_org_id: Target organization ID
|
1602
|
+
target_user_id: Target user ID
|
1603
|
+
target_folder_id: Target folder ID (optional)
|
1604
|
+
new_table_name: New table name (optional, defaults to original name + Copy)
|
1605
|
+
include_views: Whether to include view data (default: False)
|
1606
|
+
idempotency_key: Idempotency key (optional)
|
1607
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1608
|
+
**metadata: Extra metadata
|
1609
|
+
|
1610
|
+
Returns:
|
1611
|
+
CloneTableDataResponse with clone operation result
|
1612
|
+
"""
|
1613
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1614
|
+
from ...schemas.taple import CloneTableDataResponse
|
1615
|
+
|
1616
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1617
|
+
|
1618
|
+
request = taple_service_pb2.CloneTableDataRequest(
|
1619
|
+
source_table_id=source_table_id,
|
1620
|
+
target_org_id=target_org_id,
|
1621
|
+
target_user_id=target_user_id
|
1622
|
+
)
|
1623
|
+
|
1624
|
+
if target_folder_id:
|
1625
|
+
request.target_folder_id = target_folder_id
|
1626
|
+
if new_table_name:
|
1627
|
+
request.new_table_name = new_table_name
|
1628
|
+
if include_views is not None:
|
1629
|
+
request.include_views = include_views
|
1630
|
+
if idempotency_key:
|
1631
|
+
request.idempotency_key = idempotency_key
|
1632
|
+
|
1633
|
+
response = await stub.CloneTableData(request,
|
1634
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
1635
|
+
|
1636
|
+
return CloneTableDataResponse(
|
1637
|
+
success=response.success,
|
1638
|
+
new_table_id=response.new_table_id,
|
1639
|
+
new_file_id=response.new_file_id,
|
1640
|
+
sheets_cloned=response.sheets_cloned,
|
1641
|
+
cells_cloned=response.cells_cloned,
|
1642
|
+
error_message=response.error_message if response.error_message else None,
|
1643
|
+
created_at=timestamp_to_datetime(response.created_at)
|
1644
|
+
)
|
1645
|
+
|
1646
|
+
@retry_with_backoff(max_retries=3)
|
1647
|
+
async def export_table_data(
|
1648
|
+
self,
|
1649
|
+
table_id: str,
|
1650
|
+
format: 'ExportFormat',
|
1651
|
+
*,
|
1652
|
+
sheet_ids: Optional[List[str]] = None,
|
1653
|
+
options: Optional[Dict[str, Any]] = None,
|
1654
|
+
idempotency_key: Optional[str] = None,
|
1655
|
+
request_id: Optional[str] = None,
|
1656
|
+
**metadata
|
1657
|
+
) -> 'ExportTableDataResponse':
|
1658
|
+
"""
|
1659
|
+
Export table data to file.
|
1660
|
+
|
1661
|
+
Args:
|
1662
|
+
table_id: Table ID to export
|
1663
|
+
format: Export format (EXCEL, CSV, JSON)
|
1664
|
+
sheet_ids: List of sheet IDs to export (optional, empty means all)
|
1665
|
+
options: Export options dict
|
1666
|
+
idempotency_key: Idempotency key (optional)
|
1667
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1668
|
+
**metadata: Extra metadata
|
1669
|
+
|
1670
|
+
Returns:
|
1671
|
+
ExportTableDataResponse with export result
|
1672
|
+
"""
|
1673
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1674
|
+
from ...schemas.taple import ExportTableDataResponse
|
1675
|
+
from google.protobuf import struct_pb2
|
1676
|
+
|
1677
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1678
|
+
|
1679
|
+
# Convert format enum
|
1680
|
+
format_map = {
|
1681
|
+
ExportFormat.XLSX: taple_service_pb2.EXPORT_FORMAT_EXCEL,
|
1682
|
+
ExportFormat.CSV: taple_service_pb2.EXPORT_FORMAT_CSV,
|
1683
|
+
ExportFormat.JSON: taple_service_pb2.EXPORT_FORMAT_JSON,
|
1684
|
+
}
|
1685
|
+
|
1686
|
+
request = taple_service_pb2.ExportTableDataRequest(
|
1687
|
+
table_id=table_id,
|
1688
|
+
format=format_map.get(format, taple_service_pb2.EXPORT_FORMAT_UNSPECIFIED)
|
1689
|
+
)
|
1690
|
+
|
1691
|
+
if sheet_ids:
|
1692
|
+
request.sheet_ids.extend(sheet_ids)
|
1693
|
+
|
1694
|
+
if options:
|
1695
|
+
# Create ExportOptions
|
1696
|
+
export_options = taple_service_pb2.ExportOptions()
|
1697
|
+
if 'include_formulas' in options:
|
1698
|
+
export_options.include_formulas = options['include_formulas']
|
1699
|
+
if 'include_styles' in options:
|
1700
|
+
export_options.include_styles = options['include_styles']
|
1701
|
+
if 'include_hidden_sheets' in options:
|
1702
|
+
export_options.include_hidden_sheets = options['include_hidden_sheets']
|
1703
|
+
if 'include_hidden_rows_cols' in options:
|
1704
|
+
export_options.include_hidden_rows_cols = options['include_hidden_rows_cols']
|
1705
|
+
if 'date_format' in options:
|
1706
|
+
export_options.date_format = options['date_format']
|
1707
|
+
if 'csv_delimiter' in options:
|
1708
|
+
export_options.csv_delimiter = options['csv_delimiter']
|
1709
|
+
if 'csv_encoding' in options:
|
1710
|
+
export_options.csv_encoding = options['csv_encoding']
|
1711
|
+
request.options.CopyFrom(export_options)
|
1712
|
+
|
1713
|
+
if idempotency_key:
|
1714
|
+
request.idempotency_key = idempotency_key
|
1715
|
+
|
1716
|
+
response = await stub.ExportTableData(request,
|
1717
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata))
|
1718
|
+
|
1719
|
+
return ExportTableDataResponse(
|
1720
|
+
success=response.success,
|
1721
|
+
export_id=response.export_id,
|
1722
|
+
file_url=response.file_url,
|
1723
|
+
download_url=response.download_url,
|
1724
|
+
file_size=response.file_size,
|
1725
|
+
file_name=response.file_name,
|
1726
|
+
format=format.value if hasattr(format, 'value') else str(format), # Convert enum to string
|
1727
|
+
sheets_exported=response.sheets_exported,
|
1728
|
+
error_message=response.error_message if response.error_message else None,
|
1729
|
+
created_at=timestamp_to_datetime(response.created_at),
|
1730
|
+
expires_at=timestamp_to_datetime(response.expires_at)
|
1731
|
+
)
|
1732
|
+
|
1733
|
+
@retry_with_backoff(max_retries=3)
|
1734
|
+
async def import_table_data(
|
1735
|
+
self,
|
1736
|
+
file_id: str,
|
1737
|
+
*,
|
1738
|
+
target_table_id: Optional[str] = None,
|
1739
|
+
table_name: Optional[str] = None,
|
1740
|
+
folder_id: Optional[str] = None,
|
1741
|
+
import_mode: str = "APPEND",
|
1742
|
+
skip_first_row: bool = True,
|
1743
|
+
auto_detect_types: bool = True,
|
1744
|
+
clear_existing_data: bool = False,
|
1745
|
+
column_mapping: Optional[Dict[str, str]] = None,
|
1746
|
+
date_format: str = "YYYY-MM-DD",
|
1747
|
+
csv_delimiter: str = ",",
|
1748
|
+
csv_encoding: str = "UTF-8",
|
1749
|
+
max_rows: int = 0,
|
1750
|
+
idempotency_key: Optional[str] = None,
|
1751
|
+
request_id: Optional[str] = None,
|
1752
|
+
**metadata
|
1753
|
+
) -> 'ImportTableDataResponse':
|
1754
|
+
"""
|
1755
|
+
导入文件数据到表格
|
1756
|
+
|
1757
|
+
Args:
|
1758
|
+
file_id: 要导入的文件ID
|
1759
|
+
target_table_id: 目标表格ID(可选,不提供则创建新表格)
|
1760
|
+
table_name: 表格名称(仅在创建新表格时使用)
|
1761
|
+
folder_id: 文件夹ID(仅在创建新表格时使用)
|
1762
|
+
import_mode: 导入模式(APPEND/REPLACE/MERGE)
|
1763
|
+
skip_first_row: 是否跳过第一行(标题行)
|
1764
|
+
auto_detect_types: 是否自动检测列类型
|
1765
|
+
clear_existing_data: 是否清空现有数据(仅在导入到现有表格时)
|
1766
|
+
column_mapping: 列映射(源列名 -> 目标列名)
|
1767
|
+
date_format: 日期格式
|
1768
|
+
csv_delimiter: CSV分隔符
|
1769
|
+
csv_encoding: CSV编码
|
1770
|
+
max_rows: 最大导入行数限制(0表示无限制)
|
1771
|
+
idempotency_key: 幂等性键
|
1772
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1773
|
+
**metadata: 额外的元数据
|
1774
|
+
|
1775
|
+
Returns:
|
1776
|
+
ImportTableDataResponse
|
1777
|
+
"""
|
1778
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1779
|
+
from ...schemas.taple import ImportTableDataResponse
|
1780
|
+
|
1781
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1782
|
+
|
1783
|
+
# 构建导入选项
|
1784
|
+
import_options = taple_service_pb2.ImportOptions(
|
1785
|
+
import_mode=self._get_import_mode_enum(import_mode),
|
1786
|
+
skip_first_row=skip_first_row,
|
1787
|
+
auto_detect_types=auto_detect_types,
|
1788
|
+
clear_existing_data=clear_existing_data,
|
1789
|
+
date_format=date_format,
|
1790
|
+
csv_delimiter=csv_delimiter,
|
1791
|
+
csv_encoding=csv_encoding,
|
1792
|
+
max_rows=max_rows
|
1793
|
+
)
|
1794
|
+
|
1795
|
+
# 添加列映射
|
1796
|
+
if column_mapping:
|
1797
|
+
for source_col, target_col in column_mapping.items():
|
1798
|
+
import_options.column_mapping[source_col] = target_col
|
1799
|
+
|
1800
|
+
# 构建请求
|
1801
|
+
request = taple_service_pb2.ImportTableDataRequest(
|
1802
|
+
file_id=file_id,
|
1803
|
+
options=import_options
|
1804
|
+
)
|
1805
|
+
|
1806
|
+
if target_table_id:
|
1807
|
+
request.target_table_id = target_table_id
|
1808
|
+
if folder_id:
|
1809
|
+
request.folder_id = folder_id
|
1810
|
+
if table_name:
|
1811
|
+
request.table_name = table_name
|
1812
|
+
if idempotency_key:
|
1813
|
+
request.idempotency_key = idempotency_key
|
1814
|
+
|
1815
|
+
# 调用RPC
|
1816
|
+
response = await stub.ImportTableData(
|
1817
|
+
request,
|
1818
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata)
|
1819
|
+
)
|
1820
|
+
|
1821
|
+
# 转换响应
|
1822
|
+
return ImportTableDataResponse(
|
1823
|
+
success=response.success,
|
1824
|
+
table_id=response.table_id,
|
1825
|
+
file_id=response.file_id if response.file_id else None,
|
1826
|
+
sheets_imported=response.sheets_imported,
|
1827
|
+
rows_imported=response.rows_imported,
|
1828
|
+
cells_imported=response.cells_imported,
|
1829
|
+
sheet_results=[
|
1830
|
+
{
|
1831
|
+
'sheet_name': result.sheet_name,
|
1832
|
+
'sheet_id': result.sheet_id,
|
1833
|
+
'rows_imported': result.rows_imported,
|
1834
|
+
'cells_imported': result.cells_imported,
|
1835
|
+
'success': result.success,
|
1836
|
+
'error_message': result.error_message if result.error_message else None
|
1837
|
+
}
|
1838
|
+
for result in response.sheet_results
|
1839
|
+
],
|
1840
|
+
error_message=response.error_message if response.error_message else None,
|
1841
|
+
warnings=[
|
1842
|
+
{
|
1843
|
+
'type': warning.type,
|
1844
|
+
'message': warning.message,
|
1845
|
+
'sheet_name': warning.sheet_name if warning.sheet_name else None,
|
1846
|
+
'row_number': warning.row_number if warning.row_number else None,
|
1847
|
+
'column_name': warning.column_name if warning.column_name else None
|
1848
|
+
}
|
1849
|
+
for warning in response.warnings
|
1850
|
+
],
|
1851
|
+
created_at=timestamp_to_datetime(response.created_at),
|
1852
|
+
processing_time_ms=response.processing_time_ms
|
1853
|
+
)
|
1854
|
+
|
1855
|
+
def _get_import_mode_enum(self, mode: str) -> int:
|
1856
|
+
"""将字符串导入模式转换为枚举值"""
|
1857
|
+
from ...rpc.gen import taple_service_pb2
|
1858
|
+
|
1859
|
+
mode_map = {
|
1860
|
+
"APPEND": taple_service_pb2.IMPORT_MODE_APPEND,
|
1861
|
+
"REPLACE": taple_service_pb2.IMPORT_MODE_REPLACE,
|
1862
|
+
"MERGE": taple_service_pb2.IMPORT_MODE_MERGE
|
1863
|
+
}
|
1864
|
+
|
1865
|
+
return mode_map.get(mode.upper(), taple_service_pb2.IMPORT_MODE_APPEND)
|
1866
|
+
|
1867
|
+
# Table view operations
|
1868
|
+
@retry_with_backoff(max_retries=3)
|
1869
|
+
async def create_table_view(
|
1870
|
+
self,
|
1871
|
+
sheet_id: str,
|
1872
|
+
name: str,
|
1873
|
+
view_type: str,
|
1874
|
+
*,
|
1875
|
+
filter_criteria: Optional[Dict[str, Any]] = None,
|
1876
|
+
sort_criteria: Optional[Dict[str, Any]] = None,
|
1877
|
+
visible_columns: Optional[List[str]] = None,
|
1878
|
+
group_criteria: Optional[Dict[str, Any]] = None,
|
1879
|
+
is_hidden: bool = False,
|
1880
|
+
is_default: bool = False,
|
1881
|
+
config: Optional[Dict[str, Any]] = None,
|
1882
|
+
idempotency_key: Optional[str] = None,
|
1883
|
+
request_id: Optional[str] = None,
|
1884
|
+
**metadata
|
1885
|
+
) -> 'TableViewResponse':
|
1886
|
+
"""
|
1887
|
+
创建表格视图
|
1888
|
+
|
1889
|
+
Args:
|
1890
|
+
sheet_id: 所属工作表ID
|
1891
|
+
name: 视图名称
|
1892
|
+
view_type: 视图类型(table/gantt/calendar/kanban/gallery等)
|
1893
|
+
filter_criteria: 过滤条件(可选)
|
1894
|
+
sort_criteria: 排序条件(可选)
|
1895
|
+
visible_columns: 可见列列表(可选)
|
1896
|
+
group_criteria: 分组条件(可选)
|
1897
|
+
is_hidden: 是否隐藏(默认False)
|
1898
|
+
is_default: 是否默认视图(默认False)
|
1899
|
+
config: 扩展配置(可选)
|
1900
|
+
idempotency_key: 幂等性键(可选)
|
1901
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1902
|
+
**metadata: 额外的元数据
|
1903
|
+
|
1904
|
+
Returns:
|
1905
|
+
TableViewResponse
|
1906
|
+
"""
|
1907
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1908
|
+
from ...schemas.taple import TableViewResponse
|
1909
|
+
|
1910
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1911
|
+
|
1912
|
+
request = taple_service_pb2.CreateTableViewRequest(
|
1913
|
+
sheet_id=sheet_id,
|
1914
|
+
view_name=name,
|
1915
|
+
view_type=view_type,
|
1916
|
+
visible_columns=visible_columns or [],
|
1917
|
+
is_hidden=is_hidden,
|
1918
|
+
is_default=is_default,
|
1919
|
+
)
|
1920
|
+
|
1921
|
+
# 处理可选的 JSON 字段
|
1922
|
+
if filter_criteria:
|
1923
|
+
request.filter_criteria.CopyFrom(self._convert_dict_to_struct(filter_criteria))
|
1924
|
+
if sort_criteria:
|
1925
|
+
request.sort_criteria.CopyFrom(self._convert_dict_to_struct(sort_criteria))
|
1926
|
+
if group_criteria:
|
1927
|
+
request.group_criteria.CopyFrom(self._convert_dict_to_struct(group_criteria))
|
1928
|
+
if config:
|
1929
|
+
request.config.CopyFrom(self._convert_dict_to_struct(config))
|
1930
|
+
|
1931
|
+
response = await stub.CreateTableView(
|
1932
|
+
request,
|
1933
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata)
|
1934
|
+
)
|
1935
|
+
|
1936
|
+
return TableViewResponse(view=self._convert_table_view(response.view))
|
1937
|
+
|
1938
|
+
@retry_with_backoff(max_retries=3)
|
1939
|
+
async def get_table_view(
|
1940
|
+
self,
|
1941
|
+
view_id: str,
|
1942
|
+
request_id: Optional[str] = None,
|
1943
|
+
**metadata
|
1944
|
+
) -> 'TableViewResponse':
|
1945
|
+
"""
|
1946
|
+
获取表格视图
|
1947
|
+
|
1948
|
+
Args:
|
1949
|
+
view_id: 视图ID
|
1950
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1951
|
+
**metadata: 额外的元数据
|
1952
|
+
|
1953
|
+
Returns:
|
1954
|
+
TableViewResponse
|
1955
|
+
"""
|
1956
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1957
|
+
from ...schemas.taple import TableViewResponse
|
1958
|
+
|
1959
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
1960
|
+
|
1961
|
+
request = taple_service_pb2.GetTableViewRequest(view_id=view_id)
|
1962
|
+
|
1963
|
+
response = await stub.GetTableView(
|
1964
|
+
request,
|
1965
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata)
|
1966
|
+
)
|
1967
|
+
|
1968
|
+
return TableViewResponse(view=self._convert_table_view(response.view))
|
1969
|
+
|
1970
|
+
@retry_with_backoff(max_retries=3)
|
1971
|
+
async def list_table_views(
|
1972
|
+
self,
|
1973
|
+
*,
|
1974
|
+
table_id: Optional[str] = None,
|
1975
|
+
sheet_id: Optional[str] = None,
|
1976
|
+
view_type: Optional[str] = None,
|
1977
|
+
request_id: Optional[str] = None,
|
1978
|
+
**metadata
|
1979
|
+
) -> 'ListTableViewsResponse':
|
1980
|
+
"""
|
1981
|
+
列出表格视图
|
1982
|
+
|
1983
|
+
Args:
|
1984
|
+
table_id: 按表格ID查询(可选)
|
1985
|
+
sheet_id: 按工作表ID查询(可选)
|
1986
|
+
view_type: 筛选视图类型(可选)
|
1987
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
1988
|
+
**metadata: 额外的元数据
|
1989
|
+
|
1990
|
+
Returns:
|
1991
|
+
ListTableViewsResponse
|
1992
|
+
"""
|
1993
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
1994
|
+
from ...schemas.taple import ListTableViewsResponse
|
1995
|
+
|
1996
|
+
if not table_id and not sheet_id:
|
1997
|
+
raise ValidationError("必须提供 table_id 或 sheet_id 之一")
|
1998
|
+
|
1999
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
2000
|
+
|
2001
|
+
request = taple_service_pb2.ListTableViewsRequest()
|
2002
|
+
|
2003
|
+
if table_id:
|
2004
|
+
request.table_id = table_id
|
2005
|
+
elif sheet_id:
|
2006
|
+
request.sheet_id = sheet_id
|
2007
|
+
|
2008
|
+
if view_type:
|
2009
|
+
request.view_type = view_type
|
2010
|
+
|
2011
|
+
response = await stub.ListTableViews(
|
2012
|
+
request,
|
2013
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata)
|
2014
|
+
)
|
2015
|
+
|
2016
|
+
return ListTableViewsResponse(
|
2017
|
+
views=[self._convert_table_view(view) for view in response.views],
|
2018
|
+
total_count=response.total_count
|
2019
|
+
)
|
2020
|
+
|
2021
|
+
@retry_with_backoff(max_retries=3)
|
2022
|
+
async def update_table_view(
|
2023
|
+
self,
|
2024
|
+
view_id: str,
|
2025
|
+
*,
|
2026
|
+
name: Optional[str] = None,
|
2027
|
+
filter_criteria: Optional[Dict[str, Any]] = None,
|
2028
|
+
sort_criteria: Optional[Dict[str, Any]] = None,
|
2029
|
+
visible_columns: Optional[List[str]] = None,
|
2030
|
+
group_criteria: Optional[Dict[str, Any]] = None,
|
2031
|
+
is_hidden: Optional[bool] = None,
|
2032
|
+
is_default: Optional[bool] = None,
|
2033
|
+
config: Optional[Dict[str, Any]] = None,
|
2034
|
+
idempotency_key: Optional[str] = None,
|
2035
|
+
request_id: Optional[str] = None,
|
2036
|
+
**metadata
|
2037
|
+
) -> 'TableViewResponse':
|
2038
|
+
"""
|
2039
|
+
更新表格视图
|
2040
|
+
|
2041
|
+
Args:
|
2042
|
+
view_id: 视图ID
|
2043
|
+
name: 新名称(可选)
|
2044
|
+
filter_criteria: 过滤条件(可选)
|
2045
|
+
sort_criteria: 排序条件(可选)
|
2046
|
+
visible_columns: 可见列列表(可选,传入空列表清空可见列设置)
|
2047
|
+
group_criteria: 分组条件(可选)
|
2048
|
+
is_hidden: 是否隐藏(可选)
|
2049
|
+
is_default: 是否默认视图(可选)
|
2050
|
+
config: 扩展配置(可选)
|
2051
|
+
idempotency_key: 幂等性键(可选)
|
2052
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
2053
|
+
**metadata: 额外的元数据
|
2054
|
+
|
2055
|
+
Returns:
|
2056
|
+
TableViewResponse
|
2057
|
+
"""
|
2058
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
2059
|
+
from ...schemas.taple import TableViewResponse
|
2060
|
+
from google.protobuf.struct_pb2 import ListValue
|
2061
|
+
|
2062
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
2063
|
+
|
2064
|
+
request = taple_service_pb2.UpdateTableViewRequest(view_id=view_id)
|
2065
|
+
|
2066
|
+
if name is not None:
|
2067
|
+
request.view_name = name
|
2068
|
+
|
2069
|
+
# 处理可选的 JSON 字段
|
2070
|
+
if filter_criteria is not None:
|
2071
|
+
request.filter_criteria.CopyFrom(self._convert_dict_to_struct(filter_criteria))
|
2072
|
+
if sort_criteria is not None:
|
2073
|
+
request.sort_criteria.CopyFrom(self._convert_dict_to_struct(sort_criteria))
|
2074
|
+
if visible_columns is not None:
|
2075
|
+
from google.protobuf.struct_pb2 import Value
|
2076
|
+
list_value = ListValue()
|
2077
|
+
for col in visible_columns:
|
2078
|
+
value = Value()
|
2079
|
+
value.string_value = str(col)
|
2080
|
+
list_value.values.append(value)
|
2081
|
+
request.visible_columns.CopyFrom(list_value)
|
2082
|
+
if group_criteria is not None:
|
2083
|
+
request.group_criteria.CopyFrom(self._convert_dict_to_struct(group_criteria))
|
2084
|
+
|
2085
|
+
# 处理布尔字段
|
2086
|
+
if is_hidden is not None:
|
2087
|
+
request.is_hidden = is_hidden
|
2088
|
+
if is_default is not None:
|
2089
|
+
request.is_default = is_default
|
2090
|
+
|
2091
|
+
if config is not None:
|
2092
|
+
request.config.CopyFrom(self._convert_dict_to_struct(config))
|
2093
|
+
|
2094
|
+
response = await stub.UpdateTableView(
|
2095
|
+
request,
|
2096
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata)
|
2097
|
+
)
|
2098
|
+
|
2099
|
+
return TableViewResponse(view=self._convert_table_view(response.view))
|
2100
|
+
|
2101
|
+
@retry_with_backoff(max_retries=3)
|
2102
|
+
async def delete_table_view(
|
2103
|
+
self,
|
2104
|
+
view_id: str,
|
2105
|
+
*,
|
2106
|
+
idempotency_key: Optional[str] = None,
|
2107
|
+
request_id: Optional[str] = None,
|
2108
|
+
**metadata
|
2109
|
+
) -> None:
|
2110
|
+
"""
|
2111
|
+
删除表格视图
|
2112
|
+
|
2113
|
+
Args:
|
2114
|
+
view_id: 视图ID
|
2115
|
+
idempotency_key: 幂等性键(可选)
|
2116
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
2117
|
+
**metadata: 额外的元数据
|
2118
|
+
"""
|
2119
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
2120
|
+
|
2121
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
2122
|
+
|
2123
|
+
request = taple_service_pb2.DeleteTableViewRequest(view_id=view_id)
|
2124
|
+
|
2125
|
+
await stub.DeleteTableView(
|
2126
|
+
request,
|
2127
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata)
|
2128
|
+
)
|
2129
|
+
|
2130
|
+
@retry_with_backoff(max_retries=3)
|
2131
|
+
async def update_table_view_config(
|
2132
|
+
self,
|
2133
|
+
view_id: str,
|
2134
|
+
config: Dict[str, Any],
|
2135
|
+
*,
|
2136
|
+
idempotency_key: Optional[str] = None,
|
2137
|
+
request_id: Optional[str] = None,
|
2138
|
+
**metadata
|
2139
|
+
) -> 'TableViewResponse':
|
2140
|
+
"""
|
2141
|
+
更新视图配置
|
2142
|
+
|
2143
|
+
Args:
|
2144
|
+
view_id: 视图ID
|
2145
|
+
config: 新配置
|
2146
|
+
idempotency_key: 幂等性键(可选)
|
2147
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
2148
|
+
**metadata: 额外的元数据
|
2149
|
+
|
2150
|
+
Returns:
|
2151
|
+
TableViewResponse
|
2152
|
+
"""
|
2153
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
2154
|
+
from ...schemas.taple import TableViewResponse
|
2155
|
+
|
2156
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
2157
|
+
|
2158
|
+
request = taple_service_pb2.UpdateTableViewConfigRequest(view_id=view_id)
|
2159
|
+
request.config.CopyFrom(self._convert_dict_to_struct(config))
|
2160
|
+
|
2161
|
+
response = await stub.UpdateTableViewConfig(
|
2162
|
+
request,
|
2163
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata)
|
2164
|
+
)
|
2165
|
+
|
2166
|
+
return TableViewResponse(view=self._convert_table_view(response.view))
|
2167
|
+
|
2168
|
+
def _convert_table_view(self, proto_view) -> 'TableView':
|
2169
|
+
"""转换 proto TableView 到 Python TableView 模型"""
|
2170
|
+
from ...schemas.taple import TableView
|
2171
|
+
from google.protobuf.json_format import MessageToDict
|
2172
|
+
|
2173
|
+
# 处理 visible_columns 的转换
|
2174
|
+
visible_columns = None
|
2175
|
+
if proto_view.visible_columns:
|
2176
|
+
visible_columns = [str(col) for col in proto_view.visible_columns.values]
|
2177
|
+
|
2178
|
+
return TableView(
|
2179
|
+
id=proto_view.id,
|
2180
|
+
table_id=proto_view.table_id,
|
2181
|
+
sheet_id=proto_view.sheet_id,
|
2182
|
+
org_id=proto_view.org_id,
|
2183
|
+
user_id=proto_view.user_id,
|
2184
|
+
file_id=proto_view.file_id,
|
2185
|
+
|
2186
|
+
# 视图配置字段
|
2187
|
+
filter_criteria=MessageToDict(proto_view.filter_criteria) if proto_view.filter_criteria else None,
|
2188
|
+
sort_criteria=MessageToDict(proto_view.sort_criteria) if proto_view.sort_criteria else None,
|
2189
|
+
visible_columns=visible_columns,
|
2190
|
+
group_criteria=MessageToDict(proto_view.group_criteria) if proto_view.group_criteria else None,
|
2191
|
+
|
2192
|
+
# 创建者信息
|
2193
|
+
created_by_role=proto_view.created_by_role,
|
2194
|
+
created_by=proto_view.created_by,
|
2195
|
+
|
2196
|
+
# 视图基本信息
|
2197
|
+
view_name=proto_view.view_name,
|
2198
|
+
view_type=proto_view.view_type,
|
2199
|
+
|
2200
|
+
# 视图状态
|
2201
|
+
is_hidden=proto_view.is_hidden,
|
2202
|
+
is_default=proto_view.is_default,
|
2203
|
+
|
2204
|
+
# 扩展配置
|
2205
|
+
config=MessageToDict(proto_view.config) if proto_view.config else None,
|
2206
|
+
|
2207
|
+
# 时间戳
|
2208
|
+
created_at=timestamp_to_datetime(proto_view.created_at),
|
2209
|
+
updated_at=timestamp_to_datetime(proto_view.updated_at),
|
2210
|
+
deleted_at=timestamp_to_datetime(proto_view.deleted_at) if proto_view.deleted_at else None
|
2211
|
+
)
|
2212
|
+
|
2213
|
+
@retry_with_backoff(max_retries=3)
|
2214
|
+
async def batch_create_table_views(
|
2215
|
+
self,
|
2216
|
+
sheet_id: str,
|
2217
|
+
views: List[Dict[str, Any]],
|
2218
|
+
*,
|
2219
|
+
request_id: Optional[str] = None,
|
2220
|
+
**metadata
|
2221
|
+
) -> 'BatchCreateTableViewsResponse':
|
2222
|
+
"""
|
2223
|
+
批量创建表格视图
|
2224
|
+
|
2225
|
+
Args:
|
2226
|
+
sheet_id: 所属工作表ID
|
2227
|
+
views: 要创建的视图列表,每个视图包含以下字段:
|
2228
|
+
- view_name: 视图名称
|
2229
|
+
- view_type: 视图类型
|
2230
|
+
- filter_criteria: 过滤条件(可选)
|
2231
|
+
- sort_criteria: 排序条件(可选)
|
2232
|
+
- visible_columns: 可见列列表(可选)
|
2233
|
+
- group_criteria: 分组条件(可选)
|
2234
|
+
- is_hidden: 是否隐藏(可选,默认False)
|
2235
|
+
- is_default: 是否默认视图(可选,默认False)
|
2236
|
+
- config: 扩展配置(可选)
|
2237
|
+
request_id: 请求ID(可选,如果不提供则自动生成)
|
2238
|
+
**metadata: 额外的元数据
|
2239
|
+
|
2240
|
+
Returns:
|
2241
|
+
BatchCreateTableViewsResponse
|
2242
|
+
"""
|
2243
|
+
from ...rpc.gen import taple_service_pb2, taple_service_pb2_grpc
|
2244
|
+
from ...schemas.taple import BatchCreateTableViewsResponse, BatchCreateTableViewResult
|
2245
|
+
|
2246
|
+
stub = await self.client.get_stub(taple_service_pb2_grpc.TapleServiceStub)
|
2247
|
+
|
2248
|
+
# 构建请求
|
2249
|
+
request = taple_service_pb2.BatchCreateTableViewsRequest(sheet_id=sheet_id)
|
2250
|
+
|
2251
|
+
for view_data in views:
|
2252
|
+
view_req = taple_service_pb2.CreateTableViewData(
|
2253
|
+
view_name=view_data['view_name'],
|
2254
|
+
view_type=view_data['view_type'],
|
2255
|
+
visible_columns=view_data.get('visible_columns', []),
|
2256
|
+
is_hidden=view_data.get('is_hidden', False),
|
2257
|
+
is_default=view_data.get('is_default', False),
|
2258
|
+
)
|
2259
|
+
|
2260
|
+
# 处理可选的 JSON 字段
|
2261
|
+
if 'filter_criteria' in view_data:
|
2262
|
+
view_req.filter_criteria.CopyFrom(self._convert_dict_to_struct(view_data['filter_criteria']))
|
2263
|
+
if 'sort_criteria' in view_data:
|
2264
|
+
view_req.sort_criteria.CopyFrom(self._convert_dict_to_struct(view_data['sort_criteria']))
|
2265
|
+
if 'group_criteria' in view_data:
|
2266
|
+
view_req.group_criteria.CopyFrom(self._convert_dict_to_struct(view_data['group_criteria']))
|
2267
|
+
if 'config' in view_data:
|
2268
|
+
view_req.config.CopyFrom(self._convert_dict_to_struct(view_data['config']))
|
2269
|
+
|
2270
|
+
request.views.append(view_req)
|
2271
|
+
|
2272
|
+
response = await stub.BatchCreateTableViews(
|
2273
|
+
request,
|
2274
|
+
metadata=self.client.build_metadata(request_id=request_id, **metadata)
|
2275
|
+
)
|
2276
|
+
|
2277
|
+
# 转换响应
|
2278
|
+
results = []
|
2279
|
+
for result in response.results:
|
2280
|
+
results.append(BatchCreateTableViewResult(
|
2281
|
+
success=result.success,
|
2282
|
+
view=self._convert_table_view(result.view) if result.view else None,
|
2283
|
+
error_message=result.error_message if result.error_message else None,
|
2284
|
+
view_name=result.view_name if result.view_name else None
|
2285
|
+
))
|
2286
|
+
|
2287
|
+
return BatchCreateTableViewsResponse(
|
2288
|
+
results=results,
|
2289
|
+
success_count=response.success_count,
|
2290
|
+
failed_count=response.failed_count
|
2291
|
+
)
|