Coverage for python/lsst/daf/butler/registry/collections/nameKey.py: 94%
Shortcuts 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
Shortcuts 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__ = ["NameKeyCollectionManager"]
25from typing import (
26 Any,
27 Optional,
28 Type,
29 TYPE_CHECKING,
30)
32import sqlalchemy
34from ._base import (
35 CollectionTablesTuple,
36 DefaultCollectionManager,
37 makeRunTableSpec,
38 makeCollectionChainTableSpec,
39)
41from ...core import TimespanDatabaseRepresentation, ddl
42from ..interfaces import VersionTuple
44if TYPE_CHECKING: 44 ↛ 45line 44 didn't jump to line 45, because the condition on line 44 was never true
45 from ..interfaces import CollectionRecord, Database, DimensionRecordStorageManager, StaticTablesContext
48_KEY_FIELD_SPEC = ddl.FieldSpec("name", dtype=sqlalchemy.String, length=64, primaryKey=True)
51# This has to be updated on every schema change
52_VERSION = VersionTuple(2, 0, 0)
55def _makeTableSpecs(TimespanReprClass: Type[TimespanDatabaseRepresentation]) -> CollectionTablesTuple:
56 return CollectionTablesTuple(
57 collection=ddl.TableSpec(
58 fields=[
59 _KEY_FIELD_SPEC,
60 ddl.FieldSpec("type", dtype=sqlalchemy.SmallInteger, nullable=False),
61 ddl.FieldSpec("doc", dtype=sqlalchemy.Text, nullable=True),
62 ],
63 ),
64 run=makeRunTableSpec("name", sqlalchemy.String, TimespanReprClass),
65 collection_chain=makeCollectionChainTableSpec("name", sqlalchemy.String),
66 )
69class NameKeyCollectionManager(DefaultCollectionManager):
70 """A `CollectionManager` implementation that uses collection names for
71 primary/foreign keys and aggressively loads all collection/run records in
72 the database into memory.
74 Most of the logic, including caching policy, is implemented in the base
75 class, this class only adds customizations specific to this particular
76 table schema.
77 """
79 @classmethod
80 def initialize(
81 cls,
82 db: Database,
83 context: StaticTablesContext, *,
84 dimensions: DimensionRecordStorageManager,
85 ) -> NameKeyCollectionManager:
86 # Docstring inherited from CollectionManager.
87 return cls(
88 db,
89 tables=context.addTableTuple(_makeTableSpecs(db.getTimespanRepresentation())), # type: ignore
90 collectionIdName="name",
91 dimensions=dimensions,
92 )
94 @classmethod
95 def getCollectionForeignKeyName(cls, prefix: str = "collection") -> str:
96 # Docstring inherited from CollectionManager.
97 return f"{prefix}_name"
99 @classmethod
100 def getRunForeignKeyName(cls, prefix: str = "run") -> str:
101 # Docstring inherited from CollectionManager.
102 return f"{prefix}_name"
104 @classmethod
105 def addCollectionForeignKey(cls, tableSpec: ddl.TableSpec, *, prefix: str = "collection",
106 onDelete: Optional[str] = None,
107 constraint: bool = True,
108 **kwargs: Any) -> ddl.FieldSpec:
109 # Docstring inherited from CollectionManager.
110 original = _KEY_FIELD_SPEC
111 copy = ddl.FieldSpec(cls.getCollectionForeignKeyName(prefix), dtype=original.dtype,
112 length=original.length, **kwargs)
113 tableSpec.fields.add(copy)
114 if constraint: 114 ↛ 117line 114 didn't jump to line 117, because the condition on line 114 was never false
115 tableSpec.foreignKeys.append(ddl.ForeignKeySpec("collection", source=(copy.name,),
116 target=(original.name,), onDelete=onDelete))
117 return copy
119 @classmethod
120 def addRunForeignKey(cls, tableSpec: ddl.TableSpec, *, prefix: str = "run",
121 onDelete: Optional[str] = None,
122 constraint: bool = True,
123 **kwargs: Any) -> ddl.FieldSpec:
124 # Docstring inherited from CollectionManager.
125 original = _KEY_FIELD_SPEC
126 copy = ddl.FieldSpec(cls.getRunForeignKeyName(prefix), dtype=original.dtype,
127 length=original.length, **kwargs)
128 tableSpec.fields.add(copy)
129 if constraint:
130 tableSpec.foreignKeys.append(ddl.ForeignKeySpec("run", source=(copy.name,),
131 target=(original.name,), onDelete=onDelete))
132 return copy
134 def _getByName(self, name: str) -> Optional[CollectionRecord]:
135 # Docstring inherited from DefaultCollectionManager.
136 return self._records.get(name)
138 @classmethod
139 def currentVersion(cls) -> Optional[VersionTuple]:
140 # Docstring inherited from VersionedExtension.
141 return _VERSION
143 def schemaDigest(self) -> Optional[str]:
144 # Docstring inherited from VersionedExtension.
145 return self._defaultSchemaDigest(self._tables, self._db.dialect)