watchmen-collector-kernel 16.4.6__py3-none-any.whl → 16.4.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.
Files changed (48) hide show
  1. watchmen_collector_kernel/common/__init__.py +2 -2
  2. watchmen_collector_kernel/common/constants.py +16 -0
  3. watchmen_collector_kernel/model/__init__.py +15 -1
  4. watchmen_collector_kernel/model/change_data_json.py +28 -0
  5. watchmen_collector_kernel/model/change_data_record.py +19 -0
  6. watchmen_collector_kernel/model/collector_model_config.py +12 -0
  7. watchmen_collector_kernel/model/collector_table_config.py +78 -0
  8. watchmen_collector_kernel/model/competitive_lock.py +11 -0
  9. watchmen_collector_kernel/model/condition.py +73 -0
  10. watchmen_collector_kernel/model/scheduled_task.py +36 -0
  11. watchmen_collector_kernel/model/trigger_event.py +11 -0
  12. watchmen_collector_kernel/model/trigger_model.py +8 -0
  13. watchmen_collector_kernel/model/trigger_table.py +11 -0
  14. watchmen_collector_kernel/service/__init__.py +8 -0
  15. watchmen_collector_kernel/service/criteria_builder.py +53 -0
  16. watchmen_collector_kernel/service/data_capture.py +60 -0
  17. watchmen_collector_kernel/service/extract_source.py +71 -0
  18. watchmen_collector_kernel/service/extract_utils.py +70 -0
  19. watchmen_collector_kernel/service/lock_clean.py +39 -0
  20. watchmen_collector_kernel/service/lock_helper.py +28 -0
  21. watchmen_collector_kernel/service/task_housekeeping.py +61 -0
  22. watchmen_collector_kernel/service/task_service.py +72 -0
  23. watchmen_collector_kernel/service/trigger_collector.py +147 -0
  24. watchmen_collector_kernel/storage/__init__.py +17 -0
  25. watchmen_collector_kernel/storage/change_data_json_service.py +171 -0
  26. watchmen_collector_kernel/storage/change_data_record_service.py +185 -0
  27. watchmen_collector_kernel/storage/collector_model_config_service.py +107 -0
  28. watchmen_collector_kernel/storage/collector_table_config_service.py +168 -0
  29. watchmen_collector_kernel/storage/competitive_lock_service.py +83 -0
  30. watchmen_collector_kernel/storage/scheduled_task_service.py +155 -0
  31. watchmen_collector_kernel/storage/trigger_event_service.py +86 -0
  32. watchmen_collector_kernel/storage/trigger_model_service.py +96 -0
  33. watchmen_collector_kernel/storage/trigger_table_service.py +113 -0
  34. {watchmen_collector_kernel-16.4.6.dist-info → watchmen_collector_kernel-16.4.8.dist-info}/LICENSE +0 -0
  35. {watchmen_collector_kernel-16.4.6.dist-info → watchmen_collector_kernel-16.4.8.dist-info}/METADATA +9 -9
  36. watchmen_collector_kernel-16.4.8.dist-info/RECORD +38 -0
  37. {watchmen_collector_kernel-16.4.6.dist-info → watchmen_collector_kernel-16.4.8.dist-info}/WHEEL +0 -0
  38. watchmen_collector_kernel/common/settings.py +0 -14
  39. watchmen_collector_kernel/connector/__init__.py +0 -1
  40. watchmen_collector_kernel/connector/handler.py +0 -42
  41. watchmen_collector_kernel/connector/housekeeping.py +0 -58
  42. watchmen_collector_kernel/connector/s3_connector.py +0 -210
  43. watchmen_collector_kernel/lock/__init__.py +0 -3
  44. watchmen_collector_kernel/lock/distributed_lock.py +0 -23
  45. watchmen_collector_kernel/lock/oss_collector_lock_service.py +0 -127
  46. watchmen_collector_kernel/lock/unique_key_distributed_lock.py +0 -39
  47. watchmen_collector_kernel/model/oss_collector_competitive_lock.py +0 -15
  48. watchmen_collector_kernel-16.4.6.dist-info/RECORD +0 -17
