@@ -141,28 +141,52 @@ def _raise_for_protocol_mismatches(conn: sa.Connection, table: sa.Table) -> None
141141 raise RuntimeError (msg )
142142
143143
144+ def _existing_check_names (conn : sa .Connection ) -> set [str ]:
145+ return {check ["name" ] for check in sa .inspect (conn ).get_check_constraints (_CONFIG_TABLE ) if check .get ("name" )}
146+
147+
144148def _create_checks (conn : sa .Connection , table : sa .Table ) -> None :
149+ # create_all() may already have installed these from the SQLModel metadata.
150+ existing = _existing_check_names (conn )
151+ need_protocol = _PROTOCOL_CHECK not in existing
152+ need_enabled = _ENABLED_CHECK not in existing
153+ if not need_protocol and not need_enabled :
154+ return
145155 if conn .dialect .name == "sqlite" :
146156 with op .batch_alter_table (_CONFIG_TABLE , recreate = "always" ) as batch_op :
147- batch_op .create_check_constraint (_PROTOCOL_CHECK , _protocol_check (table ))
148- batch_op .create_check_constraint (_ENABLED_CHECK , _enabled_check (table ))
157+ if need_protocol :
158+ batch_op .create_check_constraint (_PROTOCOL_CHECK , _protocol_check (table ))
159+ if need_enabled :
160+ batch_op .create_check_constraint (_ENABLED_CHECK , _enabled_check (table ))
149161 return
150- op .create_check_constraint (_PROTOCOL_CHECK , _CONFIG_TABLE , _protocol_check (table ))
151- op .create_check_constraint (_ENABLED_CHECK , _CONFIG_TABLE , _enabled_check (table ))
162+ if need_protocol :
163+ op .create_check_constraint (_PROTOCOL_CHECK , _CONFIG_TABLE , _protocol_check (table ))
164+ if need_enabled :
165+ op .create_check_constraint (_ENABLED_CHECK , _CONFIG_TABLE , _enabled_check (table ))
152166
153167
154168def _drop_checks (conn : sa .Connection ) -> None :
169+ existing = _existing_check_names (conn )
170+ if _ENABLED_CHECK not in existing and _PROTOCOL_CHECK not in existing :
171+ return
155172 if conn .dialect .name == "sqlite" :
156173 with op .batch_alter_table (_CONFIG_TABLE , recreate = "always" ) as batch_op :
157- batch_op .drop_constraint (_ENABLED_CHECK , type_ = "check" )
158- batch_op .drop_constraint (_PROTOCOL_CHECK , type_ = "check" )
174+ if _ENABLED_CHECK in existing :
175+ batch_op .drop_constraint (_ENABLED_CHECK , type_ = "check" )
176+ if _PROTOCOL_CHECK in existing :
177+ batch_op .drop_constraint (_PROTOCOL_CHECK , type_ = "check" )
159178 return
160- op .drop_constraint (_ENABLED_CHECK , _CONFIG_TABLE , type_ = "check" )
161- op .drop_constraint (_PROTOCOL_CHECK , _CONFIG_TABLE , type_ = "check" )
179+ if _ENABLED_CHECK in existing :
180+ op .drop_constraint (_ENABLED_CHECK , _CONFIG_TABLE , type_ = "check" )
181+ if _PROTOCOL_CHECK in existing :
182+ op .drop_constraint (_PROTOCOL_CHECK , _CONFIG_TABLE , type_ = "check" )
162183
163184
164185def _create_slug_trigger (conn : sa .Connection ) -> None :
186+ # Idempotent for create_all()-then-upgrade: model after_create listeners may
187+ # already have installed the same trigger/function.
165188 if conn .dialect .name == "sqlite" :
189+ op .execute (sa .text (f"DROP TRIGGER IF EXISTS { _SLUG_TRIGGER } " ))
166190 op .execute (
167191 sa .text (
168192 f"""
@@ -177,6 +201,7 @@ def _create_slug_trigger(conn: sa.Connection) -> None:
177201 )
178202 )
179203 elif conn .dialect .name == "postgresql" :
204+ op .execute (sa .text (f"DROP TRIGGER IF EXISTS { _SLUG_TRIGGER } ON { _CONFIG_TABLE } " ))
180205 op .execute (
181206 sa .text (
182207 f"""
0 commit comments