plexus-python-common 1.0.15__tar.gz → 1.0.17__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.
Files changed (65) hide show
  1. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/PKG-INFO +1 -1
  2. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/utils/bagutils.py +30 -33
  3. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/utils/ormutils.py +181 -151
  4. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus_python_common.egg-info/PKG-INFO +1 -1
  5. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_tests/common/utils/ormutils_test.py +136 -30
  6. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/.editorconfig +0 -0
  7. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/.github/workflows/pr.yml +0 -0
  8. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/.github/workflows/push.yml +0 -0
  9. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/.gitignore +0 -0
  10. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/MANIFEST.in +0 -0
  11. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/README.md +0 -0
  12. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/VERSION +0 -0
  13. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/pyproject.toml +0 -0
  14. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/jsonutils/dummy.0.jsonl +0 -0
  15. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/jsonutils/dummy.1.jsonl +0 -0
  16. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/jsonutils/dummy.2.jsonl +0 -0
  17. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/0-dummy +0 -0
  18. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/1-dummy +0 -0
  19. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/2-dummy +0 -0
  20. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.0.0.jsonl +0 -0
  21. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.0.0.vol-0.jsonl +0 -0
  22. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.0.jsonl +0 -0
  23. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.1.1.jsonl +0 -0
  24. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.1.1.vol-1.jsonl +0 -0
  25. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.1.jsonl +0 -0
  26. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.2.2.jsonl +0 -0
  27. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.2.2.vol-2.jsonl +0 -0
  28. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.2.jsonl +0 -0
  29. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.csv.part0 +0 -0
  30. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.csv.part1 +0 -0
  31. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.csv.part2 +0 -0
  32. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/resources/unittest/shutils/dummy.txt +0 -0
  33. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/setup.cfg +0 -0
  34. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/setup.py +0 -0
  35. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/__init__.py +0 -0
  36. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/carto/OSMFile.py +0 -0
  37. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/carto/OSMNode.py +0 -0
  38. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/carto/OSMTags.py +0 -0
  39. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/carto/OSMWay.py +0 -0
  40. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/carto/__init__.py +0 -0
  41. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/config.py +0 -0
  42. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/pose.py +0 -0
  43. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/proj.py +0 -0
  44. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/utils/__init__.py +0 -0
  45. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/utils/datautils.py +0 -0
  46. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/utils/jsonutils.py +0 -0
  47. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/utils/s3utils.py +0 -0
  48. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/utils/shutils.py +0 -0
  49. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus/common/utils/strutils.py +0 -0
  50. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus_python_common.egg-info/SOURCES.txt +0 -0
  51. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus_python_common.egg-info/dependency_links.txt +0 -0
  52. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus_python_common.egg-info/not-zip-safe +0 -0
  53. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus_python_common.egg-info/requires.txt +0 -0
  54. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/src/plexus_python_common.egg-info/top_level.txt +0 -0
  55. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_test.py +0 -0
  56. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_tests/__init__.py +0 -0
  57. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_tests/common/carto/osm_file_test.py +0 -0
  58. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_tests/common/carto/osm_tags_test.py +0 -0
  59. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_tests/common/pose_test.py +0 -0
  60. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_tests/common/proj_test.py +0 -0
  61. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_tests/common/utils/bagutils_test.py +0 -0
  62. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_tests/common/utils/datautils_test.py +0 -0
  63. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_tests/common/utils/jsonutils_test.py +0 -0
  64. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_tests/common/utils/shutils_test.py +0 -0
  65. {plexus_python_common-1.0.15 → plexus_python_common-1.0.17}/test/plexus_tests/common/utils/strutils_test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plexus-python-common
3
- Version: 1.0.15
3
+ Version: 1.0.17
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.11
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -3,11 +3,8 @@ from collections.abc import Generator
3
3
  from contextlib import AbstractContextManager
4
4
  from typing import Literal
5
5
 
6
- import sqlalchemy
7
- from sqlalchemy import ForeignKey, Integer, LargeBinary, String
8
- from sqlalchemy import select
9
- from sqlalchemy.orm import DeclarativeBase, Mapped, Session
10
- from sqlalchemy.orm import mapped_column, relationship
6
+ import sqlalchemy as sa
7
+ import sqlalchemy.orm as sa_orm
11
8
 
