Hide keyboard shortcuts

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 

22"""Interfaces for the objects that manage opaque (logical) tables within a 

23`Registry`. 

24""" 

25 

26__all__ = ["OpaqueTableStorageManager", "OpaqueTableStorage"] 

27 

28from abc import ABC, abstractmethod 

29from typing import ( 

30 Any, 

31 Iterator, 

32 Optional, 

33) 

34 

35from ...core.ddl import TableSpec 

36from ._database import Database, StaticTablesContext 

37 

38 

39class OpaqueTableStorage(ABC): 

40 """An interface that manages the records associated with a particular 

41 opaque table in a `Registry`. 

42 

43 Parameters 

44 ---------- 

45 name : `str` 

46 Name of the opaque table. 

47 """ 

48 def __init__(self, name: str): 

49 self.name = name 

50 

51 @abstractmethod 

52 def insert(self, *data: dict) -> None: 

53 """Insert records into the table 

54 

55 Parameters 

56 ---------- 

57 *data 

58 Each additional positional argument is a dictionary that represents 

59 a single row to be added. 

60 """ 

61 raise NotImplementedError() 

62 

63 @abstractmethod 

64 def fetch(self, **where: Any) -> Iterator[dict]: 

65 """Retrieve records from an opaque table. 

66 

67 Parameters 

68 ---------- 

69 **where 

70 Additional keyword arguments are interpreted as equality 

71 constraints that restrict the returned rows (combined with AND); 

72 keyword arguments are column names and values are the values they 

73 must have. 

74 

75 Yields 

76 ------ 

77 row : `dict` 

78 A dictionary representing a single result row. 

79 """ 

80 raise NotImplementedError() 

81 

82 @abstractmethod 

83 def delete(self, **where: Any) -> None: 

84 """Remove records from an opaque table. 

85 

86 Parameters 

87 ---------- 

88 **where 

89 Additional keyword arguments are interpreted as equality 

90 constraints that restrict the deleted rows (combined with AND); 

91 keyword arguments are column names and values are the values they 

92 must have. 

93 """ 

94 raise NotImplementedError() 

95 

96 name: str 

97 """The name of the logical table this instance manages (`str`). 

98 """ 

99 

100 

101class OpaqueTableStorageManager(ABC): 

102 """An interface that manages the opaque tables in a `Registry`. 

103 

104 `OpaqueTableStorageManager` primarily serves as a container and factory for 

105 `OpaqueTableStorage` instances, which each provide access to the records 

106 for a different (logical) opaque table. 

107 

108 Notes 

109 ----- 

110 Opaque tables are primarily used by `Datastore` instances to manage their 

111 internal data in the same database that hold the `Registry`, but are not 

112 limited to this. 

113 

114 While an opaque table in a multi-layer `Registry` may in fact be the union 

115 of multiple tables in different layers, we expect this to be rare, as 

116 `Registry` layers will typically correspond to different leaf `Datastore` 

117 instances (each with their own opaque table) in a `ChainedDatastore`. 

118 """ 

119 

120 @classmethod 

121 @abstractmethod 

122 def initialize(cls, db: Database, context: StaticTablesContext) -> OpaqueTableStorageManager: 

123 """Construct an instance of the manager. 

124 

125 Parameters 

126 ---------- 

127 db : `Database` 

128 Interface to the underlying database engine and namespace. 

129 context : `StaticTablesContext` 

130 Context object obtained from `Database.declareStaticTables`; used 

131 to declare any tables that should always be present in a layer 

132 implemented with this manager. 

133 

134 Returns 

135 ------- 

136 manager : `OpaqueTableStorageManager` 

137 An instance of a concrete `OpaqueTableStorageManager` subclass. 

138 """ 

139 raise NotImplementedError() 

140 

141 def __getitem__(self, name: str) -> OpaqueTableStorage: 

142 """Interface to `get` that raises `LookupError` instead of returning 

143 `None` on failure. 

144 """ 

145 r = self.get(name) 

146 if r is None: 

147 raise LookupError(f"No logical table with name '{name}' found.") 

148 return r 

149 

150 @abstractmethod 

151 def get(self, name: str) -> Optional[OpaqueTableStorage]: 

152 """Return an object that provides access to the records associated with 

153 an opaque logical table. 

154 

155 Parameters 

156 ---------- 

157 name : `str` 

158 Name of the logical table. 

159 

160 Returns 

161 ------- 

162 records : `OpaqueTableStorage` or `None` 

163 The object representing the records for the given table in this 

164 layer, or `None` if there are no records for that table in this 

165 layer. 

166 

167 Notes 

168 ----- 

169 Opaque tables must be registered with the layer (see `register`) by 

170 the same client before they can safely be retrieved with `get`. 

171 Unlike most other manager classes, the set of opaque tables cannot be 

172 obtained from an existing data repository. 

173 """ 

174 raise NotImplementedError() 

175 

176 @abstractmethod 

177 def register(self, name: str, spec: TableSpec) -> OpaqueTableStorage: 

178 """Ensure that this layer can hold records for the given opaque logical 

179 table, creating new tables as necessary. 

180 

181 Parameters 

182 ---------- 

183 name : `str` 

184 Name of the logical table. 

185 spec : `TableSpec` 

186 Schema specification for the table to be created. 

187 

188 Returns 

189 ------- 

190 records : `OpaqueTableStorage` 

191 The object representing the records for the given element in this 

192 layer. 

193 

194 Notes 

195 ----- 

196 This operation may not be invoked within a transaction context block. 

197 """ 

198 raise NotImplementedError()