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_CHECKING,
31)
33import sqlalchemy
35from ._base import (
36 CollectionTablesTuple,
37 DefaultCollectionManager,
38 makeRunTableSpec,
39 makeCollectionChainTableSpec,
40)
41from ...core import ddl
42from ..interfaces import CollectionRecord
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 Database, StaticTablesContext
48_TABLES_SPEC = CollectionTablesTuple(
49 collection=ddl.TableSpec(
50 fields=[
51 ddl.FieldSpec("collection_id", dtype=sqlalchemy.BigInteger, primaryKey=True, autoincrement=True),
52 ddl.FieldSpec("name", dtype=sqlalchemy.String, length=64, nullable=False),
53 ddl.FieldSpec("type", dtype=sqlalchemy.SmallInteger, nullable=False),
54 ],
55 unique=[("name",)],
56 ),
57 run=makeRunTableSpec("collection_id", sqlalchemy.BigInteger),
58 collection_chain=makeCollectionChainTableSpec("collection_id", sqlalchemy.BigInteger),
59)
62class SynthIntKeyCollectionManager(DefaultCollectionManager):
63 """A `CollectionManager` implementation that uses synthetic primary key
64 (auto-incremented integer) for collections table.
66 Most of the logic, including caching policy, is implemented in the base
67 class, this class only adds customisations specific to this particular
68 table schema.
70 Parameters
71 ----------
72 db : `Database`
73 Interface to the underlying database engine and namespace.
74 tables : `NamedTuple`
75 Named tuple of SQLAlchemy table objects.
76 collectionIdName : `str`
77 Name of the column in collections table that identifies it (PK).
78 """
79 def __init__(self, db: Database, tables: CollectionTablesTuple, collectionIdName: str):
80 super().__init__(db=db, tables=tables, collectionIdName=collectionIdName)
81 self._nameCache: Dict[str, CollectionRecord] = {} # indexed by collection name
83 @classmethod
84 def initialize(cls, db: Database, context: StaticTablesContext) -> SynthIntKeyCollectionManager:
85 # Docstring inherited from CollectionManager.
86 return cls(db, tables=context.addTableTuple(_TABLES_SPEC), # type: ignore
87 collectionIdName="collection_id")
89 @classmethod
90 def getCollectionForeignKeyName(cls, prefix: str = "collection") -> str:
91 # Docstring inherited from CollectionManager.
92 return f"{prefix}_id"
94 @classmethod
95 def getRunForeignKeyName(cls, prefix: str = "run") -> str:
96 # Docstring inherited from CollectionManager.
97 return f"{prefix}_id"
99 @classmethod
100 def addCollectionForeignKey(cls, tableSpec: ddl.TableSpec, *, prefix: str = "collection",
101 onDelete: Optional[str] = None, **kwds: Any) -> ddl.FieldSpec:
102 # Docstring inherited from CollectionManager.
103 original = _TABLES_SPEC.collection.fields["collection_id"]
104 copy = ddl.FieldSpec(cls.getCollectionForeignKeyName(prefix), dtype=original.dtype, **kwds)
105 tableSpec.fields.add(copy)
106 tableSpec.foreignKeys.append(ddl.ForeignKeySpec("collection", source=(copy.name,),
107 target=(original.name,), onDelete=onDelete))
108 return copy
110 @classmethod
111 def addRunForeignKey(cls, tableSpec: ddl.TableSpec, *, prefix: str = "run",
112 onDelete: Optional[str] = None, **kwds: Any) -> ddl.FieldSpec:
113 # Docstring inherited from CollectionManager.
114 original = _TABLES_SPEC.run.fields["collection_id"]
115 copy = ddl.FieldSpec(cls.getRunForeignKeyName(prefix), dtype=original.dtype, **kwds)
116 tableSpec.fields.add(copy)
117 tableSpec.foreignKeys.append(ddl.ForeignKeySpec("run", source=(copy.name,),
118 target=(original.name,), onDelete=onDelete))
119 return copy
121 def _setRecordCache(self, records: Iterable[CollectionRecord]) -> None:
122 """Set internal record cache to contain given records,
123 old cached records will be removed.
124 """
125 self._records = {}
126 self._nameCache = {}
127 for record in records:
128 self._records[record.key] = record
129 self._nameCache[record.name] = record
131 def _addCachedRecord(self, record: CollectionRecord) -> None:
132 """Add single record to cache.
133 """
134 self._records[record.key] = record
135 self._nameCache[record.name] = record
137 def _removeCachedRecord(self, record: CollectionRecord) -> None:
138 """Remove single record from cache.
139 """
140 del self._records[record.key]
141 del self._nameCache[record.name]
143 def _getByName(self, name: str) -> Optional[CollectionRecord]:
144 # Docstring inherited from DefaultCollectionManager.
145 return self._nameCache.get(name)