@@ -0,0 +1,61 @@
1
+ from datetime import date, datetime, timedelta
2
+ from logging import getLogger
3
+ from threading import Thread
4
+ from typing import List
5
+
6
+ from time import sleep
7
+
8
+ from watchmen_collector_kernel.storage import get_competitive_lock_service
9
+ from watchmen_collector_kernel.model import CompetitiveLock
10
+
11
+
12
+ class CleanTask:
13
+
14
+ def __init__(self):
15
+ self.lock_service = get_competitive_lock_service()
16
+ self.processed_date = []
17
+ self.cleanTaskInterval = 3600
18
+
19
+ def run(self):
20
+ try:
21
+ while True:
22
+ self.clean_task()
23
+ sleep(self.cleanTaskInterval)
24
+ except Exception as e:
25
+ getLogger(__name__).error(e, exc_info=True, stack_info=True)
26
+ sleep(30)
27
+ self.restart()
28
+
29
+ def clean_task(self):
30
+ query_datetime = datetime.now()
31
+ delta = timedelta(
32
+ hours=query_datetime.hour,
33
+ minutes=query_datetime.minute,
34
+ seconds=query_datetime.second,
35
+ microseconds=query_datetime.microsecond)
36
+ query_date = query_datetime.date() - delta
37
+ if self.is_processed(query_date):
38
+ return "Done"
39
+ else:
40
+ tasks = self.get_task_list(query_date)
41
+ for task in tasks:
42
+ self.lock_service.delete_by_id(task.lockId)
43
+ self.processed_date.append(query_date.strftime('%Y-%m-%d'))
44
+
45
+ def get_task_list(self, clean_date) -> List[CompetitiveLock]:
46
+ return self.lock_service.find_completed_task(clean_date)
47
+
48
+ def is_processed(self, query_date: date) -> bool:
49
+ date_str = query_date.strftime('%Y-%m-%d')
50
+ if date_str in self.processed_date:
51
+ return True
52
+ else:
53
+ return False
54
+
55
+ def restart(self):
56
+ Thread(target=CleanTask.run, args=(self,), daemon=True).start()
57
+
58
+
59
+ def init_task_housekeeping():
60
+ clean_task = CleanTask()
61
+ Thread(target=CleanTask.run, args=(clean_task,), daemon=True).start()
@@ -0,0 +1,72 @@
1
+ from logging import getLogger
2
+ from traceback import format_exc
3
+ from typing import Callable, Dict, Optional, List
4
+
5
+ from watchmen_auth import PrincipalService
6
+ from watchmen_collector_kernel.model import ScheduledTask, TaskStatus
7
+ from watchmen_collector_kernel.model.scheduled_task import Dependence
8
+ from watchmen_collector_kernel.storage import get_scheduled_task_service
9
+ from watchmen_model.common import ScheduledTaskId
10
+ from watchmen_storage import TransactionalStorageSPI, SnowflakeGenerator
11
+ from watchmen_utilities import ArrayHelper
12
+
13
+ logger = getLogger(__name__)
14
+
15
+
16
+ class TaskService:
17
+
18
+ def __init__(self,
19
+ storage: TransactionalStorageSPI,
20
+ snowflake_generator: SnowflakeGenerator,
21
+ principal_service: PrincipalService
22
+ ):
23
+ self.storage = storage
24
+ self.snowflake_generator = snowflake_generator
25
+ self.principal_service = principal_service
26
+ self.scheduled_task_service = get_scheduled_task_service(self.storage,
27
+ self.snowflake_generator,
28
+ self.principal_service)
29
+
30
+ # noinspection PyMethodMayBeStatic
31
+ def consume_task(self, task: ScheduledTask, executed: Callable[[str, Dict, str], None]) -> ScheduledTask:
32
+ try:
33
+ executed(task.topicCode, task.content, task.tenantId)
34
+ task.status = int(TaskStatus.SUCCESS)
35
+ return self.scheduled_task_service.update_task(task)
36
+ except Exception as e:
37
+ logger.error(e, exc_info=True, stack_info=True)
38
+ task.status = int(TaskStatus.FAILED)
39
+ task.result = format_exc()
40
+ return self.scheduled_task_service.update_task(task)
41
+
42
+ def is_dependencies_finished(self, task: ScheduledTask) -> bool:
43
+ return ArrayHelper(task.parentTaskId).every(self.is_parent_task_finished) \
44
+ and self.is_dependence_finished(task.dependOn, task.tenantId)
45
+
46
+ def is_parent_task_finished(self, task_id: ScheduledTaskId) -> bool:
47
+ existed_task = self.scheduled_task_service.find_task_by_id(task_id)
48
+ return self.is_finished(existed_task)
49
+
50
+ # noinspection PyMethodMayBeStatic
51
+ def is_finished(self, task: ScheduledTask) -> bool:
52
+ if task.status == TaskStatus.SUCCESS or task.status == TaskStatus.FAILED:
53
+ return True
54
+ else:
55
+ return False
56
+
57
+ def is_dependence_finished(self, depend_on: Optional[List[Dependence]], tenant_id: str) -> bool:
58
+ if ArrayHelper(depend_on).every(lambda dependence: self.is_dependent_task_finished(dependence, tenant_id)):
59
+ return True
60
+ else:
61
+ return False
62
+
63
+ def is_dependent_task_finished(self, dependence: Dependence, tenant_id: str) -> bool:
64
+ return self.scheduled_task_service.is_dependent_task_finished(dependence.modelName,
65
+ dependence.objectId,
66
+ tenant_id)
67
+
68
+
69
+ def get_task_service(storage: TransactionalStorageSPI,
70
+ snowflake_generator: SnowflakeGenerator,
71
+ principal_service: PrincipalService) -> TaskService:
72
+ return TaskService(storage, snowflake_generator, principal_service)
@@ -0,0 +1,147 @@
1
+ from typing import Callable, List
2
+
3
+ from watchmen_auth import PrincipalService
4
+ from watchmen_collector_kernel.model import TriggerEvent, CollectorModelConfig, TriggerModel, TriggerTable, \
5
+ CollectorTableConfig
6
+
7
+ from watchmen_collector_kernel.storage import TriggerModelService, TriggerTableService, TriggerEventService, \
8
+ get_trigger_model_service, get_collector_model_config_service, get_trigger_table_service, \
9
+ CollectorTableConfigService, get_collector_table_config_service
10
+ from watchmen_meta.common import TupleService
11
+ from watchmen_model.common import Storable
12
+
13
+ from watchmen_rest.util import validate_tenant_id
14
+
15
+
16
+ # noinspection SpellCheckingInspection
17
+ def redress_storable_id(tuple_service: TupleService,
18
+ a_tuple: Storable) -> None:
19
+ tuple_id = tuple_service.get_storable_id(a_tuple)
20
+ if tuple_service.is_storable_id_faked(tuple_id):
21
+ tuple_service.redress_storable_id(a_tuple)
22
+
23
+
24
+ def new_trigger_model(model_name: str, event_trigger_id: str) -> TriggerModel:
25
+ return TriggerModel(
26
+ modelName=model_name,
27
+ is_finished=False,
28
+ eventTriggerId=event_trigger_id
29
+ )
30
+
31
+
32
+ def get_trigger_model(event_trigger: TriggerEvent, model_config: CollectorModelConfig) -> TriggerModel:
33
+ return new_trigger_model(model_config.modelName, event_trigger.eventTriggerId)
34
+
35
+
36
+ def save_trigger_model(trigger_model_service: TriggerModelService,
37
+ trigger_model: TriggerModel,
38
+ principal_service: PrincipalService) -> TriggerModel:
39
+ validate_tenant_id(trigger_model, principal_service)
40
+ redress_storable_id(trigger_model_service, trigger_model)
41
+ # noinspection PyTypeChecker
42
+ return trigger_model_service.create(trigger_model)
43
+
44
+
45
+ def get_trigger_model_action(trigger_event_service: TriggerEventService,
46
+ trigger_event: TriggerEvent) -> Callable[[CollectorModelConfig], TriggerModel]:
47
+ def create_trigger_model_action(model_config: CollectorModelConfig) -> TriggerModel:
48
+ trigger_model = get_trigger_model(trigger_event, model_config)
49
+ trigger_model_service = get_trigger_model_service(trigger_event_service.storage,
50
+ trigger_event_service.snowflakeGenerator,
51
+ trigger_event_service.principalService)
52
+ return save_trigger_model(trigger_model_service,
53
+ trigger_model,
54
+ trigger_event_service.principalService)
55
+
56
+ return create_trigger_model_action
57
+
58
+
59
+ def new_trigger_table(table_name: str,
60
+ model_name: str,
61
+ model_trigger_id: str,
62
+ event_trigger_id: str) -> TriggerTable:
63
+ return TriggerTable(
64
+ tableName=table_name,
65
+ dataCount=0,
66
+ modelName=model_name,
67
+ isExtracted=False,
68
+ modelTriggerId=model_trigger_id,
69
+ eventTriggerId=event_trigger_id
70
+ )
71
+
72
+
73
+ def get_trigger_table(model_trigger: TriggerModel, table_config: CollectorTableConfig) -> TriggerTable:
74
+ return new_trigger_table(table_config.tableName,
75
+ table_config.modelName,
76
+ model_trigger.modelTriggerId,
77
+ model_trigger.eventTriggerId)
78
+
79
+
80
+ def save_trigger_table(trigger_table_service: TriggerTableService,
81
+ trigger_table: TriggerTable,
82
+ principal_service: PrincipalService) -> None:
83
+ validate_tenant_id(trigger_table, principal_service)
84
+ redress_storable_id(trigger_table_service, trigger_table)
85
+ trigger_table_service.create(trigger_table)
86
+
87
+
88
+ def get_trigger_table_action(trigger_model_service: TriggerModelService,
89
+ trigger_model: TriggerModel) -> Callable[[CollectorTableConfig], TriggerTable]:
90
+ def create_trigger_table_action(table_config: CollectorTableConfig) -> TriggerTable:
91
+ trigger_table = get_trigger_table(trigger_model, table_config)
92
+ trigger_table_service = get_trigger_table_service(trigger_model_service.storage,
93
+ trigger_model_service.snowflakeGenerator,
94
+ trigger_model_service.principalService)
95
+ # noinspection PyTypeChecker
96
+ return save_trigger_table(trigger_table_service,
97
+ trigger_table,
98
+ trigger_table_service.principalService)
99
+
100
+ return create_trigger_table_action
101
+
102
+
103
+ def get_table_configs_by_model(collector_table_config_service: CollectorTableConfigService,
104
+ model_config: CollectorModelConfig) -> List[CollectorTableConfig]:
105
+ return collector_table_config_service.find_by_model_name(model_config.modelName)
106
+
107
+
108
+ def trigger_collector(trigger_event_service: TriggerEventService,
109
+ trigger_event: TriggerEvent,
110
+ principal_service: PrincipalService, ) -> TriggerEvent:
111
+ trigger_event_service.begin_transaction()
112
+ try:
113
+ # noinspection PyTypeChecker
114
+ trigger_event = trigger_event_service.create(trigger_event)
115
+ model_config_service = get_collector_model_config_service(trigger_event_service.storage,
116
+ trigger_event_service.snowflakeGenerator,
117
+ trigger_event_service.principalService)
118
+ model_configs = model_config_service.find_by_tenant(principal_service.get_tenant_id())
119
+ # noinspection PyTypeChecker
120
+ trigger_model_action = get_trigger_model_action(trigger_event_service, trigger_event)
121
+ trigger_model_service = get_trigger_model_service(trigger_event_service.storage,
122
+ trigger_event_service.snowflakeGenerator,
123
+ trigger_event_service.principalService)
124
+ # noinspection PyTypeChecker
125
+ table_config_service = get_collector_table_config_service(trigger_event_service.storage,
126
+ trigger_event_service.snowflakeGenerator,
127
+ trigger_event_service.principalService)
128
+ for model_config in model_configs:
129
+ trigger_model = trigger_model_action(model_config)
130
+ trigger_table_action = get_trigger_table_action(trigger_model_service, trigger_model)
131
+ table_configs = get_table_configs_by_model(table_config_service, model_config)
132
+ for table_config in table_configs:
133
+ trigger_table_action(table_config)
134
+
135
+ trigger_event_service.commit_transaction()
136
+ except Exception as e:
137
+ trigger_event_service.rollback_transaction()
138
+ raise e
139
+
140
+ # noinspection PyTypeChecker
141
+ return trigger_event
142
+
143
+
144
+ def get_trigger_collector() -> Callable[[TriggerEventService,
145
+ TriggerEvent,
146
+ PrincipalService], TriggerEvent]:
147
+ return trigger_collector
@@ -0,0 +1,17 @@
1
+ from .competitive_lock_service import get_competitive_lock_service, CompetitiveLockService
2
+ from .scheduled_task_service import get_scheduled_task_service, ScheduledTaskService
3
+
4
+
5
+ from .collector_model_config_service import get_collector_model_config_service, CollectorModelConfigService
6
+ from .collector_table_config_service import get_collector_table_config_service, CollectorTableConfigService
7
+
8
+
9
+ from .trigger_event_service import get_trigger_event_service, TriggerEventService
10
+ from .trigger_model_service import get_trigger_model_service, TriggerModelService
11
+ from .trigger_table_service import get_trigger_table_service, TriggerTableService
12
+ from .change_data_record_service import get_change_data_record_service, ChangeDataRecordService
13
+ from .change_data_json_service import get_change_data_json_service, ChangeDataJsonService
14
+
15
+
16
+
17
+
@@ -0,0 +1,171 @@
1
+ from typing import List, Dict, Any, Optional
2
+
3
+ from watchmen_auth import PrincipalService
4
+ from watchmen_collector_kernel.common import IS_POSTED, CHANGE_JSON_ID, TENANT_ID, MODEL_TRIGGER_ID
5
+ from watchmen_collector_kernel.model import ChangeDataJson
6
+ from watchmen_meta.common import TupleService, TupleShaper
7
+ from watchmen_meta.common.storage_service import StorableId
8
+ from watchmen_model.common import Storable, ChangeJsonId
9
+ from watchmen_storage import EntityName, EntityRow, EntityShaper, TransactionalStorageSPI, SnowflakeGenerator, \
10
+ ColumnNameLiteral, EntityCriteriaExpression, EntityStraightValuesFinder, EntityStraightColumn, EntitySortColumn, \
11
+ EntitySortMethod
12
+
13
+
14
+ class ChangeDataJsonShaper(EntityShaper):
15
+ def serialize(self, entity: ChangeDataJson) -> EntityRow:
16
+ return TupleShaper.serialize_tenant_based(entity,
17
+ {
18
+ 'change_json_id': entity.changeJsonId,
19
+ 'resource_id': entity.resourceId,
20
+ 'model_name': entity.modelName,
21
+ 'object_id': entity.objectId,
22
+ 'table_name': entity.tableName,
23
+ 'data_id': entity.dataId,
24
+ 'content': entity.content,
25
+ 'depend_on': entity.dependOn,
26
+ 'is_posted': entity.isPosted,
27
+ 'task_id': entity.taskId,
28
+ 'table_trigger_id': entity.tableTriggerId,
29
+ 'model_trigger_id': entity.modelTriggerId,
30
+ 'event_trigger_id': entity.eventTriggerId
31
+ })
32
+
33
+ def deserialize(self, row: EntityRow) -> ChangeDataJson:
34
+ # noinspection PyTypeChecker
35
+ return TupleShaper.deserialize_tenant_based(row,
36
+ ChangeDataJson(
37
+ changeJsonId=row.get('change_json_id'),
38
+ resourceId=row.get('resource_id'),
39
+ modelName=row.get('model_name'),
40
+ objectId=row.get('object_id'),
41
+ tableName=row.get('table_name'),
42
+ dataId=row.get('data_id'),
43
+ content=row.get('content'),
44
+ dependOn=row.get('depend_on'),
45
+ isPosted=row.get('is_posted'),
46
+ taskId=row.get('task_id'),
47
+ tableTriggerId=row.get('table_trigger_id'),
48
+ modelTriggerId=row.get('model_trigger_id'),
49
+ eventTriggerId=row.get('event_trigger_id')
50
+ ))
51
+
52
+
53
+ CHANGE_DATA_JSON_TABLE = 'change_data_json'
54
+ CHANGE_DATA_JSON_ENTITY_SHAPER = ChangeDataJsonShaper()
55
+
56
+
57
+ class ChangeDataJsonService(TupleService):
58
+
59
+ def should_record_operation(self) -> bool:
60
+ return False
61
+
62
+ def get_entity_name(self) -> EntityName:
63
+ return CHANGE_DATA_JSON_TABLE
64
+
65
+ def get_entity_shaper(self) -> EntityShaper:
66
+ return CHANGE_DATA_JSON_ENTITY_SHAPER
67
+
68
+ # noinspection SpellCheckingInspection
69
+ def get_storable_id_column_name(self) -> EntityName:
70
+ return 'change_json_id'
71
+
72
+ def get_storable_id(self, storable: ChangeDataJson) -> StorableId:
73
+ # noinspection PyTypeChecker
74
+ return storable.changeJsonId
75
+
76
+ # noinspection SpellCheckingInspection
77
+ def set_storable_id(self, storable: ChangeDataJson, storable_id: ChangeJsonId) -> Storable:
78
+ storable.changeRecordId = storable_id
79
+ return storable
80
+
81
+ def update_change_data_json(self, storable: ChangeDataJson) -> ChangeDataJson:
82
+ self.begin_transaction()
83
+ try:
84
+ self.update(storable)
85
+ self.commit_transaction()
86
+ return storable
87
+ except Exception as e:
88
+ self.rollback_transaction()
89
+ raise e
90
+
91
+ def find_not_posted_json(self, model_trigger_id: int) -> List[Dict[str, Any]]:
92
+ self.begin_transaction()
93
+ try:
94
+ return self.storage.find_straight_values(EntityStraightValuesFinder(
95
+ name=self.get_entity_name(),
96
+ shaper=self.get_entity_shaper(),
97
+ criteria=[
98
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName=IS_POSTED), right=False),
99
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName=MODEL_TRIGGER_ID), right=model_trigger_id)
100
+ ],
101
+ straightColumns=[EntityStraightColumn(columnName=CHANGE_JSON_ID),
102
+ EntityStraightColumn(columnName=TENANT_ID)]
103
+ ))
104
+ finally:
105
+ self.close_transaction()
106
+
107
+ def find_json_by_id(self, change_json_id: str) -> ChangeDataJson:
108
+ self.begin_transaction()
109
+ try:
110
+ # noinspection PyTypeChecker
111
+ return self.find_by_id(change_json_id)
112
+ finally:
113
+ self.close_transaction()
114
+
115
+ def find_id_by_resource_id(self, resource_id: str) -> Optional[ChangeDataJson]:
116
+ try:
117
+ self.storage.connect()
118
+ return self.storage.find_one(self.get_entity_finder(
119
+ criteria=[
120
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName='resource_id'), right=resource_id)
121
+ ]
122
+ ))
123
+ finally:
124
+ self.storage.close()
125
+
126
+ def find_by_object_id(self, model_name: str, object_id: str, model_trigger_id: int) -> List:
127
+ try:
128
+ self.storage.connect()
129
+ return self.storage.find(self.get_entity_finder(
130
+ criteria=[
131
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName='model_name'), right=model_name),
132
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName='object_id'), right=object_id),
133
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName='model_trigger_id'), right=model_trigger_id)
134
+ ],
135
+ sort=[EntitySortColumn(name='sequence', method=EntitySortMethod.ASC)]
136
+ ))
137
+ finally:
138
+ self.storage.close()
139
+
140
+ def is_event_finished(self, event_trigger_id: int) -> bool:
141
+ self.begin_transaction()
142
+ try:
143
+ # noinspection PyTypeChecker
144
+ return self.storage.count(self.get_entity_finder(
145
+ criteria=[
146
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName='event_trigger_id'), right=event_trigger_id),
147
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName=IS_POSTED), right=False)
148
+ ]
149
+ )) == 0
150
+ finally:
151
+ self.close_transaction()
152
+
153
+ def is_model_finished(self, model_trigger_id: int) -> bool:
154
+ self.begin_transaction()
155
+ try:
156
+ # noinspection PyTypeChecker
157
+ return self.storage.count(self.get_entity_finder(
158
+ criteria=[
159
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName='model_trigger_id'), right=model_trigger_id),
160
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName=IS_POSTED), right=False)
161
+ ]
162
+ )) == 0
163
+ finally:
164
+ self.close_transaction()
165
+
166
+
167
+ def get_change_data_json_service(storage: TransactionalStorageSPI,
168
+ snowflake_generator: SnowflakeGenerator,
169
+ principal_service: PrincipalService
170
+ ) -> ChangeDataJsonService:
171
+ return ChangeDataJsonService(storage, snowflake_generator, principal_service)
@@ -0,0 +1,185 @@
1
+ from typing import List, Optional, Dict
2
+
3
+ from watchmen_auth import PrincipalService
4
+ from watchmen_collector_kernel.common import CHANGE_RECORD_ID, TENANT_ID, IS_MERGED
5
+ from watchmen_collector_kernel.model import ChangeDataRecord
6
+ from watchmen_meta.common import TupleService, TupleShaper
7
+ from watchmen_meta.common.storage_service import StorableId
8
+ from watchmen_model.common import Storable, ChangeRecordId
9
+ from watchmen_storage import EntityName, EntityRow, EntityShaper, TransactionalStorageSPI, SnowflakeGenerator, \
10
+ EntityCriteriaExpression, ColumnNameLiteral, EntityStraightValuesFinder, EntityStraightColumn, EntityColumnType
11
+ from watchmen_utilities import ArrayHelper
12
+
13
+
14
+ class ChangeDataRecordShaper(EntityShaper):
15
+ def serialize(self, entity: ChangeDataRecord) -> EntityRow:
16
+ return TupleShaper.serialize_tenant_based(entity,
17
+ {
18
+ 'change_record_id': entity.changeRecordId,
19
+ 'model_name': entity.modelName,
20
+ 'table_name': entity.tableName,
21
+ 'data_id': entity.dataId,
22
+ 'root_table_name': entity.rootTableName,
23
+ 'root_data_id': entity.rootDataId,
24
+ 'is_merged': entity.isMerged,
25
+ 'result': entity.result,
26
+ 'table_trigger_id': entity.tableTriggerId,
27
+ 'model_trigger_id': entity.modelTriggerId,
28
+ 'event_trigger_id': entity.eventTriggerId
29
+ })
30
+
31
+ def deserialize(self, row: EntityRow) -> ChangeDataRecord:
32
+ # noinspection PyTypeChecker
33
+ return TupleShaper.deserialize_tenant_based(row,
34
+ ChangeDataRecord(
35
+ changeRecordId=row.get('change_record_id'),
36
+ modelName=row.get('model_name'),
37
+ tableName=row.get('table_name'),
38
+ dataId=row.get('data_id'),
39
+ rootTableName=row.get('root_table_name'),
40
+ rootDataId=row.get('root_data_id'),
41
+ isMerged=row.get('is_merged'),
42
+ result=row.get('result'),
43
+ tableTriggerId=row.get('table_trigger_id'),
44
+ modelTriggerId=row.get('model_trigger_id'),
45
+ eventTriggerId=row.get('event_trigger_id')
46
+ ))
47
+
48
+
49
+ CHANGE_DATA_RECORD_TABLE = 'change_data_record'
50
+ CHANGE_DATA_RECORD_ENTITY_SHAPER = ChangeDataRecordShaper()
51
+
52
+
53
+ class ChangeDataRecordService(TupleService):
54
+
55
+ def should_record_operation(self) -> bool:
56
+ return False
57
+
58
+ def get_entity_name(self) -> EntityName:
59
+ return CHANGE_DATA_RECORD_TABLE
60
+
61
+ def get_entity_shaper(self) -> EntityShaper:
62
+ return CHANGE_DATA_RECORD_ENTITY_SHAPER
63
+
64
+ # noinspection SpellCheckingInspection
65
+ def get_storable_id_column_name(self) -> EntityName:
66
+ return 'change_record_id'
67
+
68
+ # noinspection SpellCheckingInspection
69
+ def get_storable_id(self, storable: ChangeDataRecord) -> StorableId:
70
+ # noinspection PyTypeChecker
71
+ return storable.changeRecordId
72
+
73
+ # noinspection SpellCheckingInspection
74
+ def set_storable_id(self, storable: ChangeDataRecord, storable_id: ChangeRecordId) -> Storable:
75
+ storable.changeRecordId = storable_id
76
+ return storable
77
+
78
+ def create_change_record(self, record: ChangeDataRecord) -> None:
79
+ self.begin_transaction()
80
+ try:
81
+ self.create(record)
82
+ self.commit_transaction()
83
+ except Exception as e:
84
+ self.rollback_transaction()
85
+ raise e
86
+
87
+ def update_change_record(self, record: ChangeDataRecord) -> Optional[ChangeDataRecord]:
88
+ self.begin_transaction()
89
+ try:
90
+ result = self.update(record)
91
+ self.commit_transaction()
92
+ # noinspection PyTypeChecker
93
+ return result
94
+ except Exception as e:
95
+ self.rollback_transaction()
96
+ raise e
97
+
98
+ def find_unmerged_records(self) -> List:
99
+ self.begin_transaction()
100
+ try:
101
+ return self.storage.find_straight_values(EntityStraightValuesFinder(
102
+ name=self.get_entity_name(),
103
+ shaper=self.get_entity_shaper(),
104
+ criteria=[
105
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName=IS_MERGED), right=False)
106
+ ],
107
+ straightColumns=[EntityStraightColumn(columnName=CHANGE_RECORD_ID),
108
+ EntityStraightColumn(columnName=TENANT_ID)]
109
+ ))
110
+ finally:
111
+ self.close_transaction()
112
+
113
+ def count_unmerged_records(self) -> int:
114
+ self.begin_transaction()
115
+ try:
116
+ # noinspection PyTypeChecker
117
+ return self.storage.count(self.get_entity_finder(
118
+ criteria=[
119
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName=IS_MERGED), right=False)
120
+ ]
121
+ ))
122
+ finally:
123
+ self.close_transaction()
124
+
125
+ def find_change_record_by_id(self, change_record_id: ChangeRecordId) -> ChangeDataRecord:
126
+ self.begin_transaction()
127
+ try:
128
+ # noinspection PyTypeChecker
129
+ return self.find_by_id(change_record_id)
130
+ finally:
131
+ self.close_transaction()
132
+
133
+ def find_existed_records(self, table_trigger_id: int) -> List[Dict]:
134
+ self.begin_transaction()
135
+ try:
136
+ # noinspection PyTypeChecker
137
+ result = self.storage.find_straight_values(
138
+ EntityStraightValuesFinder(
139
+ name=self.get_entity_name(),
140
+ shaper=self.get_entity_shaper(),
141
+ criteria=[
142
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName='table_trigger_id'),
143
+ right=table_trigger_id)
144
+ ],
145
+ straightColumns=[EntityStraightColumn(columnName='data_id', columnType=EntityColumnType.JSON)]
146
+ )
147
+ )
148
+ return ArrayHelper(result).map(lambda x: x.get('data_id')).to_list()
149
+ finally:
150
+ self.close_transaction()
151
+
152
+ def is_event_finished(self, event_trigger_id: int) -> bool:
153
+ self.begin_transaction()
154
+ try:
155
+ # noinspection PyTypeChecker
156
+ return self.storage.count(self.get_entity_finder(
157
+ criteria=[
158
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName='event_trigger_id'),
159
+ right=event_trigger_id),
160
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName=IS_MERGED), right=False)
161
+ ]
162
+ )) == 0
163
+ finally:
164
+ self.close_transaction()
165
+
166
+ def is_model_finished(self, model_trigger_id: int) -> bool:
167
+ self.begin_transaction()
168
+ try:
169
+ # noinspection PyTypeChecker
170
+ return self.storage.count(self.get_entity_finder(
171
+ criteria=[
172
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName='model_trigger_id'),
173
+ right=model_trigger_id),
174
+ EntityCriteriaExpression(left=ColumnNameLiteral(columnName=IS_MERGED), right=False)
175
+ ]
176
+ )) == 0
177
+ finally:
178
+ self.close_transaction()
179
+
180
+
181
+ def get_change_data_record_service(storage: TransactionalStorageSPI,
182
+ snowflake_generator: SnowflakeGenerator,
183
+ principal_service: PrincipalService
184
+ ) -> ChangeDataRecordService:
185
+ return ChangeDataRecordService(storage, snowflake_generator, principal_service)