f3-data-models 0.3.5__tar.gz → 0.3.7__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: f3-data-models
3
- Version: 0.3.5
3
+ Version: 0.3.7
4
4
  Summary: The data schema and models for F3 Nation applications.
5
5
  License: MIT
6
6
  Author: Evan Petzoldt
@@ -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()
@@ -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
- session.query(cls).filter(cls.id == id).update(
171
- fields, synchronize_session="fetch"
172
- )
173
- session.flush()
174
- finally:
175
- session.commit()
176
- close_session(session)
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()
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "f3-data-models"
3
- version = "0.3.5"
3
+ version = "0.3.7"
4
4
  description = "The data schema and models for F3 Nation applications."
5
5
  authors = ["Evan Petzoldt <evan.petzoldt@protonmail.com>"]
6
6
  readme = "README.md"
File without changes