12
9
  __all__ = [
13
10
  "SerializationFormat",
@@ -27,56 +24,56 @@ SerializationFormat = Literal["cdr", "cdr2", "json", "yaml"]
27
24
  default_bag_db_file = "bag.db"
28
25
 
29
26
 
30
- class BagBase(DeclarativeBase):
27
+ class BagBase(sa_orm.DeclarativeBase):
31
28
  pass
32
29
 
33
30
 
34
31
  class BagSchema(BagBase):
35
32
  __tablename__ = "schema"
36
33
 
37
- schema_version: Mapped[int] = mapped_column(Integer, primary_key=True)
38
- ros_distro: Mapped[str] = mapped_column(String, nullable=False)
34
+ schema_version: sa_orm.Mapped[int] = sa_orm.mapped_column(sa.Integer, primary_key=True)
35
+ ros_distro: sa_orm.Mapped[str] = sa_orm.mapped_column(sa.String, nullable=False)
39
36
 
40
37
 
41
38
  class BagMetadata(BagBase):
42
39
  __tablename__ = "metadata"
43
40
 
44
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
45
- metadata_version: Mapped[int] = mapped_column(Integer, nullable=False)
46
- metadata_text: Mapped[str] = mapped_column(String, nullable=False)
41
+ id: sa_orm.Mapped[int] = sa_orm.mapped_column(sa.Integer, primary_key=True, autoincrement=True)
42
+ metadata_version: sa_orm.Mapped[int] = sa_orm.mapped_column(sa.Integer, nullable=False)
43
+ metadata_text: sa_orm.Mapped[str] = sa_orm.mapped_column(sa.String, nullable=False)
47
44
 
48
45
 
49
46
  class BagTopic(BagBase):
50
47
  __tablename__ = "topics"
51
48
 
52
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
53
- name: Mapped[str] = mapped_column(String, nullable=False)
54
- type: Mapped[str] = mapped_column(String, nullable=False)
55
- serialization_format: Mapped[str] = mapped_column(String, nullable=False)
56
- type_description_hash: Mapped[str] = mapped_column(String, nullable=False)
49
+ id: sa_orm.Mapped[int] = sa_orm.mapped_column(sa.Integer, primary_key=True, autoincrement=True)
50
+ name: sa_orm.Mapped[str] = sa_orm.mapped_column(sa.String, nullable=False)
51
+ type: sa_orm.Mapped[str] = sa_orm.mapped_column(sa.String, nullable=False)
52
+ serialization_format: sa_orm.Mapped[str] = sa_orm.mapped_column(sa.String, nullable=False)
53
+ type_description_hash: sa_orm.Mapped[str] = sa_orm.mapped_column(sa.String, nullable=False)
57
54
 
58
- messages: Mapped[list["BagMessage"]] = relationship("BagMessage", back_populates="topic")
55
+ messages: sa_orm.Mapped[list["BagMessage"]] = sa_orm.relationship("BagMessage", back_populates="topic")
59
56
 
60
57
 
61
58
  class BagMessageDefinition(BagBase):
62
59
  __tablename__ = "message_definitions"
63
60
 
64
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
65
- topic_type: Mapped[str] = mapped_column(String, nullable=False)
66
- encoding: Mapped[str] = mapped_column(String, nullable=False)
67
- encoded_message_definition: Mapped[str] = mapped_column(String, nullable=False)
68
- type_description_hash: Mapped[str] = mapped_column(String, nullable=False)
61
+ id: sa_orm.Mapped[int] = sa_orm.mapped_column(sa.Integer, primary_key=True, autoincrement=True)
62
+ topic_type: sa_orm.Mapped[str] = sa_orm.mapped_column(sa.String, nullable=False)
63
+ encoding: sa_orm.Mapped[str] = sa_orm.mapped_column(sa.String, nullable=False)
64
+ encoded_message_definition: sa_orm.Mapped[str] = sa_orm.mapped_column(sa.String, nullable=False)
65
+ type_description_hash: sa_orm.Mapped[str] = sa_orm.mapped_column(sa.String, nullable=False)
69
66
 
70
67
 
71
68
  class BagMessage(BagBase):
72
69
  __tablename__ = "messages"
73
70
 
74
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
75
- topic_id: Mapped[int] = mapped_column(Integer, ForeignKey("topics.id"), nullable=False)
76
- timestamp: Mapped[int] = mapped_column(Integer, nullable=False)
77
- data: Mapped[bytes] = mapped_column(LargeBinary, nullable=False)
71
+ id: sa_orm.Mapped[int] = sa_orm.mapped_column(sa.Integer, primary_key=True, autoincrement=True)
72
+ topic_id: sa_orm.Mapped[int] = sa_orm.mapped_column(sa.Integer, sa.ForeignKey("topics.id"), nullable=False)
73
+ timestamp: sa_orm.Mapped[int] = sa_orm.mapped_column(sa.Integer, nullable=False)
74
+ data: sa_orm.Mapped[bytes] = sa_orm.mapped_column(sa.LargeBinary, nullable=False)
78
75
 
79
- topic: Mapped["BagTopic"] = relationship("BagTopic", back_populates="messages")
76
+ topic: sa_orm.Mapped["BagTopic"] = sa_orm.relationship("BagTopic", back_populates="messages")
80
77
 
81
78
 
82
79
  class BagReader(AbstractContextManager):
@@ -85,8 +82,8 @@ class BagReader(AbstractContextManager):
85
82
  if not os.path.exists(self.db_path):
86
83
  raise FileNotFoundError(f"could not find SQLite DB at '{db_dir}'")
87
84
 
88
- self.engine = sqlalchemy.create_engine(f"sqlite:///{self.db_path}")
89
- self.session = Session(self.engine)
85
+ self.engine = sa.create_engine(f"sqlite:///{self.db_path}")
86
+ self.session = sa_orm.Session(self.engine)
90
87
  self.topic_map = None
91
88
 
92
89
  def __enter__(self):
@@ -101,7 +98,7 @@ class BagReader(AbstractContextManager):
101
98
 
102
99
  def get_topics(self) -> dict[str, BagTopic]:
103
100
  if self.topic_map is None:
104
- stmt = select(BagTopic)
101
+ stmt = sa.select(BagTopic)
105
102
  self.topic_map = {db_topic.name: db_topic for db_topic in self.session.scalars(stmt).all()}
106
103
  return self.topic_map
107
104
 
@@ -111,7 +108,7 @@ class BagReader(AbstractContextManager):
111
108
  begin_timestamp: int | None = None,
112
109
  end_timestamp: int | None = None,
113
110
  ) -> Generator[BagMessage, None, None]:
114
- stmt = select(BagMessage)
111
+ stmt = sa.select(BagMessage)
115
112
  if topic_names is not None:
116
113
  topic_ids = [db_topic.id for db_topic in self.get_topics().values() if db_topic.name in topic_names]
117
114
  stmt = stmt.where(BagMessage.topic_id.in_(topic_ids))
@@ -129,8 +126,8 @@ class BagWriter(AbstractContextManager):
129
126
  if os.path.exists(self.db_path):
130
127
  os.remove(self.db_path)
131
128
 
132
- self.engine = sqlalchemy.create_engine(f"sqlite:///{self.db_path}")
133
- self.session = sqlalchemy.orm.Session(self.engine)
129
+ self.engine = sa.create_engine(f"sqlite:///{self.db_path}")
130
+ self.session = sa_orm.Session(self.engine)
134
131
  self.topic_map = {}
135
132
 
136
133
  BagBase.metadata.create_all(self.engine)
