Coverage for python/lsst/daf/butler/registry/collections/synthIntKey.py : 96%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This file is part of daf_butler.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
21from __future__ import annotations
23__all__ = ["SynthIntKeyCollectionManager"]
25from typing import (
26 Any,
27 Dict,
28 Iterable,
29 Optional,
30 Type,
31 TYPE_CHECKING,
32)
34import sqlalchemy
36from ._base import (
37 CollectionTablesTuple,
38 DefaultCollectionManager,
39 makeRunTableSpec,
40 makeCollectionChainTableSpec,
41)
42from ...core import DatabaseTimespanRepresentation, ddl
43from ..interfaces import CollectionRecord, VersionTuple
45if TYPE_CHECKING: 45 ↛ 46line 45 didn't jump to line 46, because the condition on line 45 was never true
46 from ..interfaces import Database, StaticTablesContext
49_KEY_FIELD_SPEC = ddl.FieldSpec("collection_id", dtype=sqlalchemy.BigInteger, primaryKey=True,
50 autoincrement=True)
53# This has to be updated on every schema change
54_VERSION = VersionTuple(0, 3, 0)
57def _makeTableSpecs(tsRepr: Type[DatabaseTimespanRepresentation]) -> CollectionTablesTuple:
58 return CollectionTablesTuple(
59 collection=ddl.TableSpec(
60 fields=[
61 _KEY_FIELD_SPEC,
62 ddl.FieldSpec("name", dtype=sqlalchemy.String, length=64, nullable=False),
63 ddl.FieldSpec("type", dtype=sqlalchemy.SmallInteger, nullable=False),
64 ],
65 unique=[("name",)],
66 ),
67 run=makeRunTableSpec("collection_id", sqlalchemy.BigInteger, tsRepr),
68 collection_chain=makeCollectionChainTableSpec("collection_id", sqlalchemy.BigInteger),
69 )
72class SynthIntKeyCollectionManager(DefaultCollectionManager):
73 """A `CollectionManager` implementation that uses synthetic primary key
74 (auto-incremented integer) for collections table.
76 Most of the logic, including caching policy, is implemented in the base
77 class, this class only adds customizations specific to this particular
78 table schema.
80 Parameters
81 ----------
82 db : `Database`
83 Interface to the underlying database engine and namespace.
84 tables : `NamedTuple`
85 Named tuple of SQLAlchemy table objects.
86 collectionIdName : `str`
87 Name of the column in collections table that identifies it (PK).
88 """
89 def __init__(self, db: Database, tables: CollectionTablesTuple, collectionIdName: str):
90 super().__init__(db=db, tables=tables, collectionIdName=collectionIdName)
91 self._nameCache: Dict[str, CollectionRecord] = {} # indexed by collection name
93 @classmethod
94 def initialize(cls, db: Database, context: StaticTablesContext) -> SynthIntKeyCollectionManager:
95 # Docstring inherited from CollectionManager.
96 return cls(
97 db,
98 tables=context.addTableTuple(_makeTableSpecs(db.getTimespanRepresentation())), # type: ignore
99 collectionIdName="collection_id"
100 )
102 @classmethod
103 def getCollectionForeignKeyName(cls, prefix: str = "collection") -> str:
104 # Docstring inherited from CollectionManager.
105 return f"{prefix}_id"
107 @classmethod
108 def getRunForeignKeyName(cls, prefix: str = "run") -> str:
109 # Docstring inherited from CollectionManager.
110 return f"{prefix}_id"
112 @classmethod
113 def addCollectionForeignKey(cls, tableSpec: ddl.TableSpec, *, prefix: str = "collection",
114 onDelete: Optional[str] = None,
115 constraint: bool = True,
116 **kwargs: Any) -> ddl.FieldSpec:
117 # Docstring inherited from CollectionManager.
118 original = _KEY_FIELD_SPEC
119 copy = ddl.FieldSpec(cls.getCollectionForeignKeyName(prefix), dtype=original.dtype,
120 autoincrement=False, **kwargs)
121 tableSpec.fields.add(copy)
122 if constraint: 122 ↛ 125line 122 didn't jump to line 125, because the condition on line 122 was never false
123 tableSpec.foreignKeys.append(ddl.ForeignKeySpec("collection", source=(copy.name,),
124 target=(original.name,), onDelete=onDelete))
125 return copy
127 @classmethod
128 def addRunForeignKey(cls, tableSpec: ddl.TableSpec, *, prefix: str = "run",
129 onDelete: Optional[str] = None,
130 constraint: bool = True,
131 **kwargs: Any) -> ddl.FieldSpec:
132 # Docstring inherited from CollectionManager.
133 original = _KEY_FIELD_SPEC
134 copy = ddl.FieldSpec(cls.getRunForeignKeyName(prefix), dtype=original.dtype,
135 autoincrement=False, **kwargs)
136 tableSpec.fields.add(copy)
137 if constraint:
138 tableSpec.foreignKeys.append(ddl.ForeignKeySpec("run", source=(copy.name,),
139 target=(original.name,), onDelete=onDelete))
140 return copy
142 def _setRecordCache(self, records: Iterable[CollectionRecord]) -> None:
143 """Set internal record cache to contain given records,
144 old cached records will be removed.
145 """
146 self._records = {}
147 self._nameCache = {}
148 for record in records:
149 self._records[record.key] = record
150 self._nameCache[record.name] = record
152 def _addCachedRecord(self, record: CollectionRecord) -> None:
153 """Add single record to cache.
154 """
155 self._records[record.key] = record
156 self._nameCache[record.name] = record
158 def _removeCachedRecord(self, record: CollectionRecord) -> None:
159 """Remove single record from cache.
160 """
161 del self._records[record.key]
162 del self._nameCache[record.name]
164 def _getByName(self, name: str) -> Optional[CollectionRecord]:
165 # Docstring inherited from DefaultCollectionManager.
166 return self._nameCache.get(name)
168 @classmethod
169 def currentVersion(cls) -> Optional[VersionTuple]:
170 # Docstring inherited from VersionedExtension.
171 return _VERSION
173 def schemaDigest(self) -> Optional[str]:
174 # Docstring inherited from VersionedExtension.
175 return self._defaultSchemaDigest(self._tables, self._db.dialect)