f3-data-models 0.4.3__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 +1 -2
- f3_data_models/testing.py +4 -25
- f3_data_models/utils.py +26 -69
- {f3_data_models-0.4.3.dist-info → f3_data_models-0.4.4.dist-info}/METADATA +1 -1
- f3_data_models-0.4.4.dist-info/RECORD +7 -0
- {f3_data_models-0.4.3.dist-info → f3_data_models-0.4.4.dist-info}/WHEEL +1 -1
- f3_data_models-0.4.3.dist-info/RECORD +0 -7
f3_data_models/models.py
CHANGED
@@ -777,13 +777,12 @@ class User(Base):
|
|
777
777
|
""" # noqa: E501
|
778
778
|
|
779
779
|
__tablename__ = "users"
|
780
|
-
__table_args__ = (Index("idx_users_email", func.lower("email"), unique=True),)
|
781
780
|
|
782
781
|
id: Mapped[intpk]
|
783
782
|
f3_name: Mapped[Optional[str]]
|
784
783
|
first_name: Mapped[Optional[str]]
|
785
784
|
last_name: Mapped[Optional[str]]
|
786
|
-
email: Mapped[str] = mapped_column(CIText)
|
785
|
+
email: Mapped[str] = mapped_column(CIText, unique=True)
|
787
786
|
phone: Mapped[Optional[str]]
|
788
787
|
emergency_contact: Mapped[Optional[str]]
|
789
788
|
emergency_phone: Mapped[Optional[str]]
|
f3_data_models/testing.py
CHANGED
@@ -1,33 +1,12 @@
|
|
1
|
-
from f3_data_models.models import
|
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
|
-
|
8
|
-
|
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
|
-
|
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,
|
3
|
+
from typing import Generic, List, Optional, Tuple, Type, TypeVar # noqa
|
4
4
|
|
5
|
+
import pg8000
|
5
6
|
import sqlalchemy
|
6
|
-
from
|
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
|
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
|
-
|
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,
|
@@ -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,7 +0,0 @@
|
|
1
|
-
f3_data_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
f3_data_models/models.py,sha256=3bJUsEC-lENYt5ezqN0pbUQTV3znndLnWnrJVQ3vJOk,46043
|
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.3.dist-info/METADATA,sha256=5_8Rauj6G4fOY5QGaXtgl0nsdUfATnUGBPLISPPCJ_Y,2766
|
6
|
-
f3_data_models-0.4.3.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
7
|
-
f3_data_models-0.4.3.dist-info/RECORD,,
|