@@ -36,6 +36,7 @@ __all__ = [
36
36
  "clone_record_model_instance",
37
37
  "clone_snapshot_model_instance",
38
38
  "make_snapshot_model_trigger",
39
+ "db_make_order_by_clause",
39
40
  "db_create_serial_model",
40
41
  "db_create_serial_models",
41
42
  "db_read_serial_model",
@@ -162,8 +163,7 @@ class SerialModelMixinProtocol(Protocol):
162
163
  sid: int | None
163
164
 
164
165
 
165
- class RecordModelMixinProtocol(Protocol):
166
- sid: int | None
166
+ class RecordModelMixinProtocol(SerialModelMixinProtocol):
167
167
  created_at: datetime.datetime | None
168
168
  updated_at: datetime.datetime | None
169
169
 
@@ -177,8 +177,7 @@ class RecordModelMixinProtocol(Protocol):
177
177
  ...
178
178
 
179
179
 
180
- class SnapshotModelMixinProtocol(Protocol):
181
- sid: int | None
180
+ class SnapshotModelMixinProtocol(SerialModelMixinProtocol):
182
181
  created_at: datetime.datetime | None
183
182
  expired_at: datetime.datetime | None
184
183
  record_sid: int | None
@@ -388,13 +387,18 @@ class SnapshotModel(make_base_model(), make_snapshot_model_mixin(), table=True):
388
387
  pass
389
388
 
390
389
 
390
+ SerialModelT = TypeVar("SerialModelT", bound=SerialModelMixin)
391
+ RecordModelT = TypeVar("RecordModelT", bound=RecordModelMixin)
392
+ SnapshotModelT = TypeVar("SnapshotModelT", bound=SnapshotModelMixin)
393
+
394
+
391
395
  def clone_serial_model_instance(
392
- model: type[SerialModelMixin],
396
+ model: type[SerialModelT],
393
397
  instance: SerialModelMixin,
394
398
  *,
395
399
  clear_meta_fields: bool = True,
396
400
  inplace: bool = False,
397
- ) -> SerialModelMixin:
401
+ ) -> SerialModelT:
398
402
  result = model.model_validate(instance)
399
403
  result = instance if inplace else result
400
404
  if clear_meta_fields:
@@ -403,12 +407,12 @@ def clone_serial_model_instance(
403
407
 
404
408
 
405
409
  def clone_record_model_instance(
406
- model: type[RecordModelMixin],
410
+ model: type[RecordModelT],
407
411
  instance: RecordModelMixin,
408
412
  *,
409
413
  clear_meta_fields: bool = True,
410
414
  inplace: bool = False,
411
- ) -> RecordModelMixin:
415
+ ) -> RecordModelT:
412
416
  result = model.model_validate(instance)
413
417
  result = instance if inplace else result
414
418
  if clear_meta_fields:
@@ -419,12 +423,12 @@ def clone_record_model_instance(
419
423
 
420
424
 
421
425
  def clone_snapshot_model_instance(
422
- model: type[SnapshotModelMixin],
426
+ model: type[SnapshotModelT],
423
427
  instance: SnapshotModelMixin,
424
428
  *,
425
429
  clear_meta_fields: bool = True,
426
430
  inplace: bool = False,
427
- ) -> SnapshotModelMixin:
431
+ ) -> SnapshotModelT:
428
432
  result = model.model_validate(instance)
429
433
  result = instance if inplace else result
430
434
  if clear_meta_fields:
@@ -500,35 +504,48 @@ def make_snapshot_model_trigger(engine: sa.Engine, model: type[SQLModel]):
500
504
  conn.execute(sa.text(create_snapshot_auto_update_trigger_sql))
501
505
 
502
506
 
507
+ def db_make_order_by_clause(model: type[SerialModelT], order_by: list[str] = None):
508
+ order_criteria = []
509
+ if order_by:
510
+ for field in order_by:
511
+ if field.startswith("-"):
512
+ order_criteria.append(sa.desc(getattr(model, field[1:])))
513
+ else:
514
+ order_criteria.append(sa.asc(getattr(model, field)))
515
+ else:
516
+ order_criteria.append(model.sid)
517
+ return order_criteria
518
+
519
+
503
520
  def db_create_serial_model(
504
521
  db: sa_orm.Session,
505
- model: type[SerialModelMixin],
522
+ model: type[SerialModelT],
506
523
  instance: SerialModelMixin,
507
- ) -> SerialModelMixin:
508
- with db.begin(nested=db.in_transaction()):
509
- db_instance = clone_serial_model_instance(model, instance)
510
- db.add(db_instance)
524
+ ) -> SerialModelT:
525
+ db_instance = clone_serial_model_instance(model, instance)
526
+ db.add(db_instance)
527
+ db.flush()
511
528
 
512
529
  return db_instance
513
530
 
514
531
 
515
532
  def db_create_serial_models(
516
533
  db: sa_orm.Session,
517
- model: type[SerialModelMixin],
534
+ model: type[SerialModelT],
518
535
  instances: list[SerialModelMixin],
519
- ) -> list[SerialModelMixin]:
520
- with db.begin(nested=db.in_transaction()):
521
- db_instances = [clone_serial_model_instance(model, instance) for instance in instances]
522
- db.bulk_save_objects(db_instances, return_defaults=True)
536
+ ) -> list[SerialModelT]:
537
+ db_instances = [clone_serial_model_instance(model, instance) for instance in instances]
538
+ db.add_all(db_instances)
539
+ db.flush()
523
540
 
524
541
  return db_instances
525
542
 
526
543
 
527
544
  def db_read_serial_model(
528
545
  db: sa_orm.Session,
529
- model: type[SerialModelMixin],
546
+ model: type[SerialModelT],
530
547
  sid: int,
531
- ) -> SerialModelMixin:
548
+ ) -> SerialModelT:
532
549
  db_instance = db.query(model).where(model.sid == sid).one_or_none()
533
550
  if db_instance is None:
534
551
  raise sa_exc.NoResultFound(f"'{model}' of specified sid '{sid}' not found")
@@ -538,136 +555,139 @@ def db_read_serial_model(
538
555
 
539
556
  def db_read_serial_models(
540
557
  db: sa_orm.Session,
541
- model: type[SerialModelMixin],
558
+ model: type[SerialModelT],
542
559
  skip: int,
543
560
  limit: int,
544
- ) -> list[SerialModelMixin]:
545
- return db.query(model).order_by(model.sid).offset(skip).limit(limit).all()
561
+ order_by: list[str] = None,
562
+ ) -> list[SerialModelT]:
563
+ return db.query(model).order_by(*db_make_order_by_clause(model, order_by)).offset(skip).limit(limit).all()
546
564
 
547
565
 
