plexus-python-common 1.0.68__py3-none-any.whl → 1.0.70__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.
- plexus/common/utils/ormutils.py +28 -26
- plexus/common/utils/tagutils.py +184 -118
- {plexus_python_common-1.0.68.dist-info → plexus_python_common-1.0.70.dist-info}/METADATA +1 -1
- {plexus_python_common-1.0.68.dist-info → plexus_python_common-1.0.70.dist-info}/RECORD +6 -6
- {plexus_python_common-1.0.68.dist-info → plexus_python_common-1.0.70.dist-info}/WHEEL +0 -0
- {plexus_python_common-1.0.68.dist-info → plexus_python_common-1.0.70.dist-info}/top_level.txt +0 -0
plexus/common/utils/ormutils.py
CHANGED
|
@@ -1092,12 +1092,12 @@ def db_read_sequence_models[SequenceModelT: SequenceModelMixin](
|
|
|
1092
1092
|
limit: int | None = None,
|
|
1093
1093
|
order_by: list[str] | None = None,
|
|
1094
1094
|
) -> list[SequenceModelT]:
|
|
1095
|
-
|
|
1095
|
+
query_stmt = db.query(model).order_by(*db_make_order_by_clause(model, order_by))
|
|
1096
1096
|
if skip is not None:
|
|
1097
|
-
|
|
1097
|
+
query_stmt = query_stmt.offset(skip)
|
|
1098
1098
|
if limit is not None:
|
|
1099
|
-
|
|
1100
|
-
return
|
|
1099
|
+
query_stmt = query_stmt.limit(limit)
|
|
1100
|
+
return query_stmt.all()
|
|
1101
1101
|
|
|
1102
1102
|
|
|
1103
1103
|
def db_update_sequence_model[SequenceModelT: SequenceModelMixin](
|
|
@@ -1285,7 +1285,7 @@ def db_read_latest_snapshot_models[SnapshotModelT: SnapshotModelMixin](
|
|
|
1285
1285
|
limit: int | None = None,
|
|
1286
1286
|
order_by: list[str] | None = None,
|
|
1287
1287
|
) -> list[SnapshotModelT]:
|
|
1288
|
-
|
|
1288
|
+
subquery_stmt = (
|
|
1289
1289
|
db
|
|
1290
1290
|
.query(model.record_sqn,
|
|
1291
1291
|
sa.func.max(model.created_at).label("max_created_at"))
|
|
@@ -1293,18 +1293,19 @@ def db_read_latest_snapshot_models[SnapshotModelT: SnapshotModelMixin](
|
|
|
1293
1293
|
.subquery()
|
|
1294
1294
|
)
|
|
1295
1295
|
|
|
1296
|
-
|
|
1296
|
+
query_stmt = (
|
|
1297
1297
|
db
|
|
1298
1298
|
.query(model)
|
|
1299
|
-
.join(
|
|
1300
|
-
sa.and_(model.record_sqn ==
|
|
1299
|
+
.join(subquery_stmt,
|
|
1300
|
+
sa.and_(model.record_sqn == subquery_stmt.c.record_sqn,
|
|
1301
|
+
model.created_at == subquery_stmt.c.max_created_at))
|
|
1301
1302
|
.order_by(*db_make_order_by_clause(model, order_by))
|
|
1302
1303
|
)
|
|
1303
1304
|
if skip is not None:
|
|
1304
|
-
|
|
1305
|
+
query_stmt = query_stmt.offset(skip)
|
|
1305
1306
|
if limit is not None:
|
|
1306
|
-
|
|
1307
|
-
return
|
|
1307
|
+
query_stmt = query_stmt.limit(limit)
|
|
1308
|
+
return query_stmt.all()
|
|
1308
1309
|
|
|
1309
1310
|
|
|
1310
1311
|
def db_read_active_snapshot_models[SnapshotModelT: SnapshotModelMixin](
|
|
@@ -1314,12 +1315,12 @@ def db_read_active_snapshot_models[SnapshotModelT: SnapshotModelMixin](
|
|
|
1314
1315
|
limit: int | None = None,
|
|
1315
1316
|
order_by: list[str] | None = None,
|
|
1316
1317
|
) -> list[SnapshotModelT]:
|
|
1317
|
-
|
|
1318
|
+
query_stmt = db.query(model).where(model.expired_at.is_(None)).order_by(*db_make_order_by_clause(model, order_by))
|
|
1318
1319
|
if skip is not None:
|
|
1319
|
-
|
|
1320
|
+
query_stmt = query_stmt.offset(skip)
|
|
1320
1321
|
if limit is not None:
|
|
1321
|
-
|
|
1322
|
-
return
|
|
1322
|
+
query_stmt = query_stmt.limit(limit)
|
|
1323
|
+
return query_stmt.all()
|
|
1323
1324
|
|
|
1324
1325
|
|
|
1325
1326
|
def db_update_snapshot_model[SnapshotModelT: SnapshotModelMixin](
|
|
@@ -1512,7 +1513,7 @@ def db_read_latest_revision_models[RevisionModelT: RevisionModelMixin](
|
|
|
1512
1513
|
limit: int | None = None,
|
|
1513
1514
|
order_by: list[str] | None = None,
|
|
1514
1515
|
) -> list[RevisionModelT]:
|
|
1515
|
-
|
|
1516
|
+
subquery_stmt = (
|
|
1516
1517
|
db
|
|
1517
1518
|
.query(model.record_sqn,
|
|
1518
1519
|
sa.func.max(model.revision).label("max_revision"))
|
|
@@ -1520,18 +1521,19 @@ def db_read_latest_revision_models[RevisionModelT: RevisionModelMixin](
|
|
|
1520
1521
|
.subquery()
|
|
1521
1522
|
)
|
|
1522
1523
|
|
|
1523
|
-
|
|
1524
|
+
query_stmt = (
|
|
1524
1525
|
db
|
|
1525
1526
|
.query(model)
|
|
1526
|
-
.join(
|
|
1527
|
-
sa.and_(model.record_sqn ==
|
|
1527
|
+
.join(subquery_stmt,
|
|
1528
|
+
sa.and_(model.record_sqn == subquery_stmt.c.record_sqn,
|
|
1529
|
+
model.revision == subquery_stmt.c.max_revision))
|
|
1528
1530
|
.order_by(*db_make_order_by_clause(model, order_by))
|
|
1529
1531
|
)
|
|
1530
1532
|
if skip is not None:
|
|
1531
|
-
|
|
1533
|
+
query_stmt = query_stmt.offset(skip)
|
|
1532
1534
|
if limit is not None:
|
|
1533
|
-
|
|
1534
|
-
return
|
|
1535
|
+
query_stmt = query_stmt.limit(limit)
|
|
1536
|
+
return query_stmt.all()
|
|
1535
1537
|
|
|
1536
1538
|
|
|
1537
1539
|
def db_read_active_revision_models[RevisionModelT: RevisionModelMixin](
|
|
@@ -1541,12 +1543,12 @@ def db_read_active_revision_models[RevisionModelT: RevisionModelMixin](
|
|
|
1541
1543
|
limit: int | None = None,
|
|
1542
1544
|
order_by: list[str] | None = None,
|
|
1543
1545
|
) -> list[RevisionModelT]:
|
|
1544
|
-
|
|
1546
|
+
query_stmt = db.query(model).where(model.expired_at.is_(None)).order_by(*db_make_order_by_clause(model, order_by))
|
|
1545
1547
|
if skip is not None:
|
|
1546
|
-
|
|
1548
|
+
query_stmt = query_stmt.offset(skip)
|
|
1547
1549
|
if limit is not None:
|
|
1548
|
-
|
|
1549
|
-
return
|
|
1550
|
+
query_stmt = query_stmt.limit(limit)
|
|
1551
|
+
return query_stmt.all()
|
|
1550
1552
|
|
|
1551
1553
|
|
|
1552
1554
|
def db_update_revision_model[RevisionModelT: RevisionModelMixin](
|
plexus/common/utils/tagutils.py
CHANGED
|
@@ -394,15 +394,20 @@ def make_tag_target_model_mixin() -> type[pdt.BaseModel]:
|
|
|
394
394
|
)
|
|
395
395
|
vehicle_name: str = Field(
|
|
396
396
|
sa_column=sa.Column(sa_sqlite.VARCHAR(128), nullable=False),
|
|
397
|
-
description="
|
|
397
|
+
description="Name of the tagger's applicability vehicle",
|
|
398
398
|
)
|
|
399
399
|
begin_dt: datetime.datetime = Field(
|
|
400
400
|
sa_column=sa.Column(SQLiteDateTime, nullable=False),
|
|
401
|
-
description="
|
|
401
|
+
description="Beginning of the tagger's applicability time range",
|
|
402
402
|
)
|
|
403
403
|
end_dt: datetime.datetime = Field(
|
|
404
404
|
sa_column=sa.Column(SQLiteDateTime, nullable=False),
|
|
405
|
-
description="End
|
|
405
|
+
description="End of the tagger's applicability time range",
|
|
406
|
+
)
|
|
407
|
+
props: JsonType | None = Field(
|
|
408
|
+
sa_column=sa.Column(sa_sqlite.JSON, nullable=True),
|
|
409
|
+
default=None,
|
|
410
|
+
description="Additional properties of the tag target in JSON format",
|
|
406
411
|
)
|
|
407
412
|
|
|
408
413
|
@pdt.field_validator("identifier", mode="after")
|
|
@@ -414,7 +419,7 @@ def make_tag_target_model_mixin() -> type[pdt.BaseModel]:
|
|
|
414
419
|
@pdt.field_validator("tagger_name", mode="after")
|
|
415
420
|
@classmethod
|
|
416
421
|
def validate_tagger_name(cls, v: str) -> str:
|
|
417
|
-
|
|
422
|
+
validate_slash_tag(v)
|
|
418
423
|
return v
|
|
419
424
|
|
|
420
425
|
@pdt.field_validator("tagger_version", mode="after")
|
|
@@ -466,21 +471,21 @@ def make_tag_record_model_mixin() -> type[pdt.BaseModel]:
|
|
|
466
471
|
)
|
|
467
472
|
begin_dt: datetime.datetime = Field(
|
|
468
473
|
sa_column=sa.Column(SQLiteDateTime, nullable=False),
|
|
469
|
-
description="Begin
|
|
474
|
+
description="Begin of the tag record time range",
|
|
470
475
|
)
|
|
471
476
|
end_dt: datetime.datetime = Field(
|
|
472
477
|
sa_column=sa.Column(SQLiteDateTime, nullable=False),
|
|
473
|
-
description="End
|
|
478
|
+
description="End of the tag record time range",
|
|
474
479
|
)
|
|
475
480
|
tagset_namespace: str | None = Field(
|
|
476
481
|
sa_column=sa.Column(sa_sqlite.VARCHAR(64), nullable=True),
|
|
477
482
|
default=None,
|
|
478
|
-
description="Namespace of the tagset that the tag belongs to",
|
|
483
|
+
description="Namespace of the tagset that the tag in this record belongs to",
|
|
479
484
|
)
|
|
480
485
|
tagset_version: str | None = Field(
|
|
481
486
|
sa_column=sa.Column(sa_sqlite.VARCHAR(32), nullable=True),
|
|
482
487
|
default=None,
|
|
483
|
-
description="Version of the tagset that the tag belongs to",
|
|
488
|
+
description="Version of the tagset that the tag in this record belongs to",
|
|
484
489
|
)
|
|
485
490
|
tag: str = Field(
|
|
486
491
|
sa_column=sa.Column(sa_sqlite.VARCHAR(256), nullable=False),
|
|
@@ -573,6 +578,7 @@ if typing.TYPE_CHECKING:
|
|
|
573
578
|
vehicle_name: sa_orm.Mapped[str] = ...
|
|
574
579
|
begin_dt: sa_orm.Mapped[datetime.datetime] = ...
|
|
575
580
|
end_dt: sa_orm.Mapped[datetime.datetime] = ...
|
|
581
|
+
props: sa_orm.Mapped[JsonType | None] = ...
|
|
576
582
|
|
|
577
583
|
|
|
578
584
|
class TagTargetTable(TagTarget, SequenceModelMixinProtocol):
|
|
@@ -645,21 +651,21 @@ class TagCache(object):
|
|
|
645
651
|
end_dt: datetime.datetime | None = None,
|
|
646
652
|
) -> list[TagTargetTable]:
|
|
647
653
|
with self.make_session() as session:
|
|
648
|
-
|
|
654
|
+
query_stmt = session.query(TagTargetTable)
|
|
649
655
|
if identifier:
|
|
650
|
-
|
|
656
|
+
query_stmt = query_stmt.filter(TagTargetTable.identifier == identifier)
|
|
651
657
|
if tagger_name:
|
|
652
|
-
|
|
658
|
+
query_stmt = query_stmt.filter(TagTargetTable.tagger_name == tagger_name)
|
|
653
659
|
if tagger_version:
|
|
654
|
-
|
|
660
|
+
query_stmt = query_stmt.filter(TagTargetTable.tagger_version == tagger_version)
|
|
655
661
|
if vehicle_name:
|
|
656
|
-
|
|
662
|
+
query_stmt = query_stmt.filter(TagTargetTable.vehicle_name == vehicle_name)
|
|
657
663
|
if begin_dt:
|
|
658
|
-
|
|
664
|
+
query_stmt = query_stmt.filter(TagTargetTable.end_dt >= begin_dt)
|
|
659
665
|
if end_dt:
|
|
660
|
-
|
|
666
|
+
query_stmt = query_stmt.filter(TagTargetTable.begin_dt <= end_dt)
|
|
661
667
|
|
|
662
|
-
return
|
|
668
|
+
return query_stmt.all()
|
|
663
669
|
|
|
664
670
|
def add_target(
|
|
665
671
|
self,
|
|
@@ -669,18 +675,20 @@ class TagCache(object):
|
|
|
669
675
|
vehicle_name: str,
|
|
670
676
|
begin_dt: datetime.datetime,
|
|
671
677
|
end_dt: datetime.datetime,
|
|
678
|
+
props: JsonType | None = None,
|
|
672
679
|
) -> TagTargetTable:
|
|
673
680
|
with self.make_session() as session:
|
|
674
|
-
|
|
681
|
+
tag_target = TagTarget(
|
|
675
682
|
identifier=identifier,
|
|
676
683
|
tagger_name=tagger_name,
|
|
677
684
|
tagger_version=tagger_version,
|
|
678
685
|
vehicle_name=vehicle_name,
|
|
679
686
|
begin_dt=begin_dt,
|
|
680
687
|
end_dt=end_dt,
|
|
688
|
+
props=props,
|
|
681
689
|
)
|
|
682
|
-
|
|
683
|
-
session.add(
|
|
690
|
+
db_tag_target = clone_sequence_model_instance(TagTargetTable, tag_target)
|
|
691
|
+
session.add(db_tag_target)
|
|
684
692
|
session.commit()
|
|
685
693
|
|
|
686
694
|
return self.get_target(identifier)
|
|
@@ -695,21 +703,21 @@ class TagCache(object):
|
|
|
695
703
|
end_dt: datetime.datetime | None = None,
|
|
696
704
|
):
|
|
697
705
|
with self.make_session() as session:
|
|
698
|
-
|
|
706
|
+
query_stmt = session.query(TagTargetTable)
|
|
699
707
|
if identifier:
|
|
700
|
-
|
|
708
|
+
query_stmt = query_stmt.filter(TagTargetTable.identifier == identifier)
|
|
701
709
|
if tagger_name:
|
|
702
|
-
|
|
710
|
+
query_stmt = query_stmt.filter(TagTargetTable.tagger_name == tagger_name)
|
|
703
711
|
if tagger_version:
|
|
704
|
-
|
|
712
|
+
query_stmt = query_stmt.filter(TagTargetTable.tagger_version == tagger_version)
|
|
705
713
|
if vehicle_name:
|
|
706
|
-
|
|
714
|
+
query_stmt = query_stmt.filter(TagTargetTable.vehicle_name == vehicle_name)
|
|
707
715
|
if begin_dt:
|
|
708
|
-
|
|
716
|
+
query_stmt = query_stmt.filter(TagTargetTable.end_dt >= begin_dt)
|
|
709
717
|
if end_dt:
|
|
710
|
-
|
|
718
|
+
query_stmt = query_stmt.filter(TagTargetTable.begin_dt <= end_dt)
|
|
711
719
|
|
|
712
|
-
|
|
720
|
+
query_stmt.delete()
|
|
713
721
|
session.commit()
|
|
714
722
|
|
|
715
723
|
(
|
|
@@ -721,12 +729,16 @@ class TagCache(object):
|
|
|
721
729
|
session.commit()
|
|
722
730
|
|
|
723
731
|
def with_target(self, target: int | str) -> "TargetedTagCache":
|
|
724
|
-
|
|
725
|
-
if
|
|
726
|
-
raise ValueError(f"target '{target}' not found in cache")
|
|
727
|
-
return TargetedTagCache(cache=self,
|
|
732
|
+
db_tag_target = self.get_target(target)
|
|
733
|
+
if db_tag_target is None:
|
|
734
|
+
raise ValueError(f"tag target '{target}' not found in cache")
|
|
735
|
+
return TargetedTagCache(cache=self, tag_target=db_tag_target)
|
|
736
|
+
|
|
737
|
+
def count_records(self) -> int:
|
|
738
|
+
with self.make_session() as session:
|
|
739
|
+
return session.query(sa.func.count(TagRecordTable.sqn)).scalar()
|
|
728
740
|
|
|
729
|
-
def
|
|
741
|
+
def iter_records(
|
|
730
742
|
self,
|
|
731
743
|
begin_dt: datetime.datetime | None = None,
|
|
732
744
|
end_dt: datetime.datetime | None = None,
|
|
@@ -736,6 +748,8 @@ class TagCache(object):
|
|
|
736
748
|
*,
|
|
737
749
|
tagsets: Sequence[Tagset] | None = None,
|
|
738
750
|
tagset_inverted: bool = False,
|
|
751
|
+
skip: int | None = None,
|
|
752
|
+
limit: int | None = None,
|
|
739
753
|
batch_size: int = 1000,
|
|
740
754
|
) -> Generator[TagRecordTable, None, None]:
|
|
741
755
|
"""
|
|
@@ -749,33 +763,41 @@ class TagCache(object):
|
|
|
749
763
|
:param tagsets: Filter by tagsets (match tags that are in any of the specified tagsets)
|
|
750
764
|
:param tagset_inverted: Whether to invert the tagset filter (match tags that are NOT in any of the specified
|
|
751
765
|
tagsets)
|
|
766
|
+
:param skip: Number of records to skip (for pagination)
|
|
767
|
+
:param limit: Maximum number of records to return (for pagination)
|
|
752
768
|
:param batch_size: Number of records to fetch per batch from the database (for memory efficiency)
|
|
753
769
|
:return: Generator of ``TagRecordTable`` instances that match the filters
|
|
754
770
|
"""
|
|
755
771
|
with self.make_session() as session:
|
|
756
|
-
|
|
772
|
+
query_stmt = session.query(TagRecordTable)
|
|
757
773
|
if begin_dt:
|
|
758
|
-
|
|
774
|
+
query_stmt = query_stmt.filter(TagRecordTable.end_dt >= begin_dt)
|
|
759
775
|
if end_dt:
|
|
760
|
-
|
|
776
|
+
query_stmt = query_stmt.filter(TagRecordTable.begin_dt <= end_dt)
|
|
761
777
|
if tagset_namespace:
|
|
762
|
-
|
|
778
|
+
query_stmt = query_stmt.filter(TagRecordTable.tagset_namespace == tagset_namespace)
|
|
763
779
|
if tagset_version:
|
|
764
|
-
|
|
780
|
+
query_stmt = query_stmt.filter(TagRecordTable.tagset_version == tagset_version)
|
|
765
781
|
if tag_prefix:
|
|
766
|
-
|
|
782
|
+
query_stmt = query_stmt.filter(TagRecordTable.tag.like(f"{escape_sql_like(tag_prefix)}%", escape="\\"))
|
|
767
783
|
if tagsets:
|
|
768
784
|
if tagset_inverted:
|
|
769
|
-
|
|
785
|
+
query_stmt = query_stmt.filter(
|
|
770
786
|
TagRecordTable.tag.notin_([tag_name for tagset in tagsets for tag_name in tagset.tag_names]))
|
|
771
787
|
else:
|
|
772
|
-
|
|
788
|
+
query_stmt = query_stmt.filter(
|
|
773
789
|
TagRecordTable.tag.in_([tag_name for tagset in tagsets for tag_name in tagset.tag_names]))
|
|
774
|
-
|
|
775
|
-
|
|
790
|
+
if skip is not None or limit is not None:
|
|
791
|
+
query_stmt = query_stmt.order_by(TagRecordTable.sqn.desc())
|
|
792
|
+
if skip is not None:
|
|
793
|
+
query_stmt = query_stmt.offset(skip)
|
|
794
|
+
if limit is not None:
|
|
795
|
+
query_stmt = query_stmt.limit(limit)
|
|
796
|
+
|
|
797
|
+
for result in query_stmt.yield_per(batch_size):
|
|
776
798
|
yield result
|
|
777
799
|
|
|
778
|
-
def
|
|
800
|
+
def iter_record_and_targets(
|
|
779
801
|
self,
|
|
780
802
|
begin_dt: datetime.datetime | None = None,
|
|
781
803
|
end_dt: datetime.datetime | None = None,
|
|
@@ -791,10 +813,12 @@ class TagCache(object):
|
|
|
791
813
|
target_end_dt: datetime.datetime | None = None,
|
|
792
814
|
tagsets: Sequence[Tagset] | None = None,
|
|
793
815
|
tagset_inverted: bool = False,
|
|
816
|
+
skip: int | None = None,
|
|
817
|
+
limit: int | None = None,
|
|
794
818
|
batch_size: int = 1000,
|
|
795
819
|
) -> Generator[tuple[TagRecordTable, TagTargetTable], None, None]:
|
|
796
820
|
"""
|
|
797
|
-
Query tag records along with their target
|
|
821
|
+
Query tag records along with their target in the cache with optional filters.
|
|
798
822
|
|
|
799
823
|
:param begin_dt: Filter by begin time (inclusive)
|
|
800
824
|
:param end_dt: Filter by end time (inclusive)
|
|
@@ -810,49 +834,57 @@ class TagCache(object):
|
|
|
810
834
|
:param tagsets: Filter by tagsets (match tags that are in any of the specified tagsets)
|
|
811
835
|
:param tagset_inverted: Whether to invert the tagset filter (match tags that are NOT in any of the specified
|
|
812
836
|
tagsets)
|
|
837
|
+
:param skip: Number of records to skip (for pagination)
|
|
838
|
+
:param limit: Maximum number of records to return (for pagination)
|
|
813
839
|
:param batch_size: Number of records to fetch per batch from the database (for memory efficiency)
|
|
814
840
|
:return: Generator of ``TagRecordTable`` instances that match the filters
|
|
815
841
|
"""
|
|
816
842
|
with self.make_session() as session:
|
|
817
|
-
|
|
843
|
+
query_stmt = (
|
|
818
844
|
session
|
|
819
845
|
.query(TagRecordTable, TagTargetTable)
|
|
820
846
|
.join(TagTargetTable, TagRecordTable.target_sqn == TagTargetTable.sqn)
|
|
821
847
|
)
|
|
822
848
|
if begin_dt:
|
|
823
|
-
|
|
849
|
+
query_stmt = query_stmt.filter(TagRecordTable.end_dt >= begin_dt)
|
|
824
850
|
if end_dt:
|
|
825
|
-
|
|
851
|
+
query_stmt = query_stmt.filter(TagRecordTable.begin_dt <= end_dt)
|
|
826
852
|
if tagset_namespace:
|
|
827
|
-
|
|
853
|
+
query_stmt = query_stmt.filter(TagRecordTable.tagset_namespace == tagset_namespace)
|
|
828
854
|
if tagset_version:
|
|
829
|
-
|
|
855
|
+
query_stmt = query_stmt.filter(TagRecordTable.tagset_version == tagset_version)
|
|
830
856
|
if tag_prefix:
|
|
831
|
-
|
|
857
|
+
query_stmt = query_stmt.filter(TagRecordTable.tag.like(f"{escape_sql_like(tag_prefix)}%", escape="\\"))
|
|
832
858
|
if target_identifier:
|
|
833
|
-
|
|
859
|
+
query_stmt = query_stmt.filter(TagTargetTable.identifier == target_identifier)
|
|
834
860
|
if target_tagger_name:
|
|
835
|
-
|
|
861
|
+
query_stmt = query_stmt.filter(TagTargetTable.tagger_name == target_tagger_name)
|
|
836
862
|
if target_tagger_version:
|
|
837
|
-
|
|
863
|
+
query_stmt = query_stmt.filter(TagTargetTable.tagger_version == target_tagger_version)
|
|
838
864
|
if target_vehicle_name:
|
|
839
|
-
|
|
865
|
+
query_stmt = query_stmt.filter(TagTargetTable.vehicle_name == target_vehicle_name)
|
|
840
866
|
if target_begin_dt:
|
|
841
|
-
|
|
867
|
+
query_stmt = query_stmt.filter(TagTargetTable.end_dt >= target_begin_dt)
|
|
842
868
|
if target_end_dt:
|
|
843
|
-
|
|
869
|
+
query_stmt = query_stmt.filter(TagTargetTable.begin_dt <= target_end_dt)
|
|
844
870
|
if tagsets:
|
|
845
871
|
if tagset_inverted:
|
|
846
|
-
|
|
872
|
+
query_stmt = query_stmt.filter(
|
|
847
873
|
TagRecordTable.tag.notin_([tag_name for tagset in tagsets for tag_name in tagset.tag_names]))
|
|
848
874
|
else:
|
|
849
|
-
|
|
875
|
+
query_stmt = query_stmt.filter(
|
|
850
876
|
TagRecordTable.tag.in_([tag_name for tagset in tagsets for tag_name in tagset.tag_names]))
|
|
851
|
-
|
|
852
|
-
|
|
877
|
+
if skip is not None or limit is not None:
|
|
878
|
+
query_stmt = query_stmt.order_by(TagRecordTable.sqn.desc())
|
|
879
|
+
if skip is not None:
|
|
880
|
+
query_stmt = query_stmt.offset(skip)
|
|
881
|
+
if limit is not None:
|
|
882
|
+
query_stmt = query_stmt.limit(limit)
|
|
883
|
+
|
|
884
|
+
for result in query_stmt.yield_per(batch_size):
|
|
853
885
|
yield result
|
|
854
886
|
|
|
855
|
-
def
|
|
887
|
+
def remove_records(
|
|
856
888
|
self,
|
|
857
889
|
begin_dt: datetime.datetime | None = None,
|
|
858
890
|
end_dt: datetime.datetime | None = None,
|
|
@@ -876,26 +908,26 @@ class TagCache(object):
|
|
|
876
908
|
tagsets)
|
|
877
909
|
"""
|
|
878
910
|
with self.make_session() as session:
|
|
879
|
-
|
|
911
|
+
query_stmt = session.query(TagRecordTable)
|
|
880
912
|
if begin_dt:
|
|
881
|
-
|
|
913
|
+
query_stmt = query_stmt.filter(TagRecordTable.end_dt >= begin_dt)
|
|
882
914
|
if end_dt:
|
|
883
|
-
|
|
915
|
+
query_stmt = query_stmt.filter(TagRecordTable.begin_dt <= end_dt)
|
|
884
916
|
if tagset_namespace:
|
|
885
|
-
|
|
917
|
+
query_stmt = query_stmt.filter(TagRecordTable.tagset_namespace == tagset_namespace)
|
|
886
918
|
if tagset_version:
|
|
887
|
-
|
|
919
|
+
query_stmt = query_stmt.filter(TagRecordTable.tagset_version == tagset_version)
|
|
888
920
|
if tag_prefix:
|
|
889
|
-
|
|
921
|
+
query_stmt = query_stmt.filter(TagRecordTable.tag.like(f"{escape_sql_like(tag_prefix)}%", escape="\\"))
|
|
890
922
|
if tagsets:
|
|
891
923
|
if tagset_inverted:
|
|
892
|
-
|
|
924
|
+
query_stmt = query_stmt.filter(
|
|
893
925
|
TagRecordTable.tag.notin_([tag_name for tagset in tagsets for tag_name in tagset.tag_names]))
|
|
894
926
|
else:
|
|
895
|
-
|
|
927
|
+
query_stmt = query_stmt.filter(
|
|
896
928
|
TagRecordTable.tag.in_([tag_name for tagset in tagsets for tag_name in tagset.tag_names]))
|
|
897
929
|
|
|
898
|
-
|
|
930
|
+
query_stmt.delete()
|
|
899
931
|
session.commit()
|
|
900
932
|
|
|
901
933
|
def clear(self):
|
|
@@ -924,42 +956,59 @@ class TagCache(object):
|
|
|
924
956
|
return
|
|
925
957
|
|
|
926
958
|
with src.make_session() as src_session, dst.make_session() as dst_session:
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
clone_sequence_model_instance(TagTargetTable,
|
|
930
|
-
for
|
|
959
|
+
src_db_tag_targets = src_session.query(TagTargetTable).all()
|
|
960
|
+
dst_db_tag_targets = [
|
|
961
|
+
clone_sequence_model_instance(TagTargetTable, db_tag_target, clear_meta_fields=True)
|
|
962
|
+
for db_tag_target in src_db_tag_targets
|
|
931
963
|
]
|
|
932
|
-
dst_session.add_all(
|
|
964
|
+
dst_session.add_all(dst_db_tag_targets)
|
|
933
965
|
dst_session.flush() # ensure new sqn values are assigned
|
|
934
966
|
|
|
935
|
-
sqn_map = {
|
|
967
|
+
sqn_map = {src_db_tag_target.sqn: dst_db_tag_target.sqn
|
|
968
|
+
for src_db_tag_target, dst_db_tag_target in zip(src_db_tag_targets, dst_db_tag_targets)}
|
|
936
969
|
|
|
937
|
-
for
|
|
938
|
-
|
|
939
|
-
for db_tag_record in
|
|
940
|
-
|
|
970
|
+
for db_tag_records in batched(src_session.query(TagRecordTable).yield_per(1000), 1000):
|
|
971
|
+
cloned_db_tag_records = []
|
|
972
|
+
for db_tag_record in db_tag_records:
|
|
973
|
+
cloned_db_tag_record = clone_sequence_model_instance(TagRecordTable,
|
|
974
|
+
db_tag_record,
|
|
975
|
+
clear_meta_fields=True)
|
|
941
976
|
try:
|
|
942
|
-
|
|
977
|
+
cloned_db_tag_record.target_sqn = sqn_map[db_tag_record.target_sqn]
|
|
943
978
|
except KeyError as e:
|
|
944
|
-
raise ValueError(f"no cloned target for target_sqn '{db_tag_record.target_sqn}'") from e
|
|
945
|
-
|
|
946
|
-
dst_session.add_all(
|
|
979
|
+
raise ValueError(f"no cloned tag target for target_sqn '{db_tag_record.target_sqn}'") from e
|
|
980
|
+
cloned_db_tag_records.append(cloned_db_tag_record)
|
|
981
|
+
dst_session.add_all(cloned_db_tag_records)
|
|
947
982
|
dst_session.commit()
|
|
948
983
|
|
|
984
|
+
count_tags = count_records
|
|
985
|
+
iter_tags = iter_records
|
|
986
|
+
iter_tag_and_targets = iter_record_and_targets
|
|
987
|
+
remove_tags = remove_records
|
|
988
|
+
|
|
949
989
|
|
|
950
990
|
class TargetedTagCache(object):
|
|
951
|
-
def __init__(self, cache: TagCache,
|
|
952
|
-
self.target_info = target_info
|
|
991
|
+
def __init__(self, cache: TagCache, tag_target: TagTargetTable):
|
|
953
992
|
self.cache = cache
|
|
993
|
+
self.tag_target = tag_target
|
|
954
994
|
|
|
955
995
|
@contextlib.contextmanager
|
|
956
996
|
def make_session(self) -> Generator[sa_orm.Session, None, None]:
|
|
957
997
|
with self.cache.make_session() as session:
|
|
958
|
-
if not session.query(TagTargetTable).filter(TagTargetTable.sqn == self.
|
|
959
|
-
raise ValueError(f"target
|
|
998
|
+
if not session.query(TagTargetTable).filter(TagTargetTable.sqn == self.tag_target.sqn).first():
|
|
999
|
+
raise ValueError(f"tag target with sqn '{self.tag_target.sqn}' is no longer present in cache")
|
|
960
1000
|
yield session
|
|
961
1001
|
|
|
962
|
-
def
|
|
1002
|
+
def count_records(self) -> int:
|
|
1003
|
+
with self.make_session() as session:
|
|
1004
|
+
return (
|
|
1005
|
+
session
|
|
1006
|
+
.query(sa.func.count(TagRecordTable.sqn))
|
|
1007
|
+
.filter(TagRecordTable.target_sqn == self.tag_target.sqn)
|
|
1008
|
+
.scalar()
|
|
1009
|
+
)
|
|
1010
|
+
|
|
1011
|
+
def iter_records(
|
|
963
1012
|
self,
|
|
964
1013
|
begin_dt: datetime.datetime | None = None,
|
|
965
1014
|
end_dt: datetime.datetime | None = None,
|
|
@@ -969,6 +1018,8 @@ class TargetedTagCache(object):
|
|
|
969
1018
|
*,
|
|
970
1019
|
tagsets: Sequence[Tagset] | None = None,
|
|
971
1020
|
tagset_inverted: bool = False,
|
|
1021
|
+
skip: int | None = None,
|
|
1022
|
+
limit: int | None = None,
|
|
972
1023
|
batch_size: int = 1000,
|
|
973
1024
|
) -> Generator[TagRecordTable, None, None]:
|
|
974
1025
|
"""
|
|
@@ -982,34 +1033,42 @@ class TargetedTagCache(object):
|
|
|
982
1033
|
:param tagsets: Filter by tagsets (match tags that are in any of the specified tagsets)
|
|
983
1034
|
:param tagset_inverted: Whether to invert the tagset filter (match tags that are NOT in any of the specified
|
|
984
1035
|
tagsets)
|
|
1036
|
+
:param skip: Number of records to skip (for pagination)
|
|
1037
|
+
:param limit: Maximum number of records to return (for pagination)
|
|
985
1038
|
:param batch_size: Number of records to fetch per batch from the database (for memory efficiency)
|
|
986
1039
|
:return: Generator of ``TagRecordTable`` instances that match the filters
|
|
987
1040
|
"""
|
|
988
1041
|
|
|
989
1042
|
with self.make_session() as session:
|
|
990
|
-
|
|
1043
|
+
query_stmt = session.query(TagRecordTable).filter(TagRecordTable.target_sqn == self.tag_target.sqn)
|
|
991
1044
|
if begin_dt:
|
|
992
|
-
|
|
1045
|
+
query_stmt = query_stmt.filter(TagRecordTable.end_dt >= begin_dt)
|
|
993
1046
|
if end_dt:
|
|
994
|
-
|
|
1047
|
+
query_stmt = query_stmt.filter(TagRecordTable.begin_dt <= end_dt)
|
|
995
1048
|
if tagset_namespace:
|
|
996
|
-
|
|
1049
|
+
query_stmt = query_stmt.filter(TagRecordTable.tagset_namespace == tagset_namespace)
|
|
997
1050
|
if tagset_version:
|
|
998
|
-
|
|
1051
|
+
query_stmt = query_stmt.filter(TagRecordTable.tagset_version == tagset_version)
|
|
999
1052
|
if tag_prefix:
|
|
1000
|
-
|
|
1053
|
+
query_stmt = query_stmt.filter(TagRecordTable.tag.like(f"{escape_sql_like(tag_prefix)}%", escape="\\"))
|
|
1001
1054
|
if tagsets:
|
|
1002
1055
|
if tagset_inverted:
|
|
1003
|
-
|
|
1056
|
+
query_stmt = query_stmt.filter(
|
|
1004
1057
|
TagRecordTable.tag.notin_([tag_name for tagset in tagsets for tag_name in tagset.tag_names]))
|
|
1005
1058
|
else:
|
|
1006
|
-
|
|
1059
|
+
query_stmt = query_stmt.filter(
|
|
1007
1060
|
TagRecordTable.tag.in_([tag_name for tagset in tagsets for tag_name in tagset.tag_names]))
|
|
1008
|
-
|
|
1009
|
-
|
|
1061
|
+
if skip is not None or limit is not None:
|
|
1062
|
+
query_stmt = query_stmt.order_by(TagRecordTable.sqn.desc())
|
|
1063
|
+
if skip is not None:
|
|
1064
|
+
query_stmt = query_stmt.offset(skip)
|
|
1065
|
+
if limit is not None:
|
|
1066
|
+
query_stmt = query_stmt.limit(limit)
|
|
1067
|
+
|
|
1068
|
+
for result in query_stmt.yield_per(batch_size):
|
|
1010
1069
|
yield result
|
|
1011
1070
|
|
|
1012
|
-
def
|
|
1071
|
+
def add_ranged_record(
|
|
1013
1072
|
self,
|
|
1014
1073
|
begin_dt: datetime.datetime | None,
|
|
1015
1074
|
end_dt: datetime.datetime | None,
|
|
@@ -1036,9 +1095,9 @@ class TargetedTagCache(object):
|
|
|
1036
1095
|
"""
|
|
1037
1096
|
with self.make_session() as session:
|
|
1038
1097
|
tag_record = TagRecord(
|
|
1039
|
-
target_sqn=self.
|
|
1040
|
-
begin_dt=begin_dt or self.
|
|
1041
|
-
end_dt=end_dt or self.
|
|
1098
|
+
target_sqn=self.tag_target.sqn,
|
|
1099
|
+
begin_dt=begin_dt or self.tag_target.begin_dt,
|
|
1100
|
+
end_dt=end_dt or self.tag_target.end_dt,
|
|
1042
1101
|
tagset_namespace=tag.namespace if isinstance(tag, BoundTag) else tagset_namespace,
|
|
1043
1102
|
tagset_version=tag.version if isinstance(tag, BoundTag) else tagset_version,
|
|
1044
1103
|
tag=tag.name if isinstance(tag, Tag) else tag,
|
|
@@ -1050,7 +1109,7 @@ class TargetedTagCache(object):
|
|
|
1050
1109
|
|
|
1051
1110
|
return chainable(self, db_tag_record)
|
|
1052
1111
|
|
|
1053
|
-
def
|
|
1112
|
+
def add_record(
|
|
1054
1113
|
self,
|
|
1055
1114
|
tag: str | Tag | BoundTag,
|
|
1056
1115
|
props: JsonType | None = None,
|
|
@@ -1071,16 +1130,16 @@ class TargetedTagCache(object):
|
|
|
1071
1130
|
will be used.
|
|
1072
1131
|
:return: Self instance for chaining
|
|
1073
1132
|
"""
|
|
1074
|
-
return self.
|
|
1075
|
-
begin_dt=self.
|
|
1076
|
-
end_dt=self.
|
|
1133
|
+
return self.add_ranged_record(
|
|
1134
|
+
begin_dt=self.tag_target.begin_dt,
|
|
1135
|
+
end_dt=self.tag_target.end_dt,
|
|
1077
1136
|
tag=tag,
|
|
1078
1137
|
tagset_namespace=tagset_namespace,
|
|
1079
1138
|
tagset_version=tagset_version,
|
|
1080
1139
|
props=props,
|
|
1081
1140
|
)
|
|
1082
1141
|
|
|
1083
|
-
def
|
|
1142
|
+
def update_record(
|
|
1084
1143
|
self,
|
|
1085
1144
|
sqn: int,
|
|
1086
1145
|
*,
|
|
@@ -1134,7 +1193,7 @@ class TargetedTagCache(object):
|
|
|
1134
1193
|
|
|
1135
1194
|
return chainable(self, db_tag_record)
|
|
1136
1195
|
|
|
1137
|
-
def
|
|
1196
|
+
def remove_records(
|
|
1138
1197
|
self,
|
|
1139
1198
|
begin_dt: datetime.datetime | None = None,
|
|
1140
1199
|
end_dt: datetime.datetime | None = None,
|
|
@@ -1159,30 +1218,37 @@ class TargetedTagCache(object):
|
|
|
1159
1218
|
:return: Self instance for chaining
|
|
1160
1219
|
"""
|
|
1161
1220
|
with self.make_session() as session:
|
|
1162
|
-
|
|
1221
|
+
query_stmt = session.query(TagRecordTable).filter(TagRecordTable.target_sqn == self.tag_target.sqn)
|
|
1163
1222
|
if begin_dt:
|
|
1164
|
-
|
|
1223
|
+
query_stmt = query_stmt.filter(TagRecordTable.end_dt >= begin_dt)
|
|
1165
1224
|
if end_dt:
|
|
1166
|
-
|
|
1225
|
+
query_stmt = query_stmt.filter(TagRecordTable.begin_dt <= end_dt)
|
|
1167
1226
|
if tagset_namespace:
|
|
1168
|
-
|
|
1227
|
+
query_stmt = query_stmt.filter(TagRecordTable.tagset_namespace == tagset_namespace)
|
|
1169
1228
|
if tagset_version:
|
|
1170
|
-
|
|
1229
|
+
query_stmt = query_stmt.filter(TagRecordTable.tagset_version == tagset_version)
|
|
1171
1230
|
if tag_prefix:
|
|
1172
|
-
|
|
1231
|
+
query_stmt = query_stmt.filter(TagRecordTable.tag.like(f"{escape_sql_like(tag_prefix)}%", escape="\\"))
|
|
1173
1232
|
if tagsets:
|
|
1174
1233
|
if tagset_inverted:
|
|
1175
|
-
|
|
1234
|
+
query_stmt = query_stmt.filter(
|
|
1176
1235
|
TagRecordTable.tag.notin_([tag_name for tagset in tagsets for tag_name in tagset.tag_names]))
|
|
1177
1236
|
else:
|
|
1178
|
-
|
|
1237
|
+
query_stmt = query_stmt.filter(
|
|
1179
1238
|
TagRecordTable.tag.in_([tag_name for tagset in tagsets for tag_name in tagset.tag_names]))
|
|
1180
1239
|
|
|
1181
|
-
|
|
1240
|
+
query_stmt.delete()
|
|
1182
1241
|
session.commit()
|
|
1183
1242
|
|
|
1184
1243
|
return self
|
|
1185
1244
|
|
|
1245
|
+
count_tags = count_records
|
|
1246
|
+
iter_tags = iter_records
|
|
1247
|
+
add_ranged_tag = add_ranged_record
|
|
1248
|
+
add_tag = add_record
|
|
1249
|
+
update_tag = update_record
|
|
1250
|
+
remove_tags = remove_records
|
|
1251
|
+
|
|
1186
1252
|
|
|
1187
1253
|
@memorized
|
|
1188
1254
|
def tag_cache(*, identifier: str | None = None, file_path: str | os.PathLike[str] | None = None) -> TagCache:
|
|
@@ -16,14 +16,14 @@ plexus/common/utils/datautils.py,sha256=mgnr-dcHpw-Pk3qBud0lC3JX_pv-iKzI8llsPW9Q
|
|
|
16
16
|
plexus/common/utils/dockerutils.py,sha256=WPxQuabRWyyM8wpSSYhb_HZaOw5yZ2TbU2dEQ2xRIlQ,5787
|
|
17
17
|
plexus/common/utils/gisutils.py,sha256=UR3uVoD1nAy0SWJ1AYWCUy94Lo8zNb4nv_JdpcANBDE,11462
|
|
18
18
|
plexus/common/utils/jsonutils.py,sha256=-_uKlQMLMgmVO9pB99S45Y_Vufx5dFSq43DIwGz1a54,3328
|
|
19
|
-
plexus/common/utils/ormutils.py,sha256=
|
|
19
|
+
plexus/common/utils/ormutils.py,sha256=bAJDSp-53406E5iySueh09yQUs0OuCshygRSzU9aaW0,60667
|
|
20
20
|
plexus/common/utils/pathutils.py,sha256=hGJqSLj08tuOeZ7WeC5d4BtjnPI732BuntVQBQsqOaI,9581
|
|
21
21
|
plexus/common/utils/s3utils.py,sha256=zlO4kGs-c2gUeOfPfiKIE5liQZsbYxqAZYCwA8kL0Lo,36017
|
|
22
22
|
plexus/common/utils/sqlutils.py,sha256=D6kTBjhO5YlNRt3uFlPt6z3uH61m9ajEzPYmsI6NoFc,231
|
|
23
23
|
plexus/common/utils/strutils.py,sha256=O9Inv4ffUTf6Xjc5ftoZwbIua1NeG7itCT9S3zjZxBc,16436
|
|
24
|
-
plexus/common/utils/tagutils.py,sha256=
|
|
24
|
+
plexus/common/utils/tagutils.py,sha256=F1t62lxNCskirUQ9sIs5Q7hVWAF71f5Hs1aQ3Sj0X4w,55759
|
|
25
25
|
plexus/common/utils/testutils.py,sha256=N8ijLu7X-hlQlHzvv0TtSsQpIF4T1hbr-AjkILoV2Ac,6152
|
|
26
|
-
plexus_python_common-1.0.
|
|
27
|
-
plexus_python_common-1.0.
|
|
28
|
-
plexus_python_common-1.0.
|
|
29
|
-
plexus_python_common-1.0.
|
|
26
|
+
plexus_python_common-1.0.70.dist-info/METADATA,sha256=ZZjSJxN2hxIf9b9wmR0HqftEGdvADSZuf3KNBX3ad1g,1481
|
|
27
|
+
plexus_python_common-1.0.70.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
28
|
+
plexus_python_common-1.0.70.dist-info/top_level.txt,sha256=ug_g7CVwaMQuas5UzAXbHUrQvKGCn8ezc6ZNvvRlJOE,7
|
|
29
|
+
plexus_python_common-1.0.70.dist-info/RECORD,,
|
|
File without changes
|
{plexus_python_common-1.0.68.dist-info → plexus_python_common-1.0.70.dist-info}/top_level.txt
RENAMED
|
File without changes
|