dataops-sdk 0.3.0__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.

Potentially problematic release.


This version of dataops-sdk might be problematic. Click here for more details.

Files changed (79) hide show
  1. dataops_sdk/__init__.py +84 -0
  2. dataops_sdk/constants.py +6 -0
  3. dataops_sdk/exceptions.py +31 -0
  4. dataops_sdk/runner/__init__.py +46 -0
  5. dataops_sdk/runner/datasource_factory.py +83 -0
  6. dataops_sdk/runner/schemas/nacos/__init__.py +5 -0
  7. dataops_sdk/runner/schemas/nacos/config.py +40 -0
  8. dataops_sdk/runner/schemas/nacos/constants.py +235 -0
  9. dataops_sdk/runner/schemas/nacos/instance.py +103 -0
  10. dataops_sdk/runner/schemas/nacos/nacos_exception.py +44 -0
  11. dataops_sdk/runner/schemas/nacos/naming_param.py +62 -0
  12. dataops_sdk/runner/schemas/nacos/naming_request.py +84 -0
  13. dataops_sdk/runner/schemas/nacos/naming_response.py +50 -0
  14. dataops_sdk/runner/schemas/nacos/preserved_metadata_key.py +10 -0
  15. dataops_sdk/runner/schemas/nacos/service.py +119 -0
  16. dataops_sdk/runner/utils/__init__.py +42 -0
  17. dataops_sdk/runner/utils/common.py +209 -0
  18. dataops_sdk/runner/utils/dbConn_base.py +256 -0
  19. dataops_sdk/runner/utils/dbConn_sync.py +485 -0
  20. dataops_sdk/runner/utils/duckdb_manager.py +203 -0
  21. dataops_sdk/runner/utils/file_transfer_base.py +307 -0
  22. dataops_sdk/runner/utils/ftp_file_transfer.py +242 -0
  23. dataops_sdk/runner/utils/log.py +50 -0
  24. dataops_sdk/runner/utils/nacos.py +96 -0
  25. dataops_sdk/runner/utils/neo4j_sync.py +236 -0
  26. dataops_sdk/runner/utils/queue_base.py +224 -0
  27. dataops_sdk/runner/utils/queue_kafka.py +150 -0
  28. dataops_sdk/runner/utils/sftp_file_transfer.py +243 -0
  29. dataops_sdk/schemas/__init__.py +32 -0
  30. dataops_sdk/schemas/alarm.py +38 -0
  31. dataops_sdk/schemas/api.py +37 -0
  32. dataops_sdk/schemas/data_table.py +437 -0
  33. dataops_sdk/schemas/datasource.py +26 -0
  34. dataops_sdk/schemas/dict_.py +13 -0
  35. dataops_sdk/schemas/enums.py +120 -0
  36. dataops_sdk/schemas/group.py +40 -0
  37. dataops_sdk/schemas/hazard.py +151 -0
  38. dataops_sdk/schemas/meta.py +175 -0
  39. dataops_sdk/schemas/query.py +175 -0
  40. dataops_sdk/schemas/report.py +22 -0
  41. dataops_sdk/schemas/skill.py +70 -0
  42. dataops_sdk/schemas/table.py +65 -0
  43. dataops_sdk/schemas/user.py +52 -0
  44. dataops_sdk/schemas/widget.py +651 -0
  45. dataops_sdk/schemas/workflow.py +63 -0
  46. dataops_sdk/services/__init__.py +110 -0
  47. dataops_sdk/services/alarm.py +324 -0
  48. dataops_sdk/services/api.py +28 -0
  49. dataops_sdk/services/auth.py +120 -0
  50. dataops_sdk/services/data_table.py +485 -0
  51. dataops_sdk/services/dataset.py +127 -0
  52. dataops_sdk/services/datasource.py +57 -0
  53. dataops_sdk/services/dict_.py +69 -0
  54. dataops_sdk/services/hazard.py +260 -0
  55. dataops_sdk/services/meta.py +523 -0
  56. dataops_sdk/services/metrics.py +42 -0
  57. dataops_sdk/services/ref.py +66 -0
  58. dataops_sdk/services/report.py +36 -0
  59. dataops_sdk/services/skill.py +276 -0
  60. dataops_sdk/services/table.py +340 -0
  61. dataops_sdk/services/widget.py +143 -0
  62. dataops_sdk/services/workflow.py +102 -0
  63. dataops_sdk/session.py +292 -0
  64. dataops_sdk/tiptap/__init__.py +30 -0
  65. dataops_sdk/tiptap/builder.py +75 -0
  66. dataops_sdk/tiptap/constants.py +133 -0
  67. dataops_sdk/tiptap/markdown_parser.py +294 -0
  68. dataops_sdk/tiptap/models.py +43 -0
  69. dataops_sdk/tiptap/parse_utils.py +889 -0
  70. dataops_sdk/tiptap/render_utils.py +846 -0
  71. dataops_sdk/tiptap/renderers.py +51 -0
  72. dataops_sdk/tiptap/tool.py +629 -0
  73. dataops_sdk/utils/__init__.py +15 -0
  74. dataops_sdk/utils/common.py +211 -0
  75. dataops_sdk/utils/utils.py +120 -0
  76. dataops_sdk-0.3.0.dist-info/METADATA +25 -0
  77. dataops_sdk-0.3.0.dist-info/RECORD +79 -0
  78. dataops_sdk-0.3.0.dist-info/WHEEL +5 -0
  79. dataops_sdk-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,485 @@
