rococo 1.0.4__tar.gz → 1.0.6__tar.gz
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.
- {rococo-1.0.4 → rococo-1.0.6}/PKG-INFO +1 -1
- {rococo-1.0.4 → rococo-1.0.6}/rococo/config/config.py +16 -14
- {rococo-1.0.4 → rococo-1.0.6}/rococo/data/mysql.py +29 -26
- {rococo-1.0.4 → rococo-1.0.6}/rococo/messaging/sqs.py +12 -1
- {rococo-1.0.4 → rococo-1.0.6}/rococo/repositories/mysql/mysql_repository.py +37 -28
- {rococo-1.0.4 → rococo-1.0.6}/rococo.egg-info/PKG-INFO +1 -1
- {rococo-1.0.4 → rococo-1.0.6}/setup.py +1 -1
- {rococo-1.0.4 → rococo-1.0.6}/LICENSE +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/README.md +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/__init__.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/config/__init__.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/data/__init__.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/data/base.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/data/surrealdb.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/emailing/__init__.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/emailing/base.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/emailing/config.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/emailing/enums.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/emailing/factory.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/emailing/mailjet.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/emailing/ses.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/messaging/__init__.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/messaging/base.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/messaging/rabbitmq.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/__init__.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/email.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/login_method.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/organization.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/otp_method.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/person.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/person_organization_role.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/recovery_code.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/surrealdb/__init__.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/surrealdb/email.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/surrealdb/login_method.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/surrealdb/organization.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/surrealdb/otp_method.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/surrealdb/person.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/surrealdb/person_organization_role.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/surrealdb/surreal_versioned_model.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/models/versioned_model.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/repositories/__init__.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/repositories/base_repository.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/repositories/mysql/__init__.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/repositories/mysql/organization_repository.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/repositories/surrealdb/__init__.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/repositories/surrealdb/organization_repository.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/repositories/surrealdb/person_organization_role_repository.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo/repositories/surrealdb/surreal_db_repository.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo.egg-info/SOURCES.txt +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo.egg-info/dependency_links.txt +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo.egg-info/requires.txt +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/rococo.egg-info/top_level.txt +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/setup.cfg +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/tests/__init__.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/tests/base_repository_test.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/tests/config_test.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/tests/model_test.py +0 -0
- {rococo-1.0.4 → rococo-1.0.6}/tests/surreal_db_repository_test.py +0 -0
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Config class that allows to load from a .toml file, and/or use a .env file.
|
|
3
3
|
"""
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
4
6
|
import os
|
|
5
7
|
import re
|
|
6
|
-
import json
|
|
7
8
|
from abc import abstractmethod
|
|
8
|
-
from typing import Optional
|
|
9
|
-
|
|
9
|
+
from typing import List, Optional
|
|
10
|
+
|
|
10
11
|
from dotenv import load_dotenv
|
|
11
12
|
|
|
12
13
|
logger = logging.getLogger(__name__)
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
class BaseConfig
|
|
16
|
+
class BaseConfig:
|
|
16
17
|
"""
|
|
17
18
|
Config class that allows to load from a .toml file, and/or use a .env file.
|
|
18
19
|
"""
|
|
20
|
+
|
|
19
21
|
def __init__(self):
|
|
20
22
|
load_dotenv()
|
|
21
23
|
self.project_version = None
|
|
@@ -40,7 +42,7 @@ class BaseConfig():
|
|
|
40
42
|
logger.warning("Variable %s not found.", var_name)
|
|
41
43
|
return None
|
|
42
44
|
|
|
43
|
-
def load_toml(self, toml_folder_dir: str, log_version_string: bool=True) -> bool:
|
|
45
|
+
def load_toml(self, toml_folder_dir: str, log_version_string: bool = True) -> bool:
|
|
44
46
|
"""
|
|
45
47
|
Loads the toml file for the project
|
|
46
48
|
Args:
|
|
@@ -87,19 +89,18 @@ class BaseConfig():
|
|
|
87
89
|
logger.warning("Warning: var %s not found.", var_name)
|
|
88
90
|
return False
|
|
89
91
|
|
|
90
|
-
def get_var_as_list(self, var_name: str) ->
|
|
92
|
+
def get_var_as_list(self, var_name: str) -> Optional[List]:
|
|
91
93
|
"""
|
|
92
94
|
Returns a comma-delimited var as list
|
|
93
95
|
"""
|
|
94
|
-
if var_name in self.env_vars.keys():
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
except ValueError:
|
|
98
|
-
logger.error(
|
|
99
|
-
"Error: Invalid input format. Please provide a comma-delimited string.")
|
|
100
|
-
logger.warning("Warning: var %s not found.", var_name)
|
|
101
|
-
return None
|
|
96
|
+
if var_name not in self.env_vars.keys():
|
|
97
|
+
logger.warning("Warning: var %s not found.", var_name)
|
|
98
|
+
return None
|
|
102
99
|
|
|
100
|
+
try:
|
|
101
|
+
return [env_var.strip() for env_var in self.env_vars[var_name].split(",")]
|
|
102
|
+
except ValueError:
|
|
103
|
+
logger.error("Error: Invalid input format. Please provide a comma-delimited string.")
|
|
103
104
|
|
|
104
105
|
def convert_var_from_json_string(self, var_name: str) -> bool:
|
|
105
106
|
"""
|
|
@@ -120,3 +121,4 @@ class BaseConfig():
|
|
|
120
121
|
"""
|
|
121
122
|
Abstract method for validation of the env vars.
|
|
122
123
|
"""
|
|
124
|
+
pass
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Any, Dict, List, Tuple, Union
|
|
2
|
+
from typing import Any, Dict, List, Tuple, Union, Optional
|
|
3
3
|
from uuid import UUID
|
|
4
|
+
|
|
4
5
|
import pymysql
|
|
5
6
|
|
|
6
7
|
from rococo.data.base import DbAdapter
|
|
@@ -19,7 +20,6 @@ class MySqlAdapter(DbAdapter):
|
|
|
19
20
|
self._connection = None
|
|
20
21
|
self._cursor = None
|
|
21
22
|
|
|
22
|
-
|
|
23
23
|
def __enter__(self):
|
|
24
24
|
"""Context manager entry point for creating DB connection."""
|
|
25
25
|
self._connection = pymysql.connect(
|
|
@@ -34,7 +34,6 @@ class MySqlAdapter(DbAdapter):
|
|
|
34
34
|
|
|
35
35
|
return self
|
|
36
36
|
|
|
37
|
-
|
|
38
37
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
39
38
|
"""Context manager exit point for closing DB connection."""
|
|
40
39
|
|
|
@@ -46,7 +45,6 @@ class MySqlAdapter(DbAdapter):
|
|
|
46
45
|
self._connection.close()
|
|
47
46
|
self._connection = None
|
|
48
47
|
|
|
49
|
-
|
|
50
48
|
@property
|
|
51
49
|
def connect(self):
|
|
52
50
|
return pymysql.connect(
|
|
@@ -80,10 +78,16 @@ class MySqlAdapter(DbAdapter):
|
|
|
80
78
|
elif isinstance(value, type(None)):
|
|
81
79
|
return f"{key} IS NULL"
|
|
82
80
|
else:
|
|
83
|
-
raise Exception(f"
|
|
81
|
+
raise Exception(f"Unsupported type {type(value)} for condition key: {key}, value: {value}")
|
|
84
82
|
|
|
85
83
|
def move_entity_to_audit_table(self, table, entity_id):
|
|
86
|
-
|
|
84
|
+
# Get the column names from the table
|
|
85
|
+
self._call_cursor('execute', f"SHOW COLUMNS FROM {table}")
|
|
86
|
+
|
|
87
|
+
column_list = ", ".join(column.get('Field') for column in self._cursor.fetchall())
|
|
88
|
+
|
|
89
|
+
query = f"""INSERT INTO {table}_audit ({column_list}) (SELECT {column_list} FROM {table} WHERE entity_id="{str(entity_id).replace('-', '')}");"""
|
|
90
|
+
|
|
87
91
|
self._call_cursor('execute', query)
|
|
88
92
|
self._connection.commit()
|
|
89
93
|
|
|
@@ -109,13 +113,13 @@ class MySqlAdapter(DbAdapter):
|
|
|
109
113
|
return response
|
|
110
114
|
|
|
111
115
|
def get_one(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
) -> Dict[str, Any]:
|
|
116
|
+
self,
|
|
117
|
+
table: str,
|
|
118
|
+
conditions: Dict[str, Any],
|
|
119
|
+
sort: List[Tuple[str, str]] = None,
|
|
120
|
+
join_statements: list = None,
|
|
121
|
+
additional_fields: list = None
|
|
122
|
+
) -> Optional[Dict[str, Any]]:
|
|
119
123
|
fields = [f'{table}.*']
|
|
120
124
|
if additional_fields:
|
|
121
125
|
fields += additional_fields
|
|
@@ -123,7 +127,7 @@ class MySqlAdapter(DbAdapter):
|
|
|
123
127
|
query = f"SELECT {', '.join(fields)} FROM {table}"
|
|
124
128
|
for join_stmt in join_statements:
|
|
125
129
|
query += f"""\n{join_stmt}\n"""
|
|
126
|
-
|
|
130
|
+
|
|
127
131
|
condition_strs = []
|
|
128
132
|
if conditions:
|
|
129
133
|
condition_strs = [f"{self._build_condition_string(table, k, v)}" for k, v in conditions.items()]
|
|
@@ -144,15 +148,15 @@ class MySqlAdapter(DbAdapter):
|
|
|
144
148
|
return db_response
|
|
145
149
|
|
|
146
150
|
def get_many(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
151
|
+
self,
|
|
152
|
+
table: str,
|
|
153
|
+
conditions: Dict[str, Any] = None,
|
|
154
|
+
sort: List[Tuple[str, str]] = None,
|
|
155
|
+
limit: int = None,
|
|
156
|
+
offset: int = None,
|
|
157
|
+
active: bool = True,
|
|
158
|
+
join_statements: list = None,
|
|
159
|
+
additional_fields: list = None
|
|
156
160
|
) -> List[Dict[str, Any]]:
|
|
157
161
|
|
|
158
162
|
fields = [f'{table}.*']
|
|
@@ -178,8 +182,6 @@ class MySqlAdapter(DbAdapter):
|
|
|
178
182
|
if offset is not None:
|
|
179
183
|
query += f" OFFSET {offset}"
|
|
180
184
|
|
|
181
|
-
print(query)
|
|
182
|
-
|
|
183
185
|
db_response = self.parse_db_response(self.execute_query(query))
|
|
184
186
|
if not db_response:
|
|
185
187
|
return []
|
|
@@ -209,4 +211,5 @@ class MySqlAdapter(DbAdapter):
|
|
|
209
211
|
def delete(self, table: str, data: Dict[str, Any]) -> bool:
|
|
210
212
|
# Set active = false
|
|
211
213
|
data['active'] = False
|
|
212
|
-
|
|
214
|
+
self.save(table, data)
|
|
215
|
+
return True
|
|
@@ -3,6 +3,7 @@ import json
|
|
|
3
3
|
import logging
|
|
4
4
|
import uuid
|
|
5
5
|
import boto3
|
|
6
|
+
from dotenv import dotenv_values
|
|
6
7
|
|
|
7
8
|
from . import MessageAdapter
|
|
8
9
|
|
|
@@ -14,7 +15,8 @@ class SqsConnection(MessageAdapter):
|
|
|
14
15
|
|
|
15
16
|
def __init__(self, aws_access_key_id: str = None,
|
|
16
17
|
aws_access_key_secret: str = None,
|
|
17
|
-
region_name: str = None
|
|
18
|
+
region_name: str = None,
|
|
19
|
+
consume_config_file_path: str = None):
|
|
18
20
|
"""Initializes a new SQS connection.
|
|
19
21
|
|
|
20
22
|
Args:
|
|
@@ -26,6 +28,7 @@ class SqsConnection(MessageAdapter):
|
|
|
26
28
|
self._aws_access_key_id = aws_access_key_id
|
|
27
29
|
self._aws_access_key_secret = aws_access_key_secret
|
|
28
30
|
self._region_name = region_name
|
|
31
|
+
self._consume_config_file_path = consume_config_file_path
|
|
29
32
|
self._sqs = boto3.resource('sqs',
|
|
30
33
|
aws_access_key_id=self._aws_access_key_id,
|
|
31
34
|
aws_secret_access_key=self._aws_access_key_secret,
|
|
@@ -38,6 +41,11 @@ class SqsConnection(MessageAdapter):
|
|
|
38
41
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
39
42
|
pass
|
|
40
43
|
|
|
44
|
+
def _read_consume_config(self):
|
|
45
|
+
if self._consume_config_file_path is None:
|
|
46
|
+
return {}
|
|
47
|
+
return dotenv_values(self._consume_config_file_path)
|
|
48
|
+
|
|
41
49
|
def send_message(self, queue_name: str, message: dict):
|
|
42
50
|
"""Sends a message to the specified SQS queue.
|
|
43
51
|
|
|
@@ -83,6 +91,9 @@ class SqsConnection(MessageAdapter):
|
|
|
83
91
|
)
|
|
84
92
|
if not responses:
|
|
85
93
|
logger.info("No messages left in queue.")
|
|
94
|
+
if self._read_consume_config().get('EXIT_WHEN_FINISHED') == '1':
|
|
95
|
+
logger.info("EXIT_WHEN_FINISHED=1 and no messages left in queue. Exiting...")
|
|
96
|
+
return
|
|
86
97
|
continue
|
|
87
98
|
|
|
88
99
|
response = {}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""MySqlDbRepository class"""
|
|
2
2
|
|
|
3
|
+
import re
|
|
3
4
|
from dataclasses import fields
|
|
5
|
+
from datetime import datetime
|
|
4
6
|
from typing import Any, Dict, List, Type, Union
|
|
5
7
|
from uuid import UUID
|
|
6
|
-
import re
|
|
7
|
-
from datetime import datetime
|
|
8
8
|
|
|
9
|
-
from rococo.data import
|
|
9
|
+
from rococo.data import MySqlAdapter
|
|
10
10
|
from rococo.messaging import MessageAdapter
|
|
11
11
|
from rococo.models import VersionedModel
|
|
12
12
|
from rococo.repositories import BaseRepository
|
|
@@ -17,7 +17,7 @@ class MySqlRepository(BaseRepository):
|
|
|
17
17
|
|
|
18
18
|
def __init__(
|
|
19
19
|
self,
|
|
20
|
-
db_adapter:
|
|
20
|
+
db_adapter: MySqlAdapter,
|
|
21
21
|
model: Type[VersionedModel],
|
|
22
22
|
message_adapter: MessageAdapter,
|
|
23
23
|
queue_name: str,
|
|
@@ -34,7 +34,7 @@ class MySqlRepository(BaseRepository):
|
|
|
34
34
|
for field in fields(instance):
|
|
35
35
|
if data.get(field.name) is None:
|
|
36
36
|
continue
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
field_value = data[field.name]
|
|
39
39
|
|
|
40
40
|
if field.metadata.get('field_type') in ['entity_id', 'uuid']:
|
|
@@ -49,7 +49,7 @@ class MySqlRepository(BaseRepository):
|
|
|
49
49
|
field_value = str(field_value).replace('-', '')
|
|
50
50
|
if isinstance(field_value, datetime):
|
|
51
51
|
field_value = field_value.strftime('%Y-%m-%d %H:%M:%S')
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
data[field.name] = field_value
|
|
54
54
|
return data
|
|
55
55
|
|
|
@@ -60,7 +60,7 @@ class MySqlRepository(BaseRepository):
|
|
|
60
60
|
model()
|
|
61
61
|
is_partial = not all(_field.name in data for _field in fields(model))
|
|
62
62
|
for field in fields(model):
|
|
63
|
-
if data.get(field.name) is None:
|
|
63
|
+
if data.get(field.name) is None:
|
|
64
64
|
continue
|
|
65
65
|
|
|
66
66
|
if field.metadata.get('field_type') == 'entity_id':
|
|
@@ -80,7 +80,8 @@ class MySqlRepository(BaseRepository):
|
|
|
80
80
|
field_data = {'entity_id': field_value}
|
|
81
81
|
for _field in fields(field_model_class):
|
|
82
82
|
if f'joined_{field.name}_{field_table_name}_{_field.name}' in data:
|
|
83
|
-
field_data[_field.name] = data[
|
|
83
|
+
field_data[_field.name] = data[
|
|
84
|
+
f'joined_{field.name}_{field_table_name}_{_field.name}']
|
|
84
85
|
for data_field, data_value in data.items():
|
|
85
86
|
if data_field.startswith('joined_'):
|
|
86
87
|
field_data[data_field] = data_value
|
|
@@ -104,8 +105,8 @@ class MySqlRepository(BaseRepository):
|
|
|
104
105
|
else:
|
|
105
106
|
raise NotImplementedError
|
|
106
107
|
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
def get_one(self, conditions: Dict[str, Any] = None, join_fields: List[str] = None,
|
|
109
|
+
additional_fields: List[str] = None) -> Union[VersionedModel, None]:
|
|
109
110
|
"""get one"""
|
|
110
111
|
|
|
111
112
|
if additional_fields is None:
|
|
@@ -118,7 +119,8 @@ class MySqlRepository(BaseRepository):
|
|
|
118
119
|
if '.' in field_name:
|
|
119
120
|
parent_field, child_field = field_name.rsplit('.', 1)
|
|
120
121
|
if parent_field not in joined_fields:
|
|
121
|
-
raise Exception(
|
|
122
|
+
raise Exception(
|
|
123
|
+
f"Parent field {parent_field} needs to be joined before joining {child_field} field. Raised while joining {field_name} for model {self.model.__name__}.")
|
|
122
124
|
parent_model = joined_fields[parent_field]
|
|
123
125
|
else:
|
|
124
126
|
parent_model = self.model
|
|
@@ -129,8 +131,11 @@ class MySqlRepository(BaseRepository):
|
|
|
129
131
|
raise Exception(f"Invalid join field {child_field} specified for model {parent_model.__name__}.")
|
|
130
132
|
join_model = join_field.metadata.get('relationship').get('model')
|
|
131
133
|
join_table_name = re.sub(r'(?<!^)(?=[A-Z])', '_', join_model.__name__).lower()
|
|
132
|
-
join_stmt_list.append(
|
|
133
|
-
|
|
134
|
+
join_stmt_list.append(
|
|
135
|
+
f'INNER JOIN {join_table_name} ON {parent_table_name}.{child_field}={join_table_name}.entity_id AND {join_table_name}.active=true')
|
|
136
|
+
join_field_list = [
|
|
137
|
+
f'{join_table_name}.{_field.name} AS joined_{child_field}_{join_table_name}_{_field.name}' for
|
|
138
|
+
_field in fields(join_model)]
|
|
134
139
|
additional_fields += join_field_list
|
|
135
140
|
joined_fields[field_name] = join_model
|
|
136
141
|
|
|
@@ -156,7 +161,8 @@ class MySqlRepository(BaseRepository):
|
|
|
156
161
|
raise NotImplementedError
|
|
157
162
|
|
|
158
163
|
data = self._execute_within_context(
|
|
159
|
-
self.adapter.get_one, self.table_name, conditions, join_statements=join_stmt_list,
|
|
164
|
+
self.adapter.get_one, self.table_name, conditions, join_statements=join_stmt_list,
|
|
165
|
+
additional_fields=additional_fields
|
|
160
166
|
)
|
|
161
167
|
|
|
162
168
|
self.model() # Calls __post_init__ of model to import related models and update fields.
|
|
@@ -167,15 +173,14 @@ class MySqlRepository(BaseRepository):
|
|
|
167
173
|
return None
|
|
168
174
|
return self.model.from_dict(data)
|
|
169
175
|
|
|
170
|
-
|
|
171
176
|
def get_many(
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
self,
|
|
178
|
+
conditions: Dict[str, Any] = None,
|
|
179
|
+
join_fields: List[str] = None,
|
|
180
|
+
additional_fields: List[str] = None,
|
|
181
|
+
sort: List[tuple] = None,
|
|
182
|
+
limit: int = None,
|
|
183
|
+
offset: int = None
|
|
179
184
|
) -> List[VersionedModel]:
|
|
180
185
|
"""get many"""
|
|
181
186
|
if additional_fields is None:
|
|
@@ -188,7 +193,8 @@ class MySqlRepository(BaseRepository):
|
|
|
188
193
|
if '.' in field_name:
|
|
189
194
|
parent_field, child_field = field_name.rsplit('.', 1)
|
|
190
195
|
if parent_field not in joined_fields:
|
|
191
|
-
raise Exception(
|
|
196
|
+
raise Exception(
|
|
197
|
+
f"Parent field {parent_field} needs to be joined before joining {child_field} field. Raised while joining {field_name} for model {self.model.__name__}.")
|
|
192
198
|
parent_model = joined_fields[parent_field]
|
|
193
199
|
else:
|
|
194
200
|
parent_model = self.model
|
|
@@ -199,12 +205,14 @@ class MySqlRepository(BaseRepository):
|
|
|
199
205
|
raise Exception(f"Invalid join field {child_field} specified for model {parent_model.__name__}.")
|
|
200
206
|
join_model = join_field.metadata.get('relationship').get('model')
|
|
201
207
|
join_table_name = re.sub(r'(?<!^)(?=[A-Z])', '_', join_model.__name__).lower()
|
|
202
|
-
join_stmt_list.append(
|
|
203
|
-
|
|
208
|
+
join_stmt_list.append(
|
|
209
|
+
f'INNER JOIN {join_table_name} ON {parent_table_name}.{child_field}={join_table_name}.entity_id AND {join_table_name}.active=true')
|
|
210
|
+
join_field_list = [
|
|
211
|
+
f'{join_table_name}.{_field.name} AS joined_{child_field}_{join_table_name}_{_field.name}' for
|
|
212
|
+
_field in fields(join_model)]
|
|
204
213
|
additional_fields += join_field_list
|
|
205
214
|
joined_fields[field_name] = join_model
|
|
206
215
|
|
|
207
|
-
|
|
208
216
|
if conditions:
|
|
209
217
|
for condition_name, value in conditions.copy().items():
|
|
210
218
|
condition_field = next((field for field in fields(self.model) if field.name == condition_name), None)
|
|
@@ -231,7 +239,8 @@ class MySqlRepository(BaseRepository):
|
|
|
231
239
|
raise NotImplementedError
|
|
232
240
|
|
|
233
241
|
records = self._execute_within_context(
|
|
234
|
-
self.adapter.get_many, self.table_name, conditions, sort, limit, offset, join_statements=join_stmt_list,
|
|
242
|
+
self.adapter.get_many, self.table_name, conditions, sort, limit, offset, join_statements=join_stmt_list,
|
|
243
|
+
additional_fields=additional_fields
|
|
235
244
|
)
|
|
236
245
|
|
|
237
246
|
# If the adapter returned a single dictionary, wrap it in a list
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rococo-1.0.4 → rococo-1.0.6}/rococo/repositories/surrealdb/person_organization_role_repository.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|