548
566
  def db_update_serial_model(
549
567
  db: sa_orm.Session,
550
- model: type[SerialModelMixin],
568
+ model: type[SerialModelT],
551
569
  instance: SerialModelMixin,
552
- ) -> SerialModelMixin:
553
- with db.begin(nested=db.in_transaction()):
554
- db_instance = db.query(model).where(model.sid == instance.sid).one_or_none()
555
- if db_instance is None:
556
- raise sa_exc.NoResultFound(f"'{model}' of specified sid '{instance.sid}' not found")
570
+ sid: int,
571
+ ) -> SerialModelT:
572
+ db_instance = db.query(model).where(model.sid == sid).one_or_none()
573
+ if db_instance is None:
574
+ raise sa_exc.NoResultFound(f"'{model}' of specified sid '{sid}' not found")
557
575
 
558
- db_instance = model_copy_from(db_instance, instance, exclude_none=True)
559
- db_instance = clone_serial_model_instance(model, db_instance, clear_meta_fields=False, inplace=True)
576
+ db_instance = model_copy_from(db_instance, clone_serial_model_instance(model, instance), exclude_none=True)
577
+ db_instance = clone_serial_model_instance(model, db_instance, clear_meta_fields=False, inplace=True)
578
+ db.flush()
560
579
 
561
580
  return db_instance
562
581
 
563
582
 
564
583
  def db_delete_serial_model(
565
584
  db: sa_orm.Session,
566
- model: type[SerialModelMixin],
585
+ model: type[SerialModelT],
567
586
  sid: int,
568
- ) -> SerialModelMixin:
569
- with db.begin(nested=db.in_transaction()):
570
- db_instance = db.query(model).where(model.sid == sid).one_or_none()
571
- if db_instance is None:
572
- raise sa_exc.NoResultFound(f"'{model}' of specified sid '{sid}' not found")
587
+ ) -> SerialModelT:
588
+ db_instance = db.query(model).where(model.sid == sid).one_or_none()
589
+ if db_instance is None:
590
+ raise sa_exc.NoResultFound(f"'{model}' of specified sid '{sid}' not found")
573
591
 
574
- db.delete(db_instance)
592
+ db.delete(db_instance)
593
+ db.flush()
575
594
 
576
595
  return db_instance
577
596
 
578
597
 
579
598
  def db_create_record_model(
580
599
  db: sa_orm.Session,
581
- model: type[RecordModelMixin],
600
+ model: type[RecordModelT],
582
601
  instance: RecordModelMixin,
583
602
  created_at: datetime.datetime | None = None,
584
- ) -> RecordModelMixin:
585
- with db.begin(nested=db.in_transaction()):
586
- db_instance = clone_record_model_instance(model, instance)
587
- db_instance.created_at = created_at
588
- db_instance.updated_at = created_at
589
- db.add(db_instance)
603
+ ) -> RecordModelT:
604
+ db_instance = clone_record_model_instance(model, instance)
605
+ db_instance.created_at = created_at
606
+ db_instance.updated_at = created_at
607
+ db.add(db_instance)
608
+ db.flush()
590
609
 
591
610
  return db_instance
592
611
 
593
612
 
594
613
  def db_create_record_models(
595
614
  db: sa_orm.Session,
596
- model: type[RecordModelMixin],
615
+ model: type[RecordModelT],
597
616
  instances: list[RecordModelMixin],
598
617
  created_at: datetime.datetime | None = None,
599
- ) -> list[RecordModelMixin]:
600
- with db.begin(nested=db.in_transaction()):
601
- db_instances = [clone_record_model_instance(model, instance) for instance in instances]
602
- for db_instance in db_instances:
603
- db_instance.created_at = created_at
604
- db_instance.updated_at = created_at
605
- db.bulk_save_objects(db_instances, return_defaults=True)
618
+ ) -> list[RecordModelT]:
619
+ db_instances = [clone_record_model_instance(model, instance) for instance in instances]
620
+ for db_instance in db_instances:
621
+ db_instance.created_at = created_at
622
+ db_instance.updated_at = created_at
623
+ db.add_all(db_instances)
624
+ db.flush()
606
625
 
607
626
  return db_instances
608
627
 
609
628
 
610
629
  def db_update_record_model(
611
630
  db: sa_orm.Session,
612
- model: type[RecordModelMixin],
631
+ model: type[RecordModelT],
613
632
  instance: RecordModelMixin,
614
633
  sid: int,
615
634
  updated_at: datetime.datetime,
616
- ) -> RecordModelMixin:
617
- with db.begin(nested=db.in_transaction()):
618
- db_instance = db.query(model).where(model.sid == sid).one_or_none()
619
- if db_instance is None:
620
- raise sa_exc.NoResultFound(f"'{model}' of specified sid '{sid}' not found")
635
+ ) -> RecordModelT:
636
+ db_instance = db.query(model).where(model.sid == sid).one_or_none()
637
+ if db_instance is None:
638
+ raise sa_exc.NoResultFound(f"'{model}' of specified sid '{sid}' not found")
621
639
 
622
- db_instance = model_copy_from(db_instance, instance, exclude_none=True)
623
- db_instance.updated_at = updated_at
624
- db_instance = clone_record_model_instance(model, db_instance, clear_meta_fields=False, inplace=True)
640
+ db_instance = model_copy_from(db_instance, clone_record_model_instance(model, instance), exclude_none=True)
641
+ db_instance.updated_at = updated_at
642
+ db_instance = clone_record_model_instance(model, db_instance, clear_meta_fields=False, inplace=True)
643
+ db.flush()
625
644
 
626
645
  return db_instance
627
646
 
628
647
 
629
648
  def db_create_snapshot_model(
630
649
  db: sa_orm.Session,
631
- model: type[SnapshotModelMixin],
650
+ model: type[SnapshotModelT],
632
651
  instance: SnapshotModelMixin,
633
652
  created_at: datetime.datetime,
634
- ) -> SnapshotModelMixin:
635
- with db.begin(nested=db.in_transaction()):
636
- db_instance = clone_snapshot_model_instance(model, instance)
653
+ ) -> SnapshotModelT:
654
+ db_instance = clone_snapshot_model_instance(model, instance)
655
+ db_instance.created_at = created_at
656
+ db_instance.expired_at = None
657
+ db.add(db_instance)
658
+ db.flush()
637
659
 
638
- db_instance.created_at = created_at
639
- db_instance.expired_at = None
640
- db.add(db_instance)
641
- db.flush([db_instance])
642
- db_instance.record_sid = db_instance.sid
660
+ db_instance.record_sid = db_instance.sid
661
+ db.flush()
643
662
 