1
+ """多维表格 (DataTable) 的 SDK 服务层.
2
+
3
+ 纯 Python 接口,返回原始 Pydantic 模型,不依赖 typer/Rich。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from collections.abc import Mapping, Sequence
9
+
10
+ from pydantic import JsonValue, TypeAdapter
11
+ from pydantic_core import to_json
12
+
13
+ from dataops_sdk.schemas import (
14
+ DataTableData,
15
+ Meta,
16
+ MetaCreate,
17
+ MetaType,
18
+ PageParam,
19
+ SqlQueryParam,
20
+ )
21
+ from dataops_sdk.services.meta import (
22
+ release_list_create,
23
+ release_list_get_by_code,
24
+ release_list_get_by_name,
25
+ )
26
+ from dataops_sdk.session import get_session
27
+ from dataops_sdk.utils import encrypt_body
28
+
29
+ __all__ = [
30
+ "service_get_data_table_by_name",
31
+ "service_get_data_table_by_code",
32
+ "service_create_data_table",
33
+ "service_get_data_table_data_by_code",
34
+ "service_get_data_table_data_by_name",
35
+ "service_get_data_table_total",
36
+ "service_get_data_table_reference_list",
37
+ "service_get_data_table_record_by_id",
38
+ "service_create_data_table_record",
39
+ "service_update_data_table_record_by_id",
40
+ "service_update_data_table_record_by_id_list",
41
+ "service_delete_data_table_record_by_id",
42
+ "service_delete_data_table_record_by_id_list",
43
+ ]
44
+
45
+
46
+ def service_get_data_table_by_name(datasource: str, name: str) -> Meta[DataTableData]:
47
+ """根据名称获取多维表格.
48
+
49
+ Args:
50
+ datasource: 数据源
51
+ name: 多维表格名称
52
+
53
+ Returns:
54
+ MetaDataTable 对象
55
+
56
+ Raises:
57
+ NotFoundError: 找不到对应多维表格时
58
+ DataOpsError: API 返回错误时
59
+ AuthenticationError: 未认证或认证失败时
60
+ """
61
+ return release_list_get_by_name(
62
+ MetaType.DATA_TABLE, name, _class=DataTableData, datasource=datasource
63
+ )
64
+
65
+
66
+ def service_get_data_table_by_code(code: str) -> Meta[DataTableData]:
67
+ """根据编码获取多维表格.
68
+
69
+ Args:
70
+ code: 多维表格编码
71
+
72
+ Returns:
73
+ MetaDataTable 对象
74
+
75
+ Raises:
76
+ NotFoundError: 找不到对应多维表格时
77
+ DataOpsError: API 返回错误时
78
+ AuthenticationError: 未认证或认证失败时
79
+ """
80
+ return release_list_get_by_code(MetaType.DATA_TABLE, code, _class=DataTableData)
81
+
82
+
83
+ def service_get_data_table_data_by_code(
84
+ code: str,
85
+ page_param: PageParam | None = None,
86
+ query_param: SqlQueryParam | None = None,
87
+ show_invisible: bool = False,
88
+ translate: bool = True,
89
+ *,
90
+ meta: Meta[DataTableData] | None = None,
91
+ ) -> list[Mapping[str, JsonValue]]:
92
+ """根据编码获取多维表格的数据.
93
+
94
+ Args:
95
+ code: 数据表编码
96
+ page_param: 分页参数,默认为 PageParam()(第一页,每页 20 条)
97
+ query_param: 查询过滤条件,默认为 SqlQueryParam()
98
+ datasource: 数据源标识,指定从哪个子系统查询(可选)
99
+ show_invisible: 是否显示未标记 visible 的字段,默认为 False
100
+ translate: 是否对 DICT 类型字段进行值翻译,默认为 True
101
+
102
+ Returns:
103
+ 字典列表,每条记录 key 为中文字段标题,value 已做字典翻译
104
+
105
+ Raises:
106
+ NotFoundError: 找不到对应多维表格时
107
+ DataOpsError: API 返回错误时
108
+ AuthenticationError: 未认证或认证失败时
109
+ """
110
+ if translate:
111
+ url = f"/data/table/records/{code}"
112
+ else:
113
+ url = f"/data/table/list/{code}"
114
+
115
+ if page_param is None:
116
+ page_param = PageParam()
117
+ if query_param is None:
118
+ query_param = SqlQueryParam()
119
+
120
+ meta = meta or service_get_data_table_by_code(code)
121
+
122
+ body = {
123
+ "subSystem": meta.subSystem,
124
+ "code": code,
125
+ "pageParam": page_param,
126
+ "queryParam": query_param,
127
+ }
128
+
129
+ with get_session(timeout=15) as session:
130
+ resp = session.post(url, content=to_json(encrypt_body(body)))
131
+ resp_body = resp.json()
132
+
133
+ adapter = TypeAdapter(list[Mapping[str, JsonValue]])
134
+
135
+ if translate:
136
+ datas = adapter.validate_python(resp_body.get("data", {}).get("list", []))
137
+ else:
138
+ datas = adapter.validate_python(resp_body.get("data", []))
139
+
140
+ # 过滤不需要显示的字段,建立字段名映射
141
+ all_fields = meta.data.fields
142
+ show_fields = all_fields if show_invisible else [f for f in all_fields if f.visible]
143
+ field_name_map = {f.dbName: f.title for f in show_fields}
144
+ show_db_names = frozenset(field_name_map.keys())
145
+
146
+ # 预处理字典字段映射(只执行一次过滤)
147
+ dict_fields_name: set[str] = set()
148
+ dict_field_map: dict[str, dict[str, str]] = {}
149
+ if translate:
150
+ relations: dict[str, dict[str, str]] = resp_body.get("data", {}).get("relations", {})
151
+ dict_fields = [f for f in all_fields if f.type == MetaType.DICT.value]
152
+ for key, relation in relations.items():
153
+ if key.startswith("dict"):
154
+ # 查找匹配的字段(通过 ref.code 匹配)
155
+ field = next(
156
+ (f for f in dict_fields if f.type_ext.get("ref", {}).get("code")),
157
+ None,
158
+ )
159
+ if field:
160
+ dict_field_map[field.dbName] = relation
161
+ dict_fields_name.add(field.dbName)
162
+
163
+ # 单次遍历完成所有转换: lowercase -> 过滤 -> 字典翻译 -> 字段名映射
164
+ datas = [
165
+ {
166
+ field_name_map[k_lower]: (
167
+ dict_field_map[k_lower][str(v)]["_LABEL"] if k_lower in dict_fields_name else v
168
+ )
169
+ for k, v in data.items()
170
+ if (k_lower := k.lower()) in show_db_names
171
+ }
172
+ for data in datas
173
+ ]
174
+
175
+ return datas
176
+
177
+
178
+ def service_get_data_table_data_by_name(
179
+ datasource: str,
180
+ name: str,
181
+ page_param: PageParam | None = None,
182
+ query_param: SqlQueryParam | None = None,
183
+ show_invisible: bool = False,
184
+ translate: bool = True,
185
+ ):
186
+ meta = service_get_data_table_by_name(datasource, name)
187
+ return service_get_data_table_data_by_code(
188
+ meta.code,
189
+ page_param=page_param,
190
+ query_param=query_param,
191
+ show_invisible=show_invisible,
192
+ translate=translate,
193
+ meta=meta,
194
+ )
195
+
196
+
197
+ def service_create_data_table(meta: MetaCreate[DataTableData]) -> dict:
198
+ """创建多维表格."""
199
+ return release_list_create(
200
+ meta,
201
+ _class=DataTableData,
202
+ )
203
+
204
+
205
+ # def service_update_data_table(
206
+ # code: str,
207
+ # title: str,
208
+ # data: dict,
209
+ # *,
210
+ # name: str | None = None,
211
+ # cuid: str | None = None,
212
+ # sub_type: str | None = None,
213
+ # ) -> dict:
214
+ # """更新多维表格.
215
+
216
+ # Args:
217
+ # code: 多维表格编码
218
+ # title: 中文标题
219
+ # data: meta.data 字典,结构参考 DataTableData
220
+ # name: 名称 (默认为 code)
221
+ # cuid: 元数据 CUID (更新时必传)
222
+ # sub_type: 子类型 (可选)
223
+
224
+ # Returns:
225
+ # API 返回的 data 字典
226
+
227
+ # Raises:
228
+ # DataOpsError: API 返回错误时
229
+ # AuthenticationError: 未认证或认证失败时
230
+ # """
231
+ # return release_list_update(
232
+ # MetaType.DATA_TABLE,
233
+ # code=code,
234
+ # name=name or code,
235
+ # title=title,
236
+ # data=data,
237
+ # cuid=cuid,
238
+ # sub_type=sub_type,
239
+ # )
240
+
241
+
242
+ def service_get_data_table_total(
243
+ code: str,
244
+ query_param: SqlQueryParam | None = None,
245
+ *,
246
+ meta: Meta[DataTableData] | None = None,
247
+ ) -> int:
248
+ """统计多维表格数据总数.
249
+
250
+ Args:
251
+ code: 数据表编码
252
+ query_param: 查询过滤条件,默认为 SqlQueryParam()
253
+
254
+ Returns:
255
+ 记录总数
256
+
257
+ Raises:
258
+ NotFoundError: 找不到对应多维表格时
259
+ DataOpsError: API 返回错误时
260
+ AuthenticationError: 未认证或认证失败时
261
+ """
262
+ meta = meta or service_get_data_table_by_code(code)
263
+
264
+ body = {
265
+ "subSystem": meta.subSystem,
266
+ "code": code,
267
+ "queryParam": query_param or SqlQueryParam(),
268
+ }
269
+
270
+ with get_session(timeout=15) as session:
271
+ resp = session.post(f"/data/table/total/{code}", content=to_json(encrypt_body(body)))
272
+ resp_body = resp.json()
273
+
274
+ return int(resp_body.get("data", 0))
275
+
276
+
277
+ def service_get_data_table_reference_list(
278
+ code: str,
279
+ subcode: str,
280
+ page_param: PageParam | None = None,
281
+ query_param: SqlQueryParam | None = None,
282
+ ) -> list[str]:
283
+ """查询多维表格的引用记录列表.
284
+
285
+ Args:
286
+ code: 主表编码
287
+ subcode: 子表编码
288
+ page_param: 分页参数,默认为 PageParam()(第一页,每页 20 条)
289
+ query_param: 查询过滤条件,默认为 SqlQueryParam()
290
+
291
+ Returns:
292
+ 引用编码集合列表
293
+
294
+ Raises:
295
+ DataOpsError: API 返回错误时
296
+ AuthenticationError: 未认证或认证失败时
297
+ """
298
+ if page_param is None:
299
+ page_param = PageParam()
300
+
301
+ body = {
302
+ "pageParam": page_param,
303
+ "queryParam": query_param or SqlQueryParam(),
304
+ }
305
+
306
+ with get_session(timeout=15) as session:
307
+ resp = session.post(
308
+ f"/data/table/referenceList/{code}/{subcode}",
309
+ content=to_json(encrypt_body(body)),
310
+ )
311
+ resp_body = resp.json()
312
+
313
+ return resp_body.get("data", [])
314
+
315
+
316
+ def service_get_data_table_record_by_id(code: str, id: str) -> dict[str, JsonValue]:
317
+ """根据 ID 获取多维表格单条记录.
318
+
319
+ Args:
320
+ code: 数据表编码
321
+ id: 主键 ID
322
+
323
+ Returns:
324
+ 单条记录字典
325
+
326
+ Raises:
327
+ NotFoundError: 找不到对应记录时
328
+ DataOpsError: API 返回错误时
329
+ AuthenticationError: 未认证或认证失败时
330
+ """
331
+ with get_session(timeout=15) as session:
332
+ resp = session.get(f"/data/table/getById/{code}/{id}")
333
+ resp_body = resp.json()
334
+
335
+ if resp_body.get("data") is None:
336
+ from dataops_sdk.exceptions import NotFoundError
337
+
338
+ raise NotFoundError(f"无法找到 {code} 中 ID 为 {id} 的记录")
339
+
340
+ return resp_body["data"]
341
+
342
+
343
+ def service_create_data_table_record(
344
+ code: str,
345
+ data: Mapping[str, JsonValue],
346
+ *,
347
+ meta: Meta[DataTableData] | None = None,
348
+ ) -> str:
349
+ """新增多维表格单条记录.
350
+
351
+ Args:
352
+ code: 数据表编码
353
+ data: 记录数据字典
354
+ meta: 多维表格元数据对象(可选,用于获取 subSystem)
355
+
356
+ Returns:
357
+ 新增记录的主键 ID
358
+
359
+ Raises:
360
+ DataOpsError: API 返回错误时
361
+ AuthenticationError: 未认证或认证失败时
362
+ """
363
+ if meta is None:
364
+ meta = service_get_data_table_by_code(code)
365
+
366
+ body = dict(subSystem=meta.subSystem, **data) if meta.subSystem else dict(**data)
367
+
368
+ with get_session(timeout=15) as session:
369
+ resp = session.post(f"/data/table/create/{code}", content=to_json(encrypt_body(body)))
370
+ resp_body = resp.json()
371
+
372
+ return str(resp_body.get("data", ""))
373
+
374
+
375
+ def service_update_data_table_record_by_id(
376
+ code: str,
377
+ id: str,
378
+ data: Mapping[str, JsonValue],
379
+ ) -> bool:
380
+ """按 ID 更新多维表格记录.
381
+
382
+ Args:
383
+ code: 数据表编码
384
+ id: 主键 ID
385
+ data: 要更新的字段数据
386
+
387
+ Returns:
388
+ 更新是否成功
389
+
390
+ Raises:
391
+ DataOpsError: API 返回错误时
392
+ AuthenticationError: 未认证或认证失败时
393
+ """
394
+ with get_session(timeout=15) as session:
395
+ resp = session.post(
396
+ f"/data/table/updateById/{code}/{id}",
397
+ content=to_json(encrypt_body(data)),
398
+ )
399
+ resp_body = resp.json()
400
+
401
+ return resp_body.get("data", False)
402
+
403
+
404
+ def service_update_data_table_record_by_id_list(
405
+ code: str,
406
+ id_list: Sequence[str],
407
+ data: Mapping[str, JsonValue],
408
+ ) -> bool:
409
+ """按 ID 列表批量更新多维表格记录.
410
+
411
+ Args:
412
+ code: 数据表编码
413
+ id_list: 主键 ID 列表
414
+ data: 要更新的字段数据
415
+
416
+ Returns:
417
+ 更新是否成功
418
+
419
+ Raises:
420
+ DataOpsError: API 返回错误时
421
+ AuthenticationError: 未认证或认证失败时
422
+ """
423
+ body = {
424
+ "idList": id_list,
425
+ "data": data,
426
+ }
427
+
428
+ with get_session(timeout=15) as session:
429
+ resp = session.post(
430
+ f"/data/table/updateByIdList/{code}",
431
+ content=to_json(encrypt_body(body)),
432
+ )
433
+ resp_body = resp.json()
434
+
435
+ return resp_body.get("data", False)
436
+
437
+
438
+ def service_delete_data_table_record_by_id(code: str, id: str) -> bool:
439
+ """按 ID 删除多维表格单条记录.
440
+
441
+ Args:
442
+ code: 数据表编码
443
+ id: 主键 ID
444
+
445
+ Returns:
446
+ 删除是否成功
447
+
448
+ Raises:
449
+ DataOpsError: API 返回错误时
450
+ AuthenticationError: 未认证或认证失败时
451
+ """
452
+ with get_session(timeout=15) as session:
453
+ resp = session.post(f"/data/table/deleteById/{code}/{id}")
454
+ resp_body = resp.json()
455
+
456
+ return resp_body.get("data", False)
457
+
458
+
459
+ def service_delete_data_table_record_by_id_list(
460
+ code: str,
461
+ id_list: Sequence[str],
462
+ ) -> bool:
463
+ """按 ID 列表批量删除多维表格记录.
464
+
465
+ Args:
466
+ code: 数据表编码
467
+ id_list: 主键 ID 列表
468
+
469
+ Returns:
470
+ 删除是否成功
471
+
472
+ Raises:
473
+ DataOpsError: API 返回错误时
474
+ AuthenticationError: 未认证或认证失败时
475
+ """
476
+ body = {"idList": id_list}
477
+
478
+ with get_session(timeout=15) as session:
479
+ resp = session.post(
480
+ f"/data/table/deleteByIdList/{code}",
481
+ content=to_json(encrypt_body(body)),
482
+ )
483
+ resp_body = resp.json()
484
+
485
+ return resp_body.get("data", False)
@@ -0,0 +1,127 @@
1
+ from collections.abc import Mapping
2
+
3
+ from pydantic import ConfigDict, JsonValue, TypeAdapter
4
+ from pydantic_core import to_json
5
+
6
+ from dataops_sdk.exceptions import DataOpsError
7
+ from dataops_sdk.schemas import (
8
+ DataDataBase,
9
+ Meta,
10
+ MetaRelease,
11
+ MetaType,
12
+ PageParam,
13
+ SqlQueryParam,
14
+ )
15
+ from dataops_sdk.services.meta import release_list_get_by_code, release_list_list
16
+ from dataops_sdk.session import get_session
17
+ from dataops_sdk.utils import encrypt_body
18
+
19
+ __all__ = [
20
+ "service_count_dataset_by_code",
21
+ "service_get_dataset_data_by_code",
22
+ "service_get_dataset_detail_by_code",
23
+ "service_list_datasets",
24
+ ]
25
+
26
+
27
+ def service_list_datasets() -> list[MetaRelease]:
28
+ """搜索数据源中的表.
29
+
30
+ Returns:
31
+ MetaRelease 对象列表
32
+
33
+ Raises:
34
+ DataOpsError: API 请求失败时
35
+ AuthenticationError: 未认证时
36
+ """
37
+ return release_list_list(MetaType.DATASET)
38
+
39
+
40
+ def service_get_dataset_detail_by_code(code: str) -> Meta[DataDataBase]:
41
+ """指定数据集详情.
42
+
43
+ Args:
44
+ code: 表编码
45
+
46
+ Returns:
47
+ 数据源 DDL 模型
48
+
49
+ Raises:
50
+ ValueError: 无效类型
51
+ NotFoundError: 数据源不存在
52
+ DataOpsError: API 请求失败
53
+ AuthenticationError: 未认证
54
+ """
55
+ meta = release_list_get_by_code(MetaType.DATASET, code, _class=DataDataBase)
56
+ return meta
57
+
58
+
59
+ def service_count_dataset_by_code(
60
+ code: str,
61
+ query_param: SqlQueryParam | None = None,
62
+ ) -> int:
63
+ """按数据集编码统计数据量。"""
64
+ if query_param is None:
65
+ query_param = SqlQueryParam()
66
+
67
+ body = {
68
+ "type": MetaType.DATASET,
69
+ "code": code,
70
+ "queryParam": query_param,
71
+ }
72
+
73
+ with get_session(timeout=15) as session:
74
+ response = session.post(
75
+ "/data/dataset/countData",
76
+ content=to_json(encrypt_body(body)),
77
+ )
78
+ response_body = response.json()
79
+
80
+ if response.status_code != 200:
81
+ raise DataOpsError(
82
+ f"统计失败,{response_body.get('msg', f'HTTP {response.status_code}')}",
83
+ response.status_code,
84
+ )
85
+
86
+ return response_body.get("data") or 0
87
+
88
+
89
+ def service_get_dataset_data_by_code(
90
+ code: str,
91
+ page_param: PageParam | None = None,
92
+ query_param: SqlQueryParam | None = None,
93
+ ) -> list[Mapping[str, JsonValue]]:
94
+ """按数据集编码读取真实数据,支持分页和条件查询。"""
95
+ if page_param is None:
96
+ page_param = PageParam()
97
+ if query_param is None:
98
+ query_param = SqlQueryParam()
99
+
100
+ # 请求体遵循 DataOps 数据集接口契约;具体的认证请求头由 get_session 统一注入。
101
+ body = {
102
+ "type": MetaType.DATASET,
103
+ "code": code,
104
+ "pageParam": page_param,
105
+ "queryParam": query_param,
106
+ }
107
+
108
+ # 复用统一会话发送请求,encrypt_body 负责按项目约定包装请求体。
109
+ with get_session(timeout=15) as session:
110
+ response = session.post(
111
+ "/data/dataset/findData",
112
+ content=to_json(encrypt_body(body)),
113
+ )
114
+ response_body = response.json()
115
+
116
+ if response.status_code != 200:
117
+ raise DataOpsError(
118
+ f"查询失败,{response_body.get('msg', f'HTTP {response.status_code}')}",
119
+ response.status_code,
120
+ )
121
+
122
+ # 后端返回的是动态列数据,因此使用通用 Mapping,而不是固定业务 schema。
123
+ adapter = TypeAdapter(
124
+ list[Mapping[str, JsonValue]],
125
+ config=ConfigDict(str_to_lower=True),
126
+ )
127
+ return adapter.validate_python(response_body.get("data") or [])
@@ -0,0 +1,57 @@
1
+ from dataclasses import dataclass
2
+
3
+ from dataops_sdk.exceptions import AuthenticationError, DataOpsError
4
+ from dataops_sdk.schemas import DataDataSource, Meta
5
+ from dataops_sdk.schemas.enums import InnerMetaType
6
+ from dataops_sdk.services.meta import release_list_get_by_name
7
+ from dataops_sdk.session import get_application, get_session
8
+ from dataops_sdk.utils import encrypt_body
9
+ from pydantic_core import to_json
10
+
11
+
12
+ def service_get_datasource_config_by_application_id(
13
+ *, prod_id: str | None = None, param_name: str | None = None
14
+ ) -> Meta[DataDataSource]:
15
+ url = "/sys/application/getDatasource"
16
+ if prod_id is None:
17
+ application = get_application()
18
+ prod_id = application.CUID
19
+ body = {"prodId": prod_id, "datasourceParamName": param_name}
20
+ with get_session() as session:
21
+ resp = session.post(url, content=to_json(encrypt_body(body)))
22
+ resp_body = resp.json()
23
+ if resp.status_code == 401:
24
+ raise AuthenticationError("认证失败,请先登录")
25
+ if resp.status_code != 200:
26
+ raise DataOpsError(resp_body.get("msg", f"HTTP {resp.status_code}"), resp.status_code)
27
+ resp.json()
28
+ data = resp_body["data"]
29
+ if not isinstance(data, dict):
30
+ raise DataOpsError(f"返回的数据格式不正确, 预期为字典, 实际为 {type(data)}")
31
+
32
+ return Meta[DataDataSource].model_validate(data)
33
+
34
+
35
+ @dataclass
36
+ class DatasourceConfig:
37
+ main: Meta[DataDataSource]
38
+ hazard_read: Meta[DataDataSource]
39
+ hazard_write: Meta[DataDataSource]
40
+
41
+
42
+ def service_get_main_datasource_config_by_application(app_id: str | None = None) -> DatasourceConfig:
43
+ if app_id is None:
44
+ application = get_application()
45
+ app_id = application.CUID
46
+ # 主数据源
47
+ datasource_main = service_get_datasource_config_by_application_id(prod_id=app_id)
48
+ # 隐患读数据源
49
+ datasource_hazard_read = service_get_datasource_config_by_application_id(prod_id=app_id, param_name="datasource_hazard_read")
50
+ # 隐患写数据源
51
+ datasource_hazard_write = service_get_datasource_config_by_application_id(prod_id=app_id, param_name="datasource_hazard_write")
52
+ return DatasourceConfig(datasource_main, datasource_hazard_read, datasource_hazard_write)
53
+
54
+
55
+ def service_get_datasource_by_name(name: str) -> Meta[DataDataSource]:
56
+ """获取数据源 Meta"""
57
+ return release_list_get_by_name(InnerMetaType.DATASOURCE.value, name, _class=DataDataSource)