@@ -287,6 +287,11 @@ class Model(ABC, Generic[D]):
287
287
terms.
288
288
"""
289
289
290
+ _indices : Sequence [types .Index ] = ()
291
+ """A sequence of `Index` objects that describe the indices to be
292
+ created for this table.
293
+ """
294
+
290
295
@cached_classproperty
291
296
def _types (cls ) -> dict [str , types .Type ]:
292
297
"""Optional types for non-fixed (flexible and computed) fields."""
@@ -1031,7 +1036,9 @@ def __init__(self, path, timeout: float = 5.0):
1031
1036
1032
1037
# Set up database schema.
1033
1038
for model_cls in self ._models :
1034
- self ._make_table (model_cls ._table , model_cls ._fields )
1039
+ self ._make_table (
1040
+ model_cls ._table , model_cls ._fields , model_cls ._indices
1041
+ )
1035
1042
self ._make_attribute_table (model_cls ._flex_table )
1036
1043
1037
1044
# Primitive access control: connections and transactions.
@@ -1153,20 +1160,32 @@ def load_extension(self, path: str):
1153
1160
1154
1161
# Schema setup and migration.
1155
1162
1156
- def _make_table (self , table : str , fields : Mapping [str , types .Type ]):
1163
+ def _make_table (
1164
+ self ,
1165
+ table : str ,
1166
+ fields : Mapping [str , types .Type ],
1167
+ indices : Sequence [types .Index ] = [],
1168
+ ):
1157
1169
"""Set up the schema of the database. `fields` is a mapping
1158
1170
from field names to `Type`s. Columns are added if necessary.
1159
1171
"""
1160
- # Get current schema.
1172
+ # Get current schema and existing indexes
1161
1173
with self .transaction () as tx :
1162
1174
rows = tx .query ("PRAGMA table_info(%s)" % table )
1163
- current_fields = {row [1 ] for row in rows }
1175
+ current_fields = {row [1 ] for row in rows }
1176
+ index_rows = tx .query (f"PRAGMA index_list({ table } )" )
1177
+ current_indices = {row [1 ] for row in index_rows } # Index names
1164
1178
1179
+ # Skip table creation if the current schema matches the
1180
+ # requested schema (and no indexes are missing).
1165
1181
field_names = set (fields .keys ())
1166
- if current_fields .issuperset (field_names ):
1167
- # Table exists and has all the required columns.
1182
+ index_names = {index .name for index in indices }
1183
+ if current_fields .issuperset (
1184
+ field_names
1185
+ ) and current_indices .issuperset (index_names ):
1168
1186
return
1169
1187
1188
+ # Table schema handling
1170
1189
if not current_fields :
1171
1190
# No table exists.
1172
1191
columns = []
@@ -1189,6 +1208,17 @@ def _make_table(self, table: str, fields: Mapping[str, types.Type]):
1189
1208
with self .transaction () as tx :
1190
1209
tx .script (setup_sql )
1191
1210
1211
+ # Index handling
1212
+ with self .transaction () as tx :
1213
+ for index in indices :
1214
+ if index .name in current_indices :
1215
+ continue
1216
+
1217
+ columns_str = ", " .join (index .columns )
1218
+ tx .script (
1219
+ f"CREATE INDEX { index .name } ON { table } ({ columns_str } )"
1220
+ )
1221
+
1192
1222
def _make_attribute_table (self , flex_table : str ):
1193
1223
"""Create a table and associated index for flexible attributes
1194
1224
for the given entity (if they don't exist).
0 commit comments