644
663
  return db_instance
645
664
 
646
665
 
647
666
  def db_create_snapshot_models(
648
667
  db: sa_orm.Session,
649
- model: type[SnapshotModelMixin],
668
+ model: type[SnapshotModelT],
650
669
  instances: list[SnapshotModelMixin],
651
670
  created_at: datetime.datetime,
652
- ) -> list[SnapshotModelMixin]:
653
- with db.begin(nested=db.in_transaction()):
654
- db_instances = [clone_snapshot_model_instance(model, instance) for instance in instances]
655
- for db_instance in db_instances:
656
- db_instance.created_at = created_at
657
- db_instance.expired_at = None
658
- db.bulk_save_objects(db_instances, return_defaults=True)
659
- db.flush(db_instances)
660
- for db_instance in db_instances:
661
- db_instance.record_sid = db_instance.sid
671
+ ) -> list[SnapshotModelT]:
672
+ db_instances = [clone_snapshot_model_instance(model, instance) for instance in instances]
673
+ for db_instance in db_instances:
674
+ db_instance.created_at = created_at
675
+ db_instance.expired_at = None
676
+ db.add_all(db_instances)
677
+ db.flush()
678
+
679
+ for db_instance in db_instances:
680
+ db_instance.record_sid = db_instance.sid
681
+ db.flush()
662
682
 
663
683
  return db_instances
664
684
 
665
685
 
666
686
  def db_read_snapshot_models_of_record(
667
687
  db: sa_orm.Session,
668
- model: type[SnapshotModelMixin],
688
+ model: type[SnapshotModelT],
669
689
  record_sid: int,
670
- ) -> list[SnapshotModelMixin]:
690
+ ) -> list[SnapshotModelT]:
671
691
  return (
672
692
  db
673
693
  .query(model)
@@ -679,9 +699,9 @@ def db_read_snapshot_models_of_record(
679
699
 
680
700
  def db_read_latest_snapshot_model_of_record(
681
701
  db: sa_orm.Session,
682
- model: type[SnapshotModelMixin],
702
+ model: type[SnapshotModelT],
683
703
  record_sid: int,
684
- ) -> SnapshotModelMixin:
704
+ ) -> SnapshotModelT:
685
705
  db_instance = (
686
706
  db
687
707
  .query(model)
@@ -697,9 +717,9 @@ def db_read_latest_snapshot_model_of_record(
697
717
 
698
718
  def db_read_active_snapshot_model_of_record(
699
719
  db: sa_orm.Session,
700
- model: type[SnapshotModelMixin],
720
+ model: type[SnapshotModelT],
701
721
  record_sid: int,
702
- ) -> SnapshotModelMixin:
722
+ ) -> SnapshotModelT:
703
723
  db_instance = db.query(model).where(model.record_sid == record_sid, model.expired_at.is_(None)).one_or_none()
704
724
  if db_instance is None:
705
725
  raise sa_exc.NoResultFound(f"Active '{model}' of specified record_sid '{record_sid}' not found")
@@ -709,24 +729,25 @@ def db_read_active_snapshot_model_of_record(
709
729
 
710
730
  def db_read_expired_snapshot_models_of_record(
711
731
  db: sa_orm.Session,
712
- model: type[SnapshotModelMixin],
732
+ model: type[SnapshotModelT],
713
733
  record_sid: int,
714
- ) -> list[SnapshotModelMixin]:
734
+ ) -> list[SnapshotModelT]:
715
735
  return (
716
736
  db
717
737
  .query(model)
718
738
  .where(model.record_sid == record_sid, model.expired_at.is_not(None))
719
- .order_by(model.expired_at.desc())
739
+ .order_by(model.created_at.desc())
720
740
  .all()
721
741
  )
722
742
 
723
743
 
724
744
  def db_read_latest_snapshot_models(
725
745
  db: sa_orm.Session,
726
- model: type[SnapshotModelMixin],
746
+ model: type[SnapshotModelT],
727
747
  skip: int,
728
748
  limit: int,
729
- ) -> list[SnapshotModelMixin]:
749
+ order_by: list[str] = None,
750
+ ) -> list[SnapshotModelT]:
730
751
  subquery = (
731
752
  db
732
753
  .query(model.record_sid,
@@ -740,7 +761,7 @@ def db_read_latest_snapshot_models(
740
761
  .query(model)
741
762
  .join(subquery,
742
763
  sa.and_(model.record_sid == subquery.c.record_sid, model.created_at == subquery.c.max_created_at))
743
- .order_by(model.record_sid)
764
+ .order_by(*db_make_order_by_clause(model, order_by))
744
765
  .offset(skip)
745
766
  .limit(limit)
746
767
  .all()
@@ -749,88 +770,97 @@ def db_read_latest_snapshot_models(
749
770
 
750
771
  def db_read_active_snapshot_models(
751
772
  db: sa_orm.Session,
752
- model: type[SnapshotModelMixin],
773
+ model: type[SnapshotModelT],
753
774
  skip: int,
754
775
  limit: int,
755
- ) -> list[SnapshotModelMixin]:
756
- return db.query(model).where(model.expired_at.is_(None)).offset(skip).limit(limit).all()
776
+ order_by: list[str] = None,
777
+ ) -> list[SnapshotModelT]:
778
+ return (
779
+ db
780
+ .query(model)
781
+ .where(model.expired_at.is_(None))
782
+ .order_by(*db_make_order_by_clause(model, order_by))
783
+ .offset(skip)
784
+ .limit(limit)
785
+ .all()
786
+ )
757
787
 
758
788
 
759
789
  def db_update_snapshot_model(
760
790
  db: sa_orm.Session,
761
- model: type[SnapshotModelMixin],
791
+ model: type[SnapshotModelT],
762
792
  instance: SnapshotModelMixin,
763
793
  record_sid: int,
764
794
  updated_at: datetime.datetime,
765
- ) -> SnapshotModelMixin:
766
- with db.begin(nested=db.in_transaction()):
767
- db_instance = db.query(model).where(model.record_sid == record_sid, model.expired_at.is_(None)).one_or_none()
768
- if db_instance is None:
769
- raise sa_exc.NoResultFound(f"Active '{model}' of specified record_sid '{record_sid}' not found")
795
+ ) -> SnapshotModelT:
796
+ db_instance = db.query(model).where(model.record_sid == record_sid, model.expired_at.is_(None)).one_or_none()
797
+ if db_instance is None:
798
+ raise sa_exc.NoResultFound(f"Active '{model}' of specified record_sid '{record_sid}' not found")
770
799
 
771
- db_instance.expired_at = updated_at
772
- db_instance = clone_snapshot_model_instance(model, db_instance, clear_meta_fields=False, inplace=True)
800
+ db_instance.expired_at = updated_at
801
+ db_instance = clone_snapshot_model_instance(model, db_instance, clear_meta_fields=False, inplace=True)
802
+ db.flush()
773
803
 
774
- db_new_instance = clone_snapshot_model_instance(model, instance)
775
- db_new_instance.record_sid = record_sid
776
- db_new_instance.created_at = updated_at
777
- db_new_instance.expired_at = None
778
- db.add(db_new_instance)
804
+ db_new_instance = clone_snapshot_model_instance(model, instance)
805
+ db_new_instance.record_sid = record_sid
806
+ db_new_instance.created_at = updated_at
807
+ db_new_instance.expired_at = None
808
+ db.add(db_new_instance)
809
+ db.flush()
779
810
 
780
811
  return db_new_instance
781
812
 
782
813
 
783
814
  def db_expire_snapshot_model(
784
815
  db: sa_orm.Session,
785
- model: type[SnapshotModelMixin],
816
+ model: type[SnapshotModelT],
786
817
  record_sid: int,
787
818
  updated_at: datetime.datetime,
788
- ) -> SnapshotModelMixin:
789
- with db.begin(nested=db.in_transaction()):
790
- db_instance = (
791
- db
792
- .query(model)
793
- .where(model.record_sid == record_sid, model.expired_at.is_(None))
794
- .one_or_none()
795
- )
796
- if db_instance is None:
797
- raise sa_exc.NoResultFound(f"Active '{model}' of specified record_sid '{record_sid}' not found")
819
+ ) -> SnapshotModelT:
820
+ db_instance = (
821
+ db
822
+ .query(model)
823
+ .where(model.record_sid == record_sid, model.expired_at.is_(None))
824
+ .one_or_none()
825
+ )
826
+ if db_instance is None:
827
+ raise sa_exc.NoResultFound(f"Active '{model}' of specified record_sid '{record_sid}' not found")
798
828
 
799
- db_instance.expired_at = updated_at
800
- db_instance = clone_snapshot_model_instance(model, db_instance, clear_meta_fields=False, inplace=True)
829
+ db_instance.expired_at = updated_at
830
+ db_instance = clone_snapshot_model_instance(model, db_instance, clear_meta_fields=False, inplace=True)
831
+ db.flush()
801
832
 
802
833
  return db_instance
803
834
 
804
835
 
805
836
  def db_activate_snapshot_model(
806
837
  db: sa_orm.Session,
807
- model: type[SnapshotModelMixin],
838
+ model: type[SnapshotModelT],
808
839
  record_sid: int,
809
840
  updated_at: datetime.datetime,
810
- ) -> SnapshotModelMixin:
811
- with db.begin(nested=db.in_transaction()):
812
- db_instance = db.query(model).where(model.record_sid == record_sid, model.expired_at.is_(None)).one_or_none()
813
- if db_instance is not None:
814
- raise sa_exc.MultipleResultsFound(f"Active '{model}' of specified record_sid '{record_sid}' already exists")
815
-
816
- db_instance = (
817
- db
818
- .query(model)
819
- .where(model.record_sid == record_sid, model.expired_at.is_not(None))
820
- .order_by(model.expired_at.desc())
821
- .first()
822
- )
823
- if db_instance is None:
824
- raise sa_exc.NoResultFound(f"Expired '{model}' of specified record_sid '{record_sid}' not found")
825
-
826
- db_new_instance = clone_snapshot_model_instance(model, db_instance)
827
- db_new_instance.record_sid = record_sid
828
- db_new_instance.created_at = db_instance.expired_at
829
- db_new_instance.expired_at = updated_at
830
-
831
- db_new_instance = clone_snapshot_model_instance(model, db_new_instance, clear_meta_fields=False, inplace=True)
832
- db_new_instance.created_at = updated_at
833
- db_new_instance.expired_at = None
834
- db.add(db_new_instance)
841
+ ) -> SnapshotModelT:
842
+ db_instance = db.query(model).where(model.record_sid == record_sid, model.expired_at.is_(None)).one_or_none()
843
+ if db_instance is not None:
844
+ raise sa_exc.MultipleResultsFound(f"Active '{model}' of specified record_sid '{record_sid}' already exists")
845
+
846
+ db_instance = (
847
+ db
848
+ .query(model)
849
+ .where(model.record_sid == record_sid, model.expired_at.is_not(None))
850
+ .order_by(model.created_at.desc())
851
+ .first()
852
+ )
853
+ if db_instance is None:
854
+ raise sa_exc.NoResultFound(f"Expired '{model}' of specified record_sid '{record_sid}' not found")
855
+
856
+ db_new_instance = clone_snapshot_model_instance(model, db_instance)
857
+ db_new_instance.record_sid = record_sid
858
+ db_new_instance.created_at = db_instance.expired_at
859
+ db_new_instance.expired_at = updated_at
860
+ db_new_instance = clone_snapshot_model_instance(model, db_new_instance, clear_meta_fields=False, inplace=True)
861
+ db_new_instance.created_at = updated_at
862
+ db_new_instance.expired_at = None
863
+ db.add(db_new_instance)
864
+ db.flush()
835
865
 
836
866
  return db_new_instance
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plexus-python-common
3
- Version: 1.0.15
3
+ Version: 1.0.17
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.11
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -10,11 +10,12 @@ from iker.common.utils.dbutils import make_scheme
10
10
  from iker.common.utils.dtutils import dt_parse_iso
11
11
  from iker.common.utils.jsonutils import JsonType
12
12
  from iker.common.utils.randutils import randomizer
13
- from sqlmodel import Field
13
+ from sqlmodel import Field, SQLModel
14
14
 
15
15
  from plexus.common.utils.ormutils import (
16
16
  db_activate_snapshot_model,
17
17
  db_create_record_model,
18
+ db_create_serial_model,
18
19
  db_create_snapshot_model,
19
20
  db_delete_serial_model,
20
21
  db_expire_snapshot_model,
@@ -26,6 +27,7 @@ from plexus.common.utils.ormutils import (
26
27
  db_read_serial_models,
27
28
  db_read_snapshot_models_of_record,
28
29
  db_update_record_model,
30
+ db_update_serial_model,
29
31
  db_update_snapshot_model,
30
32
  )
31
33
  from plexus.common.utils.ormutils import (
@@ -44,48 +46,151 @@ fixture_postgresql_test = pytest_postgresql.factories.postgresql("fixture_postgr
44
46
  DummyBaseModel = make_base_model()
45
47
 
46
48
 
47
- class DummySerialModel(DummyBaseModel, make_serial_model_mixin(), table=True):
48
- __tablename__ = "dummy_serial_model"
49
+ def make_dummy_model():
50
+ class Model(SQLModel):
51
+ dummy_str: str = Field(sa_column=sa.Column(sa_pg.VARCHAR(256)), default="")
52
+ dummy_int: int = Field(sa_column=sa.Column(sa_pg.BIGINT), default=0)
53
+ dummy_float: float = Field(sa_column=sa.Column(sa_pg.DOUBLE_PRECISION), default=0.0)
54
+ dummy_bool: bool = Field(sa_column=sa.Column(sa_pg.BOOLEAN), default=False)
55
+ dummy_array: list[str] = Field(sa_column=sa.Column(sa_pg.ARRAY(sa_pg.VARCHAR(64))))
56
+ dummy_json: JsonType = Field(sa_column=sa.Column(sa_pg.JSONB))
49
57
 
50
- dummy_str: str = Field(sa_column=sa.Column(sa_pg.VARCHAR(256)), default="")
51
- dummy_int: int = Field(sa_column=sa.Column(sa_pg.BIGINT), default=0)
52
- dummy_float: float = Field(sa_column=sa.Column(sa_pg.DOUBLE_PRECISION), default=0.0)
53
- dummy_bool: bool = Field(sa_column=sa.Column(sa_pg.BOOLEAN), default=False)
54
- dummy_array: list[str] = Field(sa_column=sa.Column(sa_pg.ARRAY(sa_pg.VARCHAR(64))))
55
- dummy_json: JsonType = Field(sa_column=sa.Column(sa_pg.JSONB))
58
+ return Model
56
59
 
57
60
 
58
- class DummyRecordModel(DummyBaseModel, make_record_model_mixin(), table=True):
59
- __tablename__ = "dummy_record_model"
61
+ DummyModel = make_dummy_model()
60
62
 
61
- dummy_str: str = Field(sa_column=sa.Column(sa_pg.VARCHAR(256)), default="")
62
- dummy_int: int = Field(sa_column=sa.Column(sa_pg.BIGINT), default=0)
63
- dummy_float: float = Field(sa_column=sa.Column(sa_pg.DOUBLE_PRECISION), default=0.0)
64
- dummy_bool: bool = Field(sa_column=sa.Column(sa_pg.BOOLEAN), default=False)
65
- dummy_array: list[str] = Field(sa_column=sa.Column(sa_pg.ARRAY(sa_pg.VARCHAR(64))))
66
- dummy_json: JsonType = Field(sa_column=sa.Column(sa_pg.JSONB))
67
63
 
64
+ class DummySerialModel(DummyBaseModel, make_dummy_model(), make_serial_model_mixin(), table=True):
65
+ __tablename__ = "dummy_serial_model"
66
+
67
+
68
+ class DummyRecordModel(DummyBaseModel, make_dummy_model(), make_record_model_mixin(), table=True):
69
+ __tablename__ = "dummy_record_model"
68
70
  __table_args__ = (
69
71
  record_model_mixin.make_index_created_at("ix_dummy_record_model_created_at"),
70
72
  )
71
73
 
72
74
 
73
- class DummySnapshotModel(DummyBaseModel, make_snapshot_model_mixin(), table=True):
75
+ class DummySnapshotModel(DummyBaseModel, make_dummy_model(), make_snapshot_model_mixin(), table=True):
74
76
  __tablename__ = "dummy_snapshot_model"
75
-
76
- dummy_str: str = Field(sa_column=sa.Column(sa_pg.VARCHAR(256)), default="")
77
- dummy_int: int = Field(sa_column=sa.Column(sa_pg.BIGINT), default=0)
78
- dummy_float: float = Field(sa_column=sa.Column(sa_pg.DOUBLE_PRECISION), default=0.0)
79
- dummy_bool: bool = Field(sa_column=sa.Column(sa_pg.BOOLEAN), default=False)
80
- dummy_array: list[str] = Field(sa_column=sa.Column(sa_pg.ARRAY(sa_pg.VARCHAR(64))))
81
- dummy_json: JsonType = Field(sa_column=sa.Column(sa_pg.JSONB))
82
-
83
77
  __table_args__ = (
84
78
  snapshot_model_mixin.make_index_created_at_expired_at("ix_dummy_snapshot_model_created_at_expired_at"),
85
79
  snapshot_model_mixin.make_active_unique_index_record_sid("ix_au_dummy_snapshot_model_record_sid"),
86
80
  )
87
81
 
88
82
 
83
+ def test_db_serial_model_crud(fixture_postgresql_test_proc, fixture_postgresql_test):
84
+ scheme = make_scheme(Dialects.postgresql, Drivers.psycopg)
85
+ host = fixture_postgresql_test.info.host
86
+ port = fixture_postgresql_test.info.port
87
+ user = fixture_postgresql_test.info.user
88
+ database = fixture_postgresql_test.info.dbname
89
+
90
+ maker = ConnectionMaker.create(scheme,
91
+ host,
92
+ port,
93
+ user,
94
+ None,
95
+ database,
96
+ session_opts=dict(expire_on_commit=False))
97
+
98
+ DummyBaseModel.metadata.create_all(maker.engine)
99
+
100
+ rng = randomizer()
101
+
102
+ def random_record() -> DummyModel:
103
+ return DummyModel(
104
+ dummy_int=rng.next_int(0, 1000),
105
+ dummy_str=rng.random_alphanumeric(rng.next_int(10, 20)),
106
+ dummy_float=rng.next_float(0.0, 100.0),
107
+ dummy_bool=rng.next_bool(),
108
+ dummy_array=list(rng.random_ascii(rng.next_int(10, 20)) for _ in range(rng.next_int(10, 20))),
109
+ dummy_json=rng.random_json_object(5),
110
+ )
111
+
112
+ with maker.make_session() as session:
113
+ session.execute(sa.sql.text("SET TIMEZONE TO 'UTC'"))
114
+ session.commit()
115
+
116
+ create_records = [random_record() for _ in range(0, 100)]
117
+ update_records = [random_record() for _ in range(0, 100)]
118
+
119
+ for i in range(0, 100):
120
+ with pytest.raises(sa_exc.NoResultFound):
121
+ db_read_serial_model(session, DummySerialModel, i + 1)
122
+
123
+ for i in range(0, 100):
124
+ result = db_create_serial_model(session, DummySerialModel, create_records[i])
125
+
126
+ assert result.sid == i + 1
127
+ assert result.dummy_int == create_records[i].dummy_int
128
+ assert result.dummy_str == create_records[i].dummy_str
129
+ assert result.dummy_float == create_records[i].dummy_float
130
+ assert result.dummy_bool == create_records[i].dummy_bool
131
+ assert result.dummy_array == create_records[i].dummy_array
132
+ assert result.dummy_json == create_records[i].dummy_json
133
+
134
+ for i in range(0, 100):
135
+ result = db_read_serial_model(session, DummySerialModel, i + 1)
136
+
137
+ assert result.sid == i + 1
138
+ assert result.dummy_int == create_records[i].dummy_int
139
+ assert result.dummy_str == create_records[i].dummy_str
140
+ assert result.dummy_float == create_records[i].dummy_float
141
+ assert result.dummy_bool == create_records[i].dummy_bool
142
+ assert result.dummy_array == create_records[i].dummy_array
143
+ assert result.dummy_json == create_records[i].dummy_json
144
+
145
+ for i in range(0, 100):
146
+ result = db_update_serial_model(session, DummySerialModel, update_records[i], i + 1)
147
+
148
+ assert result.sid == i + 1
149
+ assert result.dummy_int == update_records[i].dummy_int
150
+ assert result.dummy_str == update_records[i].dummy_str
151
+ assert result.dummy_float == update_records[i].dummy_float
152
+ assert result.dummy_bool == update_records[i].dummy_bool
153
+ assert result.dummy_array == update_records[i].dummy_array
154
+ assert result.dummy_json == update_records[i].dummy_json
155
+
156
+ results = db_read_serial_models(session, DummySerialModel, 0, 200)
157
+ assert len(results) == 100
158
+
159
+ for i, (result, update_record) in enumerate(zip(results, update_records)):
160
+ assert result.sid == i + 1
161
+ assert result.dummy_int == update_record.dummy_int
162
+ assert result.dummy_str == update_record.dummy_str
163
+ assert result.dummy_float == update_record.dummy_float
164
+ assert result.dummy_bool == update_record.dummy_bool
165
+ assert result.dummy_array == update_record.dummy_array
166
+ assert result.dummy_json == update_record.dummy_json
167
+
168
+ for i in range(0, 100):
169
+ result = db_read_serial_model(session, DummySerialModel, i + 1)
170
+
171
+ assert result.sid == i + 1
172
+ assert result.dummy_int == update_records[i].dummy_int
173
+ assert result.dummy_str == update_records[i].dummy_str
174
+ assert result.dummy_float == update_records[i].dummy_float
175
+ assert result.dummy_bool == update_records[i].dummy_bool
176
+ assert result.dummy_array == update_records[i].dummy_array
177
+ assert result.dummy_json == update_records[i].dummy_json
178
+
179
+ for i in range(0, 100):
180
+ result = db_delete_serial_model(session, DummySerialModel, i + 1)
181
+
182
+ assert result.sid == i + 1
183
+ assert result.dummy_int == update_records[i].dummy_int
184
+ assert result.dummy_str == update_records[i].dummy_str
185
+ assert result.dummy_float == update_records[i].dummy_float
186
+ assert result.dummy_bool == update_records[i].dummy_bool
187
+ assert result.dummy_array == update_records[i].dummy_array
188
+ assert result.dummy_json == update_records[i].dummy_json
189
+
190
+ results = db_read_serial_models(session, DummySerialModel, 0, 200)
191
+ assert len(results) == 0
192
+
193
+
89
194
  def test_db_record_model_crud(fixture_postgresql_test_proc, fixture_postgresql_test):
90
195
  scheme = make_scheme(Dialects.postgresql, Drivers.psycopg)
91
196
  host = fixture_postgresql_test.info.host
@@ -105,8 +210,8 @@ def test_db_record_model_crud(fixture_postgresql_test_proc, fixture_postgresql_t
105
210
 
106
211
  rng = randomizer()
107
212
 
108
- def random_record() -> DummyRecordModel:
109
- return DummyRecordModel(
213
+ def random_record() -> DummyModel:
214
+ return DummyModel(
110
215
  dummy_int=rng.next_int(0, 1000),
111
216
  dummy_str=rng.random_alphanumeric(rng.next_int(10, 20)),
112
217
  dummy_float=rng.next_float(0.0, 100.0),
@@ -215,6 +320,7 @@ def test_db_record_model_crud(fixture_postgresql_test_proc, fixture_postgresql_t
215
320
  results = db_read_serial_models(session, DummyRecordModel, 0, 200)
216
321
  assert len(results) == 0
217
322
 
323
+
218
324
  def test_db_snapshot_model_crud(fixture_postgresql_test_proc, fixture_postgresql_test):
219
325
  scheme = make_scheme(Dialects.postgresql, Drivers.psycopg)
220
326
  host = fixture_postgresql_test.info.host
@@ -235,8 +341,8 @@ def test_db_snapshot_model_crud(fixture_postgresql_test_proc, fixture_postgresql
235
341
 
236
342
  rng = randomizer()
237
343
 
238
- def random_record() -> DummySnapshotModel:
239
- return DummySnapshotModel(
344
+ def random_record() -> DummyModel:
345
+ return DummyModel(
240
346
  dummy_int=rng.next_int(0, 1000),
241
347
  dummy_str=rng.random_alphanumeric(rng.next_int(10, 20)),
242
348
  dummy_float=rng.next_float(0.0, 100.0),