f3-data-models 0.3.5__py3-none-any.whl → 0.3.7__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.
- f3_data_models/testing.py +40 -0
- f3_data_models/utils.py +107 -14
- {f3_data_models-0.3.5.dist-info → f3_data_models-0.3.7.dist-info}/METADATA +1 -1
- f3_data_models-0.3.7.dist-info/RECORD +7 -0
- {f3_data_models-0.3.5.dist-info → f3_data_models-0.3.7.dist-info}/WHEEL +1 -1
- f3_data_models-0.3.5.dist-info/RECORD +0 -6
@@ -0,0 +1,40 @@
|
|
1
|
+
from f3_data_models.models import Event, Day_Of_Week, Event_Cadence, EventType_x_Event
|
2
|
+
import datetime
|
3
|
+
from f3_data_models.utils import DbManager
|
4
|
+
|
5
|
+
|
6
|
+
def test_update_event():
|
7
|
+
event = Event(
|
8
|
+
org_id=3,
|
9
|
+
location_id=2,
|
10
|
+
is_series=True,
|
11
|
+
is_active=True,
|
12
|
+
highlight=True,
|
13
|
+
start_date=datetime.date(2025, 2, 17),
|
14
|
+
end_date=datetime.date(2026, 2, 17),
|
15
|
+
start_time="0500",
|
16
|
+
end_time="0600",
|
17
|
+
event_x_event_types=[
|
18
|
+
EventType_x_Event(event_type_id=4),
|
19
|
+
],
|
20
|
+
recurrence_pattern=Event_Cadence.weekly,
|
21
|
+
day_of_week=Day_Of_Week.monday,
|
22
|
+
recurrence_interval=1,
|
23
|
+
index_within_interval=1,
|
24
|
+
name="Test Event",
|
25
|
+
)
|
26
|
+
update_dict = event.__dict__
|
27
|
+
DbManager.update_records(Event, [Event.id == 3], update_dict)
|
28
|
+
|
29
|
+
# with get_session() as session:
|
30
|
+
# # delete event_x_event_types
|
31
|
+
# session.query(EventType_x_Event).filter(
|
32
|
+
# EventType_x_Event.event_id == 3
|
33
|
+
# ).delete()
|
34
|
+
# # add event_x_event_types
|
35
|
+
# session.add(EventType_x_Event(event_id=3, event_type_id=4))
|
36
|
+
# session.commit()
|
37
|
+
|
38
|
+
|
39
|
+
if __name__ == "__main__":
|
40
|
+
test_update_event()
|
f3_data_models/utils.py
CHANGED
@@ -3,11 +3,12 @@ from dataclasses import dataclass
|
|
3
3
|
from typing import List, Optional, Tuple, TypeVar
|
4
4
|
|
5
5
|
import sqlalchemy
|
6
|
-
from sqlalchemy import Select, and_, select
|
6
|
+
from sqlalchemy import Select, and_, select, inspect
|
7
7
|
|
8
8
|
from sqlalchemy.dialects.postgresql import insert
|
9
9
|
from sqlalchemy.engine import Engine
|
10
10
|
from sqlalchemy.orm import sessionmaker, joinedload
|
11
|
+
from sqlalchemy.orm.collections import InstrumentedList
|
11
12
|
|
12
13
|
from f3_data_models.models import Base
|
13
14
|
|
@@ -15,6 +16,8 @@ from pydot import Dot
|
|
15
16
|
from sqlalchemy_schemadisplay import create_schema_graph
|
16
17
|
from google.cloud.sql.connector import Connector, IPTypes
|
17
18
|
import pg8000
|
19
|
+
from sqlalchemy.orm import class_mapper
|
20
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
18
21
|
|
19
22
|
|
20
23
|
@dataclass
|
@@ -165,22 +168,112 @@ class DbManager:
|
|
165
168
|
close_session(session)
|
166
169
|
|
167
170
|
def update_record(cls: T, id, fields):
|
171
|
+
with get_session() as session:
|
172
|
+
record = session.query(cls).get(id)
|
173
|
+
if not record:
|
174
|
+
raise ValueError(f"Record with id {id} not found in {cls.__name__}")
|
175
|
+
|
176
|
+
mapper = class_mapper(cls)
|
177
|
+
relationships = mapper.relationships.keys()
|
178
|
+
for key, value in fields.items():
|
179
|
+
if hasattr(cls, key) and key not in relationships:
|
180
|
+
attr = getattr(cls, key)
|
181
|
+
if isinstance(attr, InstrumentedAttribute):
|
182
|
+
setattr(record, key, value)
|
183
|
+
elif key in relationships:
|
184
|
+
# Handle relationships separately
|
185
|
+
relationship = mapper.relationships[key]
|
186
|
+
related_class = relationship.mapper.class_
|
187
|
+
# find mapping of related_class
|
188
|
+
og_primary_key = None
|
189
|
+
for k in related_class.__table__.foreign_keys:
|
190
|
+
if k.references(cls.__table__):
|
191
|
+
og_primary_key = k.constraint.columns[0].name
|
192
|
+
break
|
193
|
+
|
194
|
+
if isinstance(value, list) and og_primary_key:
|
195
|
+
# Delete existing related records
|
196
|
+
related_class = relationship.mapper.class_
|
197
|
+
related_relationships = class_mapper(
|
198
|
+
related_class
|
199
|
+
).relationships.keys()
|
200
|
+
session.query(related_class).filter(
|
201
|
+
getattr(related_class, og_primary_key) == id
|
202
|
+
).delete()
|
203
|
+
# Add new related records
|
204
|
+
items = [item.__dict__ for item in value]
|
205
|
+
for related_item in items:
|
206
|
+
update_dict = {
|
207
|
+
k: v
|
208
|
+
for k, v in related_item.items()
|
209
|
+
if hasattr(related_class, k)
|
210
|
+
and k not in related_relationships
|
211
|
+
}
|
212
|
+
related_record = related_class(
|
213
|
+
**{og_primary_key: id, **update_dict}
|
214
|
+
)
|
215
|
+
session.add(related_record)
|
216
|
+
|
217
|
+
try:
|
218
|
+
session.commit()
|
219
|
+
except pg8000.IntegrityError as e:
|
220
|
+
session.rollback()
|
221
|
+
raise e
|
222
|
+
|
223
|
+
def update_records(cls, filters, fields):
|
168
224
|
session = get_session()
|
169
225
|
try:
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
226
|
+
# Fetch the objects to be updated
|
227
|
+
objects = session.query(cls).filter(and_(*filters)).all()
|
228
|
+
|
229
|
+
# Get the list of valid attributes for the class
|
230
|
+
valid_attributes = {attr.key for attr in inspect(cls).mapper.column_attrs}
|
231
|
+
valid_relationships = {rel.key for rel in inspect(cls).mapper.relationships}
|
232
|
+
|
233
|
+
for obj in objects:
|
234
|
+
# Update simple fields
|
235
|
+
for key, value in fields.items():
|
236
|
+
if key in valid_attributes and not isinstance(
|
237
|
+
value, InstrumentedList
|
238
|
+
):
|
239
|
+
setattr(obj, key, value)
|
240
|
+
|
241
|
+
# Update relationships separately
|
242
|
+
for key, value in fields.items():
|
243
|
+
if key in valid_relationships:
|
244
|
+
# Handle relationships separately
|
245
|
+
relationship = inspect(cls).mapper.relationships[key]
|
246
|
+
related_class = relationship.mapper.class_
|
247
|
+
# find mapping of related_class
|
248
|
+
og_primary_key = None
|
249
|
+
for k in related_class.__table__.foreign_keys:
|
250
|
+
if k.references(cls.__table__):
|
251
|
+
og_primary_key = k.constraint.columns[0].name
|
252
|
+
break
|
253
|
+
|
254
|
+
if isinstance(value, list) and og_primary_key:
|
255
|
+
# Delete existing related records
|
256
|
+
related_class = relationship.mapper.class_
|
257
|
+
related_relationships = class_mapper(
|
258
|
+
related_class
|
259
|
+
).relationships.keys()
|
260
|
+
session.query(related_class).filter(
|
261
|
+
getattr(related_class, og_primary_key) == obj.id
|
262
|
+
).delete()
|
263
|
+
# Add new related records
|
264
|
+
items = [item.__dict__ for item in value]
|
265
|
+
for related_item in items:
|
266
|
+
update_dict = {
|
267
|
+
k: v
|
268
|
+
for k, v in related_item.items()
|
269
|
+
if hasattr(related_class, k)
|
270
|
+
and k not in related_relationships
|
271
|
+
}
|
272
|
+
related_record = related_class(
|
273
|
+
**{og_primary_key: obj.id, **update_dict}
|
274
|
+
)
|
275
|
+
session.add(related_record)
|
177
276
|
|
178
|
-
def update_records(cls: T, filters, fields):
|
179
|
-
session = get_session()
|
180
|
-
try:
|
181
|
-
session.query(cls).filter(and_(*filters)).update(
|
182
|
-
fields, synchronize_session="fetch"
|
183
|
-
)
|
184
277
|
session.flush()
|
185
278
|
finally:
|
186
279
|
session.commit()
|
@@ -0,0 +1,7 @@
|
|
1
|
+
f3_data_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
f3_data_models/models.py,sha256=SLOXwM2BMnlGTwkVZfG3fM9hoksvPkcFRqzpEI4bm2Y,44293
|
3
|
+
f3_data_models/testing.py,sha256=vetCEBQC8R1hf0TcH3-lINXdlHMVIcjC6OhVWiiFWU0,1204
|
4
|
+
f3_data_models/utils.py,sha256=5Hg0f1cPMYc-URdTbDTLMiG9rCFN5NskJ4lUHw1a2NU,13747
|
5
|
+
f3_data_models-0.3.7.dist-info/METADATA,sha256=F34OA9YQW-60PwJ77YytFIHNL_-zMlbew6t23Rrdfm4,2716
|
6
|
+
f3_data_models-0.3.7.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
7
|
+
f3_data_models-0.3.7.dist-info/RECORD,,
|
@@ -1,6 +0,0 @@
|
|
1
|
-
f3_data_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
f3_data_models/models.py,sha256=SLOXwM2BMnlGTwkVZfG3fM9hoksvPkcFRqzpEI4bm2Y,44293
|
3
|
-
f3_data_models/utils.py,sha256=1hdZ2tvMiNibNZvwt0dx4PhPCw_pJGg1mG2cCvwc6CI,8857
|
4
|
-
f3_data_models-0.3.5.dist-info/METADATA,sha256=L2i2GhGM0d1ueb9uQuHNqPJs_X1NbuJKdLD6jaKp6RM,2716
|
5
|
-
f3_data_models-0.3.5.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
6
|
-
f3_data_models-0.3.5.dist-info/RECORD,,
|