LSST Applications g0603fd7c41+d727c1d375,g124d44cf3d+604aa34adb,g180d380827+5ffeb7c294,g1afd7665f7+eb25d4c773,g2079a07aa2+86d27d4dc4,g2305ad1205+89e8e9cf63,g2bbee38e9b+44a02a0554,g337abbeb29+44a02a0554,g33d1c0ed96+44a02a0554,g3a166c0a6a+44a02a0554,g3d1719c13e+9a7b30876f,g487adcacf7+719c5abdea,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+85bc5ede60,g858d7b2824+9a7b30876f,g991b906543+9a7b30876f,g99cad8db69+8994cf29ec,g9b9dfce982+0fdee8fa3c,g9ddcbc5298+9a081db1e4,ga1e77700b3+03d07e1c1f,gb0e22166c9+60f28cb32d,gb23b769143+9a7b30876f,gb3a676b8dc+e2510deafe,gb4b16eec92+8df1cf93fe,gba4ed39666+c2a2e4ac27,gbb8dafda3b+7edb7fc777,gbd998247f1+585e252eca,gc120e1dc64+79b8551dca,gc28159a63d+44a02a0554,gc3e9b769f7+20d5ea8805,gcf0d15dbbd+0fdee8fa3c,gdaeeff99f8+f9a426f77a,ge79ae78c31+44a02a0554,gee10cc3b42+585e252eca,w.2024.19
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Protected Member Functions | Static Protected Member Functions | Protected Attributes | List of all members
lsst.dax.apdb.sql.modelToSql.ModelToSql Class Reference

Public Member Functions

 __init__ (self, sqlalchemy.schema.MetaData metadata, str prefix="")
 
Mapping[str, sqlalchemy.schema.Table] make_tables (self, Iterable[schema_model.Table] tables)
 

Protected Member Functions

list[sqlalchemy.schema.Column] _table_columns (self, schema_model.Table table)
 
list[sqlalchemy.schema.SchemaItem] _table_constraints (self, schema_model.Table table, Mapping[str, sqlalchemy.schema.Table] table_map)
 

Static Protected Member Functions

list[schema_model.Table_topo_sort (Iterable[schema_model.Table] table_iter)
 

Protected Attributes

 _metadata
 
 _prefix
 

Detailed Description

Class which implements schema model conversion to SQLAlchemy format.

Parameters
----------
metadata : `sqlalchemy.schema.MetaData`
    Metadata object for created tables.
prefix : `str`, optional
    Prefix to add to all schema elements.

Definition at line 90 of file modelToSql.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.dax.apdb.sql.modelToSql.ModelToSql.__init__ ( self,
sqlalchemy.schema.MetaData metadata,
str prefix = "" )

Definition at line 101 of file modelToSql.py.

105 ):
106 self._metadata = metadata
107 self._prefix = prefix
108
109 # Map model column types to SQLAlchemy.
110 self._type_map: dict[felis.datamodel.DataType | schema_model.ExtraDataTypes, type] = {
111 felis.datamodel.DataType.double: sqlalchemy.types.Double,
112 felis.datamodel.DataType.float: sqlalchemy.types.Float,
113 felis.datamodel.DataType.timestamp: sqlalchemy.types.TIMESTAMP,
114 felis.datamodel.DataType.long: sqlalchemy.types.BigInteger,
115 felis.datamodel.DataType.int: sqlalchemy.types.Integer,
116 felis.datamodel.DataType.short: sqlalchemy.types.SmallInteger,
117 felis.datamodel.DataType.byte: sqlalchemy.types.SmallInteger, # Byte types are not very portable
118 felis.datamodel.DataType.binary: sqlalchemy.types.LargeBinary,
119 felis.datamodel.DataType.text: sqlalchemy.types.Text,
120 felis.datamodel.DataType.string: sqlalchemy.types.CHAR,
121 felis.datamodel.DataType.char: sqlalchemy.types.CHAR,
122 felis.datamodel.DataType.unicode: sqlalchemy.types.CHAR,
123 felis.datamodel.DataType.boolean: sqlalchemy.types.Boolean,
124 schema_model.ExtraDataTypes.UUID: GUID,
125 }
126

Member Function Documentation

◆ _table_columns()

list[sqlalchemy.schema.Column] lsst.dax.apdb.sql.modelToSql.ModelToSql._table_columns ( self,
schema_model.Table table )
protected
Return set of columns in a table

Parameters
----------
table : `schema_model.Table`
    Table model.

Returns
-------
column_defs : `list` [`sqlalchemy.schema.Column`]
    List of columns.

Definition at line 159 of file modelToSql.py.

159 def _table_columns(self, table: schema_model.Table) -> list[sqlalchemy.schema.Column]:
160 """Return set of columns in a table
161
162 Parameters
163 ----------
164 table : `schema_model.Table`
165 Table model.
166
167 Returns
168 -------
169 column_defs : `list` [`sqlalchemy.schema.Column`]
170 List of columns.
171 """
172 column_defs: list[sqlalchemy.schema.Column] = []
173 for column in table.columns:
174 kwargs: dict[str, Any] = dict(nullable=column.nullable)
175 if column.value is not None:
176 kwargs.update(server_default=str(column.value))
177 if column in table.primary_key and column.autoincrement is None:
178 kwargs.update(autoincrement=False)
179 else:
180 kwargs.update(autoincrement=column.autoincrement)
181 ctype = self._type_map[column.datatype]
182 if column.length is not None:
183 if ctype not in (sqlalchemy.types.Text, sqlalchemy.types.TIMESTAMP):
184 ctype = ctype(length=column.length)
185 column_defs.append(sqlalchemy.schema.Column(column.name, ctype, **kwargs))
186
187 return column_defs
188

◆ _table_constraints()

list[sqlalchemy.schema.SchemaItem] lsst.dax.apdb.sql.modelToSql.ModelToSql._table_constraints ( self,
schema_model.Table table,
Mapping[str, sqlalchemy.schema.Table] table_map )
protected
Return set of constraints/indices in a table.

Parameters
----------
table : `schema_model.Table`
    Table model.
table_map : `~collections.abc.Mapping`
    MApping of table ID to sqlalchemy table definition for tables
    that already exist, this must include all tables referenced by
    foreign keys in ``table``.

Returns
-------
constraints : `list` [`sqlalchemy.schema.SchemaItem`]
    List of SQLAlchemy index/constraint objects.

Definition at line 189 of file modelToSql.py.

193 ) -> list[sqlalchemy.schema.SchemaItem]:
194 """Return set of constraints/indices in a table.
195
196 Parameters
197 ----------
198 table : `schema_model.Table`
199 Table model.
200 table_map : `~collections.abc.Mapping`
201 MApping of table ID to sqlalchemy table definition for tables
202 that already exist, this must include all tables referenced by
203 foreign keys in ``table``.
204
205 Returns
206 -------
207 constraints : `list` [`sqlalchemy.schema.SchemaItem`]
208 List of SQLAlchemy index/constraint objects.
209 """
210 constraints: list[sqlalchemy.schema.SchemaItem] = []
211 if table.primary_key:
212 # It is very useful to have named PK.
213 name = self._prefix + table.name + "_pk"
214 constraints.append(
215 sqlalchemy.schema.PrimaryKeyConstraint(*[column.name for column in table.primary_key])
216 )
217 for index in table.indexes:
218 if index.expressions:
219 raise TypeError(f"Expression indices are not supported: {table}")
220 name = self._prefix + index.name if index.name else ""
221 constraints.append(sqlalchemy.schema.Index(name, *[column.name for column in index.columns]))
222 for constraint in table.constraints:
223 constr_name: str | None = None
224 if constraint.name:
225 constr_name = self._prefix + constraint.name
226 if isinstance(constraint, schema_model.UniqueConstraint):
227 constraints.append(
228 sqlalchemy.schema.UniqueConstraint(
229 *[column.name for column in constraint.columns], name=constr_name
230 )
231 )
232 elif isinstance(constraint, schema_model.ForeignKeyConstraint):
233 column_names = [col.name for col in constraint.columns]
234 foreign_table = table_map[constraint.referenced_table.id]
235 refcolumns = [foreign_table.columns[col.name] for col in constraint.referenced_columns]
236 constraints.append(
237 sqlalchemy.schema.ForeignKeyConstraint(
238 columns=column_names,
239 refcolumns=refcolumns,
240 name=constr_name,
241 deferrable=constraint.deferrable,
242 initially=constraint.initially,
243 onupdate=constraint.onupdate,
244 ondelete=constraint.ondelete,
245 )
246 )
247 elif isinstance(constraint, schema_model.CheckConstraint):
248 constraints.append(
249 sqlalchemy.schema.CheckConstraint(
250 constraint.expression,
251 name=constr_name,
252 deferrable=constraint.deferrable,
253 initially=constraint.initially,
254 )
255 )
256 else:
257 raise TypeError(f"Unknown constraint type: {constraint}")
258
259 return constraints
260

◆ _topo_sort()

list[schema_model.Table] lsst.dax.apdb.sql.modelToSql.ModelToSql._topo_sort ( Iterable[schema_model.Table] table_iter)
staticprotected
Toplogical sorting of tables.

Definition at line 262 of file modelToSql.py.

262 def _topo_sort(table_iter: Iterable[schema_model.Table]) -> list[schema_model.Table]:
263 """Toplogical sorting of tables."""
264 result: list[schema_model.Table] = []
265 result_ids: set[str] = set()
266 tables = list(table_iter)
267
268 # Map of table ID to foreign table IDs.
269 referenced_tables: dict[str, set[str]] = {}
270 for table in tables:
271 referenced_tables[table.id] = set()
272 for constraint in table.constraints:
273 if isinstance(constraint, schema_model.ForeignKeyConstraint):
274 referenced_tables[table.id].add(constraint.referenced_table.id)
275
276 while True:
277 keep = []
278 changed = False
279 for table in tables:
280 if referenced_tables[table.id].issubset(result_ids):
281 changed = True
282 result.append(table)
283 result_ids.add(table.id)
284 else:
285 keep.append(table)
286 tables = keep
287 if not changed:
288 break
289
290 # If nothing can be removed it means cycle.
291 if tables:
292 raise ValueError(f"Dependency cycle in foreign keys: {tables}")
293
294 return result
daf::base::PropertySet * set
Definition fits.cc:931

◆ make_tables()

Mapping[str, sqlalchemy.schema.Table] lsst.dax.apdb.sql.modelToSql.ModelToSql.make_tables ( self,
Iterable[schema_model.Table] tables )
Generate sqlalchemy table schema from the list of modedls.

Parameters
----------
tables : `~collections.abc.Iterable` [`schema_model.Table`]
    List of table models.

Returns
-------
tables : `~collections.abc.Mapping` [`str`, `sqlalchemy.schema.Table`]
    SQLAlchemy table definitions indexed by identifier of the table
    model.

Definition at line 127 of file modelToSql.py.

127 def make_tables(self, tables: Iterable[schema_model.Table]) -> Mapping[str, sqlalchemy.schema.Table]:
128 """Generate sqlalchemy table schema from the list of modedls.
129
130 Parameters
131 ----------
132 tables : `~collections.abc.Iterable` [`schema_model.Table`]
133 List of table models.
134
135 Returns
136 -------
137 tables : `~collections.abc.Mapping` [`str`, `sqlalchemy.schema.Table`]
138 SQLAlchemy table definitions indexed by identifier of the table
139 model.
140 """
141 # Order tables based on their FK dependencies.
142 tables = self._topo_sort(tables)
143
144 table_map: dict[str, sqlalchemy.schema.Table] = {}
145 for table in tables:
146 columns = self._table_columns(table)
147 constraints = self._table_constraints(table, table_map)
148 sa_table = sqlalchemy.schema.Table(
149 self._prefix + table.name,
150 self._metadata,
151 *columns,
152 *constraints,
153 schema=self._metadata.schema,
154 )
155 table_map[table.id] = sa_table
156
157 return table_map
158

Member Data Documentation

◆ _metadata

lsst.dax.apdb.sql.modelToSql.ModelToSql._metadata
protected

Definition at line 106 of file modelToSql.py.

◆ _prefix

lsst.dax.apdb.sql.modelToSql.ModelToSql._prefix
protected

Definition at line 107 of file modelToSql.py.


The documentation for this class was generated from the following file: