@@ -287,6 +287,11 @@ class Model(ABC, Generic[D]):
287287 terms.
288288 """
289289
290+ _indices : Sequence [types .Index ] = ()
291+ """A sequence of `Index` objects that describe the indices to be
292+ created for this table.
293+ """
294+
290295 @cached_classproperty
291296 def _types (cls ) -> dict [str , types .Type ]:
292297 """Optional types for non-fixed (flexible and computed) fields."""
@@ -1031,7 +1036,9 @@ def __init__(self, path, timeout: float = 5.0):
10311036
10321037 # Set up database schema.
10331038 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+ )
10351042 self ._make_attribute_table (model_cls ._flex_table )
10361043
10371044 # Primitive access control: connections and transactions.
@@ -1153,20 +1160,32 @@ def load_extension(self, path: str):
11531160
11541161 # Schema setup and migration.
11551162
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+ ):
11571169 """Set up the schema of the database. `fields` is a mapping
11581170 from field names to `Type`s. Columns are added if necessary.
11591171 """
1160- # Get current schema.
1172+ # Get current schema and existing indexes
11611173 with self .transaction () as tx :
11621174 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 }
11641178
1179+ # Skip table creation if the current schema matches the
1180+ # requested schema (and no indexes are missing).
11651181 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 ):
11681186 return
11691187
1188+ # Table schema handling
11701189 if not current_fields :
11711190 # No table exists.
11721191 columns = []
@@ -1189,6 +1208,17 @@ def _make_table(self, table: str, fields: Mapping[str, types.Type]):
11891208 with self .transaction () as tx :
11901209 tx .script (setup_sql )
11911210
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+
11921222 def _make_attribute_table (self , flex_table : str ):
11931223 """Create a table and associated index for flexible attributes
11941224 for the given entity (if they don't exist).
0 commit comments