f3-data-models 0.4.2__py3-none-any.whl → 0.4.4__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/models.py CHANGED
@@ -1,5 +1,8 @@
1
- from datetime import datetime, date, time
1
+ import enum
2
+ from datetime import date, datetime, time
2
3
  from typing import Any, Dict, List, Optional
4
+
5
+ from citext import CIText
3
6
  from sqlalchemy import (
4
7
  ARRAY,
5
8
  JSON,
@@ -9,25 +12,24 @@ from sqlalchemy import (
9
12
  VARCHAR,
10
13
  Boolean,
11
14
  DateTime,
15
+ Enum,
12
16
  Float,
13
17
  ForeignKey,
14
18
  Index,
15
19
  Integer,
16
- func,
17
20
  UniqueConstraint,
18
- Enum,
19
21
  Uuid,
22
+ func,
20
23
  inspect,
21
24
  )
22
- from typing_extensions import Annotated
23
25
  from sqlalchemy.orm import (
24
26
  DeclarativeBase,
25
- mapped_column,
26
27
  Mapped,
28
+ mapped_column,
27
29
  relationship,
28
30
  )
29
31
  from sqlalchemy.orm.attributes import InstrumentedAttribute
30
- import enum
32
+ from typing_extensions import Annotated
31
33
 
32
34
  # Custom Annotations
33
35
  time_notz = Annotated[time, TIME(timezone=False)]
@@ -35,9 +37,7 @@ time_with_tz = Annotated[time, TIME(timezone=True)]
35
37
  ts_notz = Annotated[datetime, DateTime(timezone=False)]
36
38
  text = Annotated[str, TEXT]
37
39
  intpk = Annotated[int, mapped_column(Integer, primary_key=True, autoincrement=True)]
38
- dt_create = Annotated[
39
- datetime, mapped_column(DateTime, server_default=func.timezone("utc", func.now()))
40
- ]
40
+ dt_create = Annotated[datetime, mapped_column(DateTime, server_default=func.timezone("utc", func.now()))]
41
41
  dt_update = Annotated[
42
42
  datetime,
43
43
  mapped_column(
@@ -49,30 +49,70 @@ dt_update = Annotated[
49
49
 
50
50
 
51
51
  class User_Status(enum.Enum):
52
+ """
53
+ Enum representing the status of a user.
54
+
55
+ Attributes:
56
+ active
57
+ inactive
58
+ deleted
59
+ """
60
+
52
61
  active = 1
53
62
  inactive = 2
54
63
  deleted = 3
55
64
 
56
65
 
57
66
  class Region_Role(enum.Enum):
67
+ """
68
+ Enum representing the roles within a region.
69
+
70
+ Attributes:
71
+ user
72
+ editor
73
+ admin
74
+ """
75
+
58
76
  user = 1
59
77
  editor = 2
60
78
  admin = 3
61
79
 
62
80
 
63
81
  class User_Role(enum.Enum):
82
+ """
83
+ Enum representing the roles of a user.
84
+
85
+ Attributes:
86
+ user
87
+ editor
88
+ admin
89
+ """
90
+
64
91
  user = 1
65
92
  editor = 2
66
93
  admin = 3
67
94
 
68
95
 
69
96
  class Update_Request_Status(enum.Enum):
97
+ """
98
+ Enum representing the status of an update request.
99
+
100
+ Attributes:
101
+ pending
102
+ approved
103
+ rejected
104
+ """
105
+
70
106
  pending = 1
71
107
  approved = 2
72
108
  rejected = 3
73
109
 
74
110
 
75
111
  class Day_Of_Week(enum.Enum):
112
+ """
113
+ Enum representing the days of the week.
114
+ """
115
+
76
116
  monday = 0
77
117
  tuesday = 1
78
118
  wednesday = 2
@@ -83,11 +123,30 @@ class Day_Of_Week(enum.Enum):
83
123
 
84
124
 
85
125
  class Event_Cadence(enum.Enum):
126
+ """
127
+ Enum representing the cadence of an event.
128
+
129
+ Attributes:
130
+ weekly
131
+ monthly
132
+ """
133
+
86
134
  weekly = 1
87
135
  monthly = 2
88
136
 
89
137
 
90
138
  class Org_Type(enum.Enum):
139
+ """
140
+ Enum representing the type of organization.
141
+
142
+ Attributes:
143
+ ao
144
+ region
145
+ area
146
+ sector
147
+ nation
148
+ """
149
+
91
150
  ao = 1
92
151
  region = 2
93
152
  area = 3
@@ -96,12 +155,31 @@ class Org_Type(enum.Enum):
96
155
 
97
156
 
98
157
  class Event_Category(enum.Enum):
158
+ """
159
+ Enum representing the category of an event.
160
+
161
+ Attributes:
162
+ first_f
163
+ second_f
164
+ third_f
165
+ """
166
+
99
167
  first_f = 1
100
168
  second_f = 2
101
169
  third_f = 3
102
170
 
103
171
 
104
172
  class Request_Type(enum.Enum):
173
+ """
174
+ Enum representing the type of request.
175
+
176
+ Attributes:
177
+ create_location
178
+ create_event
179
+ edit
180
+ delete_event
181
+ """
182
+
105
183
  create_location = 1
106
184
  create_event = 2
107
185
  edit = 3
@@ -154,11 +232,7 @@ class Base(DeclarativeBase):
154
232
  Returns:
155
233
  dict: A dictionary representation of the model instance.
156
234
  """
157
- return {
158
- c.key: self.get(c.key)
159
- for c in self.__table__.columns
160
- if c.key not in ["created", "updated"]
161
- }
235
+ return {c.key: self.get(c.key) for c in self.__table__.columns if c.key not in ["created", "updated"]}
162
236
 
163
237
  def to_update_dict(self) -> Dict[InstrumentedAttribute, Any]:
164
238
  update_dict = {}
@@ -174,7 +248,7 @@ class Base(DeclarativeBase):
174
248
  related_value = getattr(self, rel.key)
175
249
  if related_value is not None:
176
250
  if rel.uselist:
177
- update_dict[rel] = [item for item in related_value]
251
+ update_dict[rel] = list(related_value)
178
252
  print(rel, update_dict[rel])
179
253
  else:
180
254
  update_dict[rel] = related_value
@@ -284,9 +358,7 @@ class Role_x_Permission(Base):
284
358
  __tablename__ = "roles_x_permissions"
285
359
 
286
360
  role_id: Mapped[int] = mapped_column(ForeignKey("roles.id"), primary_key=True)
287
- permission_id: Mapped[int] = mapped_column(
288
- ForeignKey("permissions.id"), primary_key=True
289
- )
361
+ permission_id: Mapped[int] = mapped_column(ForeignKey("permissions.id"), primary_key=True)
290
362
 
291
363
 
292
364
  class Role_x_User_x_Org(Base):
@@ -335,7 +407,7 @@ class Org(Base):
335
407
  achievements (Optional[List[Achievement]]): The achievements available within the organization.
336
408
  parent_org (Optional[Org]): The parent organization.
337
409
  slack_space (Optional[SlackSpace]): The associated Slack workspace.
338
- """
410
+ """ # noqa: E501
339
411
 
340
412
  __tablename__ = "orgs"
341
413
 
@@ -363,9 +435,7 @@ class Org(Base):
363
435
  Index("idx_orgs_is_active", "is_active"),
364
436
  )
365
437
 
366
- locations: Mapped[Optional[List["Location"]]] = relationship(
367
- "Location", cascade="expunge"
368
- )
438
+ locations: Mapped[Optional[List["Location"]]] = relationship("Location", cascade="expunge")
369
439
  event_types: Mapped[Optional[List["EventType"]]] = relationship(
370
440
  "EventType",
371
441
  primaryjoin="or_(EventType.specific_org_id == Org.id, EventType.specific_org_id.is_(None))",
@@ -383,9 +453,7 @@ class Org(Base):
383
453
  cascade="expunge",
384
454
  primaryjoin="or_(Achievement.specific_org_id == Org.id, Achievement.specific_org_id.is_(None))",
385
455
  )
386
- parent_org: Mapped[Optional["Org"]] = relationship(
387
- "Org", remote_side=[id], cascade="expunge"
388
- )
456
+ parent_org: Mapped[Optional["Org"]] = relationship("Org", remote_side=[id], cascade="expunge")
389
457
  slack_space: Mapped[Optional["SlackSpace"]] = relationship(
390
458
  "SlackSpace", secondary="orgs_x_slack_spaces", cascade="expunge"
391
459
  )
@@ -404,7 +472,7 @@ class EventType(Base):
404
472
  specific_org_id (Optional[int]): The ID of the specific organization.
405
473
  created (datetime): The timestamp when the record was created.
406
474
  updated (datetime): The timestamp when the record was last updated.
407
- """
475
+ """ # noqa: E501
408
476
 
409
477
  __tablename__ = "event_types"
410
478
 
@@ -427,14 +495,12 @@ class EventType_x_Event(Base):
427
495
  event_type_id (int): The ID of the associated event type.
428
496
 
429
497
  event (Event): The associated event.
430
- """
498
+ """ # noqa: E501
431
499
 
432
500
  __tablename__ = "events_x_event_types"
433
501
 
434
502
  event_id: Mapped[int] = mapped_column(ForeignKey("events.id"), primary_key=True)
435
- event_type_id: Mapped[int] = mapped_column(
436
- ForeignKey("event_types.id"), primary_key=True
437
- )
503
+ event_type_id: Mapped[int] = mapped_column(ForeignKey("event_types.id"), primary_key=True)
438
504
  __table_args__ = (
439
505
  Index("idx_events_x_event_types_event_id", "event_id"),
440
506
  Index("idx_events_x_event_types_event_type_id", "event_type_id"),
@@ -443,25 +509,6 @@ class EventType_x_Event(Base):
443
509
  event: Mapped["Event"] = relationship(back_populates="event_x_event_types")
444
510
 
445
511
 
446
- # class EventType_x_Org(Base):
447
- # """
448
- # Model representing the association between event types and organizations. This controls which event types are available for selection at the region level, as well as default types for each AO.
449
-
450
- # Attributes:
451
- # event_type_id (int): The ID of the associated event type.
452
- # org_id (int): The ID of the associated organization.
453
- # is_default (bool): Whether this is the default event type for the organization. Default is False.
454
- # """
455
-
456
- # __tablename__ = "event_types_x_org"
457
-
458
- # event_type_id: Mapped[int] = mapped_column(
459
- # ForeignKey("event_types.id"), primary_key=True
460
- # )
461
- # org_id: Mapped[int] = mapped_column(ForeignKey("orgs.id"), primary_key=True)
462
- # is_default: Mapped[bool] = mapped_column(Boolean, default=False)
463
-
464
-
465
512
  class EventTag(Base):
466
513
  """
467
514
  Model representing an event tag. These are used to mark special events, such as anniversaries or special workouts.
@@ -496,37 +543,16 @@ class EventTag_x_Event(Base):
496
543
  event_tag_id (int): The ID of the associated event tag.
497
544
 
498
545
  event (Event): The associated event.
499
- """
546
+ """ # noqa: E501
500
547
 
501
548
  __tablename__ = "event_tags_x_events"
502
549
 
503
550
  event_id: Mapped[int] = mapped_column(ForeignKey("events.id"), primary_key=True)
504
- event_tag_id: Mapped[int] = mapped_column(
505
- ForeignKey("event_tags.id"), primary_key=True
506
- )
551
+ event_tag_id: Mapped[int] = mapped_column(ForeignKey("event_tags.id"), primary_key=True)
507
552
 
508
553
  event: Mapped["Event"] = relationship(back_populates="event_x_event_tags")
509
554
 
510
555
 
511
- # class EventTag_x_Org(Base):
512
- # """
513
- # Model representing the association between event tags and organizations. Controls which event tags are available for selection at the region level.
514
-
515
- # Attributes:
516
- # event_tag_id (int): The ID of the associated event tag.
517
- # org_id (int): The ID of the associated organization.
518
- # color_override (Optional[str]): The calendar color override for the event tag (if the region wants to use something other than the default).
519
- # """
520
-
521
- # __tablename__ = "event_tags_x_org"
522
-
523
- # event_tag_id: Mapped[int] = mapped_column(
524
- # ForeignKey("event_tags.id"), primary_key=True
525
- # )
526
- # org_id: Mapped[int] = mapped_column(ForeignKey("orgs.id"), primary_key=True)
527
- # color_override: Mapped[Optional[str]]
528
-
529
-
530
556
  class Org_x_SlackSpace(Base):
531
557
  """
532
558
  Model representing the association between organizations and Slack workspaces. This is currently meant to be one to one, but theoretically could support multiple workspaces per organization.
@@ -534,14 +560,12 @@ class Org_x_SlackSpace(Base):
534
560
  Attributes:
535
561
  org_id (int): The ID of the associated organization.
536
562
  slack_space_id (str): The ID of the associated Slack workspace.
537
- """
563
+ """ # noqa: E501
538
564
 
539
565
  __tablename__ = "orgs_x_slack_spaces"
540
566
 
541
567
  org_id: Mapped[int] = mapped_column(ForeignKey("orgs.id"), primary_key=True)
542
- slack_space_id: Mapped[int] = mapped_column(
543
- ForeignKey("slack_spaces.id"), primary_key=True
544
- )
568
+ slack_space_id: Mapped[int] = mapped_column(ForeignKey("slack_spaces.id"), primary_key=True)
545
569
 
546
570
 
547
571
  class Location(Base):
@@ -565,7 +589,7 @@ class Location(Base):
565
589
  meta (Optional[Dict[str, Any]]): Additional metadata for the location.
566
590
  created (datetime): The timestamp when the record was created.
567
591
  updated (datetime): The timestamp when the record was last updated.
568
- """
592
+ """ # noqa: E501
569
593
 
570
594
  __tablename__ = "locations"
571
595
 
@@ -575,12 +599,8 @@ class Location(Base):
575
599
  description: Mapped[Optional[text]]
576
600
  is_active: Mapped[bool]
577
601
  email: Mapped[Optional[str]]
578
- latitude: Mapped[Optional[float]] = mapped_column(
579
- Float(precision=8, decimal_return_scale=5)
580
- )
581
- longitude: Mapped[Optional[float]] = mapped_column(
582
- Float(precision=8, decimal_return_scale=5)
583
- )
602
+ latitude: Mapped[Optional[float]] = mapped_column(Float(precision=8, decimal_return_scale=5))
603
+ longitude: Mapped[Optional[float]] = mapped_column(Float(precision=8, decimal_return_scale=5))
584
604
  address_street: Mapped[Optional[str]]
585
605
  address_street2: Mapped[Optional[str]]
586
606
  address_city: Mapped[Optional[str]]
@@ -639,7 +659,7 @@ class Event(Base):
639
659
  event_tags (Optional[List[EventTag]]): The associated event tags.
640
660
  event_x_event_types (List[EventType_x_Event]): The association between the event and event types.
641
661
  event_x_event_tags (Optional[List[EventTag_x_Event]]): The association between the event and event tags.
642
- """
662
+ """ # noqa: E501
643
663
 
644
664
  __tablename__ = "events"
645
665
 
@@ -680,9 +700,7 @@ class Event(Base):
680
700
  )
681
701
 
682
702
  org: Mapped[Org] = relationship(innerjoin=True, cascade="expunge", viewonly=True)
683
- location: Mapped[Location] = relationship(
684
- innerjoin=True, cascade="expunge", viewonly=True
685
- )
703
+ location: Mapped[Location] = relationship(innerjoin=True, cascade="expunge", viewonly=True)
686
704
  event_types: Mapped[List[EventType]] = relationship(
687
705
  secondary="events_x_event_types",
688
706
  innerjoin=True,
@@ -698,9 +716,7 @@ class Event(Base):
698
716
  event_x_event_tags: Mapped[Optional[List[EventTag_x_Event]]] = relationship(
699
717
  back_populates="event", cascade="save-update, merge, delete"
700
718
  )
701
- attendance: Mapped[List["Attendance"]] = relationship(
702
- back_populates="event", cascade="expunge, delete"
703
- )
719
+ attendance: Mapped[List["Attendance"]] = relationship(back_populates="event", cascade="expunge, delete")
704
720
 
705
721
 
706
722
  class AttendanceType(Base):
@@ -710,7 +726,7 @@ class AttendanceType(Base):
710
726
  Attributes:
711
727
  type (str): The type of attendance.
712
728
  description (Optional[str]): A description of the attendance type.
713
- """
729
+ """ # noqa: E501
714
730
 
715
731
  __tablename__ = "attendance_types"
716
732
 
@@ -730,20 +746,14 @@ class Attendance_x_AttendanceType(Base):
730
746
  attendance_type_id (int): The ID of the associated attendance type.
731
747
 
732
748
  attendance (Attendance): The associated attendance.
733
- """
749
+ """ # noqa: E501
734
750
 
735
751
  __tablename__ = "attendance_x_attendance_types"
736
752
 
737
- attendance_id: Mapped[int] = mapped_column(
738
- ForeignKey("attendance.id"), primary_key=True
739
- )
740
- attendance_type_id: Mapped[int] = mapped_column(
741
- ForeignKey("attendance_types.id"), primary_key=True
742
- )
753
+ attendance_id: Mapped[int] = mapped_column(ForeignKey("attendance.id"), primary_key=True)
754
+ attendance_type_id: Mapped[int] = mapped_column(ForeignKey("attendance_types.id"), primary_key=True)
743
755
 
744
- attendance: Mapped["Attendance"] = relationship(
745
- back_populates="attendance_x_attendance_types"
746
- )
756
+ attendance: Mapped["Attendance"] = relationship(back_populates="attendance_x_attendance_types")
747
757
 
748
758
 
749
759
  class User(Base):
@@ -764,7 +774,7 @@ class User(Base):
764
774
  status (UserStatus): The status of the user. Default is 'active'.
765
775
  created (datetime): The timestamp when the record was created.
766
776
  updated (datetime): The timestamp when the record was last updated.
767
- """
777
+ """ # noqa: E501
768
778
 
769
779
  __tablename__ = "users"
770
780
 
@@ -772,7 +782,7 @@ class User(Base):
772
782
  f3_name: Mapped[Optional[str]]
773
783
  first_name: Mapped[Optional[str]]
774
784
  last_name: Mapped[Optional[str]]
775
- email: Mapped[str] = mapped_column(VARCHAR, unique=True)
785
+ email: Mapped[str] = mapped_column(CIText, unique=True)
776
786
  phone: Mapped[Optional[str]]
777
787
  emergency_contact: Mapped[Optional[str]]
778
788
  emergency_phone: Mapped[Optional[str]]
@@ -781,9 +791,7 @@ class User(Base):
781
791
  avatar_url: Mapped[Optional[str]]
782
792
  meta: Mapped[Optional[Dict[str, Any]]]
783
793
  email_verified: Mapped[Optional[datetime]]
784
- status: Mapped[User_Status] = mapped_column(
785
- Enum(User_Status), default=User_Status.active
786
- )
794
+ status: Mapped[User_Status] = mapped_column(Enum(User_Status), default=User_Status.active)
787
795
  created: Mapped[dt_create]
788
796
  updated: Mapped[dt_update]
789
797
 
@@ -811,7 +819,7 @@ class SlackUser(Base):
811
819
  slack_updated (Optional[datetime]): The last update time of the Slack user.
812
820
  created (datetime): The timestamp when the record was created.
813
821
  updated (datetime): The timestamp when the record was last updated.
814
- """
822
+ """ # noqa: E501
815
823
 
816
824
  __tablename__ = "slack_users"
817
825
 
@@ -853,7 +861,7 @@ class Attendance(Base):
853
861
  slack_user (Optional[SlackUser]): The associated Slack user.
854
862
  attendance_x_attendance_types (List[Attendance_x_AttendanceType]): The association between the attendance and attendance types.
855
863
  attendance_types (List[AttendanceType]): The associated attendance types.
856
- """
864
+ """ # noqa: E501
857
865
 
858
866
  __tablename__ = "attendance"
859
867
  __table_args__ = (UniqueConstraint("event_id", "user_id", "is_planned"),)
@@ -866,15 +874,13 @@ class Attendance(Base):
866
874
  created: Mapped[dt_create]
867
875
  updated: Mapped[dt_update]
868
876
 
869
- event: Mapped[Event] = relationship(
870
- innerjoin=True, cascade="expunge", viewonly=True
871
- )
877
+ event: Mapped[Event] = relationship(innerjoin=True, cascade="expunge", viewonly=True)
872
878
  user: Mapped[User] = relationship(innerjoin=True, cascade="expunge", viewonly=True)
873
879
  slack_user: Mapped[Optional[SlackUser]] = relationship(
874
880
  innerjoin=False, cascade="expunge", secondary="users", viewonly=True
875
881
  )
876
- attendance_x_attendance_types: Mapped[List[Attendance_x_AttendanceType]] = (
877
- relationship(back_populates="attendance", cascade="save-update, merge, delete")
882
+ attendance_x_attendance_types: Mapped[List[Attendance_x_AttendanceType]] = relationship(
883
+ back_populates="attendance", cascade="save-update, merge, delete"
878
884
  )
879
885
  attendance_types: Mapped[List[AttendanceType]] = relationship(
880
886
  secondary="attendance_x_attendance_types",
@@ -897,7 +903,7 @@ class Achievement(Base):
897
903
  specific_org_id (Optional[int]): The ID of the specific region if a custom achievement. If null, the achievement is available to all regions.
898
904
  created (datetime): The timestamp when the record was created.
899
905
  updated (datetime): The timestamp when the record was last updated.
900
- """
906
+ """ # noqa: E501
901
907
 
902
908
  __tablename__ = "achievements"
903
909
 
@@ -919,17 +925,13 @@ class Achievement_x_User(Base):
919
925
  achievement_id (int): The ID of the associated achievement.
920
926
  user_id (int): The ID of the associated user.
921
927
  date_awarded (date): The date the achievement was awarded. Default is the current date.
922
- """
928
+ """ # noqa: E501
923
929
 
924
930
  __tablename__ = "achievements_x_users"
925
931
 
926
- achievement_id: Mapped[int] = mapped_column(
927
- ForeignKey("achievements.id"), primary_key=True
928
- )
932
+ achievement_id: Mapped[int] = mapped_column(ForeignKey("achievements.id"), primary_key=True)
929
933
  user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), primary_key=True)
930
- date_awarded: Mapped[date] = mapped_column(
931
- DateTime, server_default=func.timezone("utc", func.now())
932
- )
934
+ date_awarded: Mapped[date] = mapped_column(DateTime, server_default=func.timezone("utc", func.now()))
933
935
 
934
936
 
935
937
  class Position(Base):
@@ -941,7 +943,7 @@ class Position(Base):
941
943
  description (Optional[str]): A description of the position.
942
944
  org_type (Optional[Org_Type]): The associated organization type. This is used to limit the positions available to certain types of organizations. If null, the position is available to all organization types.
943
945
  org_id (Optional[int]): The ID of the associated organization. This is used to limit the positions available to certain organizations. If null, the position is available to all organizations.
944
- """
946
+ """ # noqa: E501
945
947
 
946
948
  __tablename__ = "positions"
947
949
 
@@ -962,13 +964,11 @@ class Position_x_Org_x_User(Base):
962
964
  position_id (int): The ID of the associated position.
963
965
  org_id (int): The ID of the associated organization.
964
966
  user_id (int): The ID of the associated user.
965
- """
967
+ """ # noqa: E501
966
968
 
967
969
  __tablename__ = "positions_x_orgs_x_users"
968
970
 
969
- position_id: Mapped[int] = mapped_column(
970
- ForeignKey("positions.id"), primary_key=True
971
- )
971
+ position_id: Mapped[int] = mapped_column(ForeignKey("positions.id"), primary_key=True)
972
972
  org_id: Mapped[int] = mapped_column(ForeignKey("orgs.id"), primary_key=True)
973
973
  user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), primary_key=True)
974
974
 
@@ -987,7 +987,7 @@ class Expansion(Base):
987
987
  interested_in_organizing (bool): Whether the user is interested in organizing.
988
988
  created (datetime): The timestamp when the record was created.
989
989
  updated (datetime): The timestamp when the record was last updated.
990
- """
990
+ """ # noqa: E501
991
991
 
992
992
  __tablename__ = "expansions"
993
993
 
@@ -1011,17 +1011,13 @@ class Expansion_x_User(Base):
1011
1011
  user_id (int): The ID of the associated user.
1012
1012
  requst_date (date): The date of the request. Default is the current date.
1013
1013
  notes (Optional[text]): Additional notes for the association.
1014
- """
1014
+ """ # noqa: E501
1015
1015
 
1016
1016
  __tablename__ = "expansions_x_users"
1017
1017
 
1018
- expansion_id: Mapped[int] = mapped_column(
1019
- ForeignKey("expansions.id"), primary_key=True
1020
- )
1018
+ expansion_id: Mapped[int] = mapped_column(ForeignKey("expansions.id"), primary_key=True)
1021
1019
  user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), primary_key=True)
1022
- request_date: Mapped[date] = mapped_column(
1023
- DateTime, server_default=func.timezone("utc", func.now())
1024
- )
1020
+ request_date: Mapped[date] = mapped_column(DateTime, server_default=func.timezone("utc", func.now()))
1025
1021
  notes: Mapped[Optional[text]]
1026
1022
 
1027
1023
 
@@ -1043,7 +1039,7 @@ class NextAuthAccount(Base):
1043
1039
  session_state (Optional[text]): The session state.
1044
1040
  created (datetime): The timestamp when the record was created.
1045
1041
  updated (datetime): The timestamp when the record was last updated.
1046
- """
1042
+ """ # noqa: E501
1047
1043
 
1048
1044
  __tablename__ = "auth_accounts"
1049
1045
 
@@ -1072,7 +1068,7 @@ class NextAuthSession(Base):
1072
1068
  expires (ts_notz): The expiration time of the session.
1073
1069
  created (datetime): The timestamp when the record was created.
1074
1070
  updated (datetime): The timestamp when the record was last updated.
1075
- """
1071
+ """ # noqa: E501
1076
1072
 
1077
1073
  __tablename__ = "auth_sessions"
1078
1074
 
@@ -1093,7 +1089,7 @@ class NextAuthVerificationToken(Base):
1093
1089
  expires (ts_notz): The expiration time of the token.
1094
1090
  created (datetime): The timestamp when the record was created.
1095
1091
  updated (datetime): The timestamp when the record was last updated.
1096
- """
1092
+ """ # noqa: E501
1097
1093
 
1098
1094
  __tablename__ = "auth_verification_tokens"
1099
1095
 
@@ -1154,16 +1150,12 @@ class UpdateRequest(Base):
1154
1150
  request_type (Request_Type): The type of the request.
1155
1151
  created (datetime): The timestamp when the record was created.
1156
1152
  updated (datetime): The timestamp when the record was last updated.
1157
- """
1153
+ """ # noqa: E501
1158
1154
 
1159
1155
  __tablename__ = "update_requests"
1160
1156
 
1161
- id: Mapped[Uuid] = mapped_column(
1162
- UUID(as_uuid=True), primary_key=True, server_default=func.gen_random_uuid()
1163
- )
1164
- token: Mapped[Uuid] = mapped_column(
1165
- UUID(as_uuid=True), server_default=func.gen_random_uuid()
1166
- )
1157
+ id: Mapped[Uuid] = mapped_column(UUID(as_uuid=True), primary_key=True, server_default=func.gen_random_uuid())
1158
+ token: Mapped[Uuid] = mapped_column(UUID(as_uuid=True), server_default=func.gen_random_uuid())
1167
1159
  region_id: Mapped[int] = mapped_column(ForeignKey("orgs.id"))
1168
1160
  event_id: Mapped[Optional[int]] = mapped_column(ForeignKey("events.id"))
1169
1161
  event_type_ids: Mapped[Optional[List[int]]] = mapped_column(ARRAY(Integer))
@@ -1193,12 +1185,8 @@ class UpdateRequest(Base):
1193
1185
  location_state: Mapped[Optional[str]]
1194
1186
  location_zip: Mapped[Optional[str]]
1195
1187
  location_country: Mapped[Optional[str]]
1196
- location_lat: Mapped[Optional[float]] = mapped_column(
1197
- Float(precision=8, decimal_return_scale=5)
1198
- )
1199
- location_lng: Mapped[Optional[float]] = mapped_column(
1200
- Float(precision=8, decimal_return_scale=5)
1201
- )
1188
+ location_lat: Mapped[Optional[float]] = mapped_column(Float(precision=8, decimal_return_scale=5))
1189
+ location_lng: Mapped[Optional[float]] = mapped_column(Float(precision=8, decimal_return_scale=5))
1202
1190
  location_id: Mapped[Optional[int]] = mapped_column(ForeignKey("locations.id"))
1203
1191
  location_contact_email: Mapped[Optional[str]]
1204
1192
 
f3_data_models/testing.py CHANGED
@@ -1,33 +1,12 @@
1
- from f3_data_models.models import Event, Day_Of_Week, Event_Cadence, EventType_x_Event
2
- import datetime
1
+ from f3_data_models.models import User
3
2
  from f3_data_models.utils import DbManager
4
3
 
5
4
 
6
5
  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="0400",
16
- end_time="0600",
17
- event_x_event_types=[
18
- EventType_x_Event(event_type_id=3),
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",
6
+ user = User(
7
+ email="evan.Petzoldt@protonmail.com",
25
8
  )
26
- update_dict = event.to_update_dict()
27
- DbManager.update_record(Event, 3, update_dict)
28
-
29
- # event = DbManager.get(Event, 3)
30
- DbManager.delete_records(Event, [Event.series_id == 3])
9
+ DbManager.create_record(user)
31
10
 
32
11
 
33
12
  if __name__ == "__main__":
f3_data_models/utils.py CHANGED
@@ -1,24 +1,21 @@
1
1
  import os
2
2
  from dataclasses import dataclass
3
- from typing import List, Optional, Tuple, TypeVar, Type, Generic # noqa
3
+ from typing import Generic, List, Optional, Tuple, Type, TypeVar # noqa
4
4
 
5
+ import pg8000
5
6
  import sqlalchemy
6
- from sqlalchemy import Select, and_, select, inspect
7
-
7
+ from google.cloud.sql.connector import Connector, IPTypes
8
+ from pydot import Dot
9
+ from sqlalchemy import Select, and_, inspect, select
8
10
  from sqlalchemy.dialects.postgresql import insert
9
11
  from sqlalchemy.engine import Engine
10
- from sqlalchemy.orm import sessionmaker, joinedload
12
+ from sqlalchemy.orm import class_mapper, joinedload, sessionmaker
13
+ from sqlalchemy.orm.attributes import InstrumentedAttribute
11
14
  from sqlalchemy.orm.collections import InstrumentedList
15
+ from sqlalchemy_schemadisplay import create_schema_graph
12
16
 
13
17
  from f3_data_models.models import Base
14
18
 
15
- from pydot import Dot
16
- from sqlalchemy_schemadisplay import create_schema_graph
17
- from google.cloud.sql.connector import Connector, IPTypes
18
- import pg8000
19
- from sqlalchemy.orm import class_mapper
20
- from sqlalchemy.orm.attributes import InstrumentedAttribute
21
-
22
19
 
23
20
  @dataclass
24
21
  class DatabaseField:
@@ -53,9 +50,7 @@ def get_engine(echo=False) -> Engine:
53
50
  )
54
51
  return conn
55
52
 
56
- engine = sqlalchemy.create_engine(
57
- "postgresql+pg8000://", creator=get_connection, echo=echo
58
- )
53
+ engine = sqlalchemy.create_engine("postgresql+pg8000://", creator=get_connection, echo=echo)
59
54
  return engine
60
55
 
61
56
 
@@ -81,10 +76,7 @@ T = TypeVar("T")
81
76
 
82
77
  def _joinedloads(cls: T, query: Select, joinedloads: list | str) -> Select:
83
78
  if joinedloads == "all":
84
- joinedloads = [
85
- getattr(cls, relationship.key)
86
- for relationship in cls.__mapper__.relationships
87
- ]
79
+ joinedloads = [getattr(cls, relationship.key) for relationship in cls.__mapper__.relationships]
88
80
  return query.options(*[joinedload(load) for load in joinedloads])
89
81
 
90
82
 
@@ -101,9 +93,7 @@ class DbManager:
101
93
  session.rollback()
102
94
  close_session(session)
103
95
 
104
- def find_records(
105
- cls: T, filters: Optional[List], joinedloads: List | str = []
106
- ) -> List[T]:
96
+ def find_records(cls: T, filters: Optional[List], joinedloads: List | str = []) -> List[T]:
107
97
  session = get_session()
108
98
  try:
109
99
  query = select(cls)
@@ -117,9 +107,7 @@ class DbManager:
117
107
  session.rollback()
118
108
  close_session(session)
119
109
 
120
- def find_first_record(
121
- cls: T, filters: Optional[List], joinedloads: List | str = []
122
- ) -> T:
110
+ def find_first_record(cls: T, filters: Optional[List], joinedloads: List | str = []) -> T:
123
111
  session = get_session()
124
112
  try:
125
113
  query = select(cls)
@@ -136,21 +124,14 @@ class DbManager:
136
124
  def find_join_records2(left_cls: T, right_cls: T, filters) -> List[Tuple[T]]:
137
125
  session = get_session()
138
126
  try:
139
- records = (
140
- session.query(left_cls, right_cls)
141
- .join(right_cls)
142
- .filter(and_(*filters))
143
- .all()
144
- )
127
+ records = session.query(left_cls, right_cls).join(right_cls).filter(and_(*filters)).all()
145
128
  session.expunge_all()
146
129
  return records
147
130
  finally:
148
131
  session.rollback()
149
132
  close_session(session)
150
133
 
151
- def find_join_records3(
152
- left_cls: T, right_cls1: T, right_cls2: T, filters, left_join=False
153
- ) -> List[Tuple[T]]:
134
+ def find_join_records3(left_cls: T, right_cls1: T, right_cls2: T, filters, left_join=False) -> List[Tuple[T]]:
154
135
  session = get_session()
155
136
  try:
156
137
  records = (
@@ -176,7 +157,7 @@ class DbManager:
176
157
  mapper = class_mapper(cls)
177
158
  relationships = mapper.relationships.keys()
178
159
  for attr, value in fields.items():
179
- key = attr.key
160
+ key = attr if isinstance(attr, str) else attr.key
180
161
  if hasattr(cls, key) and key not in relationships:
181
162
  if isinstance(attr, InstrumentedAttribute):
182
163
  setattr(record, key, value)
@@ -194,24 +175,17 @@ class DbManager:
194
175
  if isinstance(value, list) and og_primary_key:
195
176
  # Delete existing related records
196
177
  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()
178
+ related_relationships = class_mapper(related_class).relationships.keys()
179
+ session.query(related_class).filter(getattr(related_class, og_primary_key) == id).delete()
203
180
  # Add new related records
204
181
  items = [item.__dict__ for item in value]
205
182
  for related_item in items:
206
183
  update_dict = {
207
184
  k: v
208
185
  for k, v in related_item.items()
209
- if hasattr(related_class, k)
210
- and k not in related_relationships
186
+ if hasattr(related_class, k) and k not in related_relationships
211
187
  }
212
- related_record = related_class(
213
- **{og_primary_key: id, **update_dict}
214
- )
188
+ related_record = related_class(**{og_primary_key: id, **update_dict})
215
189
  session.add(related_record)
216
190
 
217
191
  try:
@@ -234,9 +208,7 @@ class DbManager:
234
208
  # Update simple fields
235
209
  for attr, value in fields.items():
236
210
  key = attr.key
237
- if key in valid_attributes and not isinstance(
238
- value, InstrumentedList
239
- ):
211
+ if key in valid_attributes and not isinstance(value, InstrumentedList):
240
212
  setattr(obj, key, value)
241
213
 
242
214
  # Update relationships separately
@@ -256,9 +228,7 @@ class DbManager:
256
228
  if isinstance(value, list) and og_primary_key:
257
229
  # Delete existing related records
258
230
  related_class = relationship.mapper.class_
259
- related_relationships = class_mapper(
260
- related_class
261
- ).relationships.keys()
231
+ related_relationships = class_mapper(related_class).relationships.keys()
262
232
  session.query(related_class).filter(
263
233
  getattr(related_class, og_primary_key) == obj.id
264
234
  ).delete()
@@ -268,12 +238,9 @@ class DbManager:
268
238
  update_dict = {
269
239
  k: v
270
240
  for k, v in related_item.items()
271
- if hasattr(related_class, k)
272
- and k not in related_relationships
241
+ if hasattr(related_class, k) and k not in related_relationships
273
242
  }
274
- related_record = related_class(
275
- **{og_primary_key: obj.id, **update_dict}
276
- )
243
+ related_record = related_class(**{og_primary_key: obj.id, **update_dict})
277
244
  session.add(related_record)
278
245
 
279
246
  session.flush()
@@ -307,11 +274,7 @@ class DbManager:
307
274
  session = get_session()
308
275
  try:
309
276
  for record in records:
310
- record_dict = {
311
- k: v
312
- for k, v in record.__dict__.items()
313
- if k != "_sa_instance_state"
314
- }
277
+ record_dict = {k: v for k, v in record.__dict__.items() if k != "_sa_instance_state"}
315
278
  stmt = insert(cls).values(record_dict).on_conflict_do_nothing()
316
279
  session.execute(stmt)
317
280
  session.flush()
@@ -323,15 +286,9 @@ class DbManager:
323
286
  session = get_session()
324
287
  try:
325
288
  for record in records:
326
- record_dict = {
327
- k: v
328
- for k, v in record.__dict__.items()
329
- if k != "_sa_instance_state"
330
- }
289
+ record_dict = {k: v for k, v in record.__dict__.items() if k != "_sa_instance_state"}
331
290
  stmt = insert(cls).values(record_dict)
332
- update_dict = {
333
- c.name: getattr(record, c.name) for c in cls.__table__.columns
334
- }
291
+ update_dict = {c.name: getattr(record, c.name) for c in cls.__table__.columns}
335
292
  stmt = stmt.on_conflict_do_update(
336
293
  index_elements=[cls.__table__.primary_key.columns.keys()],
337
294
  set_=update_dict,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: f3-data-models
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: The data schema and models for F3 Nation applications.
5
5
  License: MIT
6
6
  Author: Evan Petzoldt
@@ -21,6 +21,7 @@ Requires-Dist: sphinx-autodoc-typehints (>=2.5.0,<3.0.0)
21
21
  Requires-Dist: sphinx-multiversion (>=0.2.4,<0.3.0)
22
22
  Requires-Dist: sphinx-rtd-theme (>=3.0.2,<4.0.0)
23
23
  Requires-Dist: sqlalchemy (>=2.0.36,<3.0.0)
24
+ Requires-Dist: sqlalchemy-citext (>=1.8.0,<2.0.0)
24
25
  Requires-Dist: sqlalchemy-schemadisplay (>=2.0,<3.0)
25
26
  Requires-Dist: sqlmodel (>=0.0.22,<0.0.23)
26
27
  Project-URL: Documentation, https://github.io/F3-Nation/f3-data-models
@@ -0,0 +1,7 @@
1
+ f3_data_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ f3_data_models/models.py,sha256=q_oQEe2Ccvcnl5l4Zf4fYNoogiT_1SSa8vMNmbW_QH8,45973
3
+ f3_data_models/testing.py,sha256=fdiwiSy0ZoYbsXAKhukVHMJr7WvBLwD20Tg949wshmk,265
4
+ f3_data_models/utils.py,sha256=l9x2nEcIrnjDLkIAATDsZ5I-0Y2sg1u_sfkBcRKrTu4,13051
5
+ f3_data_models-0.4.4.dist-info/METADATA,sha256=fTfrpyeuWFQKRRM79NlpO4U2j6CVboBmBKD8sxCYOv8,2766
6
+ f3_data_models-0.4.4.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
7
+ f3_data_models-0.4.4.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.1
2
+ Generator: poetry-core 2.1.2
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,7 +0,0 @@
1
- f3_data_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- f3_data_models/models.py,sha256=gz14Lybp1QpLUMdCMgXbO5tazx_dcTc6laoyvbPIFqE,46533
3
- f3_data_models/testing.py,sha256=KmTjMe345-NZCdHNaNnOyL33J8D5oVdqdIhYIKbM8XM,968
4
- f3_data_models/utils.py,sha256=UpNx1E_kmt8_1vN4fdFSy55yPCoDA2algzof_5EAJ2k,13835
5
- f3_data_models-0.4.2.dist-info/METADATA,sha256=W8Ze7HlIc4UiZHQaYY4w1fbe_jHG8ISecN-QVk-4JRs,2716
6
- f3_data_models-0.4.2.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
7
- f3_data_models-0.4.2.dist-info/RECORD,,