diff --git a/framework/py/flwr/supercore/state/alembic/versions/rev_2026_04_30_make_run_substatus_and_details_not_nullable.py b/framework/py/flwr/supercore/state/alembic/versions/rev_2026_04_30_make_run_substatus_and_details_not_nullable.py new file mode 100644 index 000000000000..1b97848547e3 --- /dev/null +++ b/framework/py/flwr/supercore/state/alembic/versions/rev_2026_04_30_make_run_substatus_and_details_not_nullable.py @@ -0,0 +1,69 @@ +# Copyright 2026 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Make run sub_status and details not nullable. + +Revision ID: e566a1e755c5 +Revises: c7eb009ce75c +Create Date: 2026-04-30 09:43:42.202183 +""" +from collections.abc import Sequence + +import sqlalchemy as sa +from alembic import op + +# pylint: disable=no-member + +# revision identifiers, used by Alembic. +revision: str = "e566a1e755c5" +down_revision: str | Sequence[str] | None = "c7eb009ce75c" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + + +def upgrade() -> None: + """Upgrade schema.""" + # Backfill existing NULLs before enforcing NOT NULL. + op.execute("UPDATE run SET sub_status = '' WHERE sub_status IS NULL") + op.execute("UPDATE run SET details = '' WHERE details IS NULL") + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("run", schema=None) as batch_op: + batch_op.alter_column( + "sub_status", + existing_type=sa.VARCHAR(), + server_default=sa.text("''"), + nullable=False, + ) + batch_op.alter_column( + "details", + existing_type=sa.VARCHAR(), + server_default=sa.text("''"), + nullable=False, + ) + + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("run", schema=None) as batch_op: + batch_op.alter_column( + "details", existing_type=sa.VARCHAR(), server_default=None, nullable=True + ) + batch_op.alter_column( + "sub_status", existing_type=sa.VARCHAR(), server_default=None, nullable=True + ) + + # ### end Alembic commands ### diff --git a/framework/py/flwr/supercore/state/schema/README.md b/framework/py/flwr/supercore/state/schema/README.md index c320f556ce7f..a8971e09d3b8 100644 --- a/framework/py/flwr/supercore/state/schema/README.md +++ b/framework/py/flwr/supercore/state/schema/README.md @@ -94,7 +94,7 @@ erDiagram BIGINT bytes_recv "nullable" BIGINT bytes_sent "nullable" FLOAT clientapp_runtime "nullable" - VARCHAR details "nullable" + VARCHAR details VARCHAR fab_hash "nullable" VARCHAR fab_id "nullable" VARCHAR fab_version "nullable" @@ -109,7 +109,7 @@ erDiagram VARCHAR run_type VARCHAR running_at "nullable" VARCHAR starting_at "nullable" - VARCHAR sub_status "nullable" + VARCHAR sub_status VARCHAR usage_reported_at } diff --git a/framework/py/flwr/supercore/state/schema/linkstate_tables.py b/framework/py/flwr/supercore/state/schema/linkstate_tables.py index 7b8b10a87799..dc52c3dbb324 100644 --- a/framework/py/flwr/supercore/state/schema/linkstate_tables.py +++ b/framework/py/flwr/supercore/state/schema/linkstate_tables.py @@ -79,8 +79,8 @@ def create_linkstate_metadata() -> MetaData: Column("running_at", String), Column("finished_at", String), Column("usage_reported_at", String, nullable=False, server_default=text("''")), - Column("sub_status", String), - Column("details", String), + Column("sub_status", String, nullable=False, server_default=text("''")), + Column("details", String, nullable=False, server_default=text("''")), Column("federation", String), Column("primary_task_id", BigInteger, nullable=True), Column("federation_config", String),