diff --git a/api/db/db_models.py b/api/db/db_models.py index 04009562fc..77ebcfc48f 100644 --- a/api/db/db_models.py +++ b/api/db/db_models.py @@ -1321,7 +1321,7 @@ class Document(DataBaseModel): progress_msg = TextField(null=True, help_text="process message", default="") process_begin_at = DateTimeField(null=True, index=True) process_duration = FloatField(default=0) - suffix = CharField(max_length=32, null=False, help_text="The real file extension suffix", index=True) + suffix = EmptyStringCharField(max_length=32, null=False, help_text="The real file extension suffix", index=True) content_hash = CharField(max_length=32, null=True, help_text="xxhash128 of document content for change detection", default="", index=True) @@ -1895,6 +1895,7 @@ GAUSSDB_EMPTY_STRING_COMPATIBLE_COLUMNS = ( ("dialog", ("llm_id", "rerank_id")), ("memory", ("embd_id", "llm_id")), ("file", ("source_type",)), + ("document", ("suffix",)), ("system_settings", ("value",)), ("task", ("task_type",)), ("sync_logs", ("error_msg", "full_exception_trace")), @@ -2395,7 +2396,7 @@ def migrate_db(): alter_db_add_column(migrator, "mcp_server", "variables", JSONField(null=True, help_text="MCP Server variables", default=dict)) alter_db_rename_column(migrator, "task", "process_duation", "process_duration") alter_db_rename_column(migrator, "document", "process_duation", "process_duration") - alter_db_add_column(migrator, "document", "suffix", CharField(max_length=32, null=False, default="", help_text="The real file extension suffix", index=True)) + alter_db_add_column(migrator, "document", "suffix", EmptyStringCharField(max_length=32, null=False, default="", help_text="The real file extension suffix", index=True)) alter_db_add_column(migrator, "api_4_conversation", "errors", TextField(null=True, help_text="errors")) alter_db_add_column(migrator, "dialog", "meta_data_filter", JSONField(null=True, default={})) alter_db_column_type(migrator, "canvas_template", "title", JSONField(null=True, default=dict, help_text="Canvas title")) diff --git a/test/unit_test/api/db/test_gaussdb_adaptation_points.py b/test/unit_test/api/db/test_gaussdb_adaptation_points.py index 0c7f46e841..55f8d1e6f5 100644 --- a/test/unit_test/api/db/test_gaussdb_adaptation_points.py +++ b/test/unit_test/api/db/test_gaussdb_adaptation_points.py @@ -75,6 +75,7 @@ def test_gaussdb_empty_string_compatible_migration_drops_not_null_only_for_gauss assert len(FakeDB.queries) == expected_query_count assert ('ALTER TABLE "user" ALTER COLUMN "nickname" DROP NOT NULL', None) in FakeDB.queries assert ('ALTER TABLE "tenant" ALTER COLUMN "llm_id" DROP NOT NULL', None) in FakeDB.queries + assert ('ALTER TABLE "document" ALTER COLUMN "suffix" DROP NOT NULL', None) in FakeDB.queries assert ('ALTER TABLE "system_settings" ALTER COLUMN "value" DROP NOT NULL', None) in FakeDB.queries assert ('ALTER TABLE "task" ALTER COLUMN "task_type" DROP NOT NULL', None) in FakeDB.queries assert ('ALTER TABLE "sync_logs" ALTER COLUMN "error_msg" DROP NOT NULL', None) in FakeDB.queries @@ -88,15 +89,14 @@ def test_gaussdb_empty_string_compatible_migration_drops_not_null_only_for_gauss assert len(FakeDB.queries) == expected_query_count -def test_gaussdb_migration_adds_compatible_tags_before_relaxing_columns(monkeypatch): +def test_gaussdb_migration_adds_compatible_fields_before_relaxing_columns(monkeypatch): events = [] - migrated_tags_field = None + migrated_fields = {} def record_add_column(_migrator, table_name, column_name, column_type): - nonlocal migrated_tags_field events.append(("add", table_name, column_name)) - if (table_name, column_name) == ("user_canvas", "tags"): - migrated_tags_field = column_type + if (table_name, column_name) in {("document", "suffix"), ("user_canvas", "tags")}: + migrated_fields[(table_name, column_name)] = column_type monkeypatch.setattr(settings, "DATABASE_TYPE", "gaussdb") monkeypatch.setattr(db_models, "alter_db_add_column", record_add_column) @@ -111,11 +111,22 @@ def test_gaussdb_migration_adds_compatible_tags_before_relaxing_columns(monkeypa db_models.migrate_db() - assert isinstance(migrated_tags_field, db_models.EmptyStringCharField) - assert migrated_tags_field.null is True + for field in migrated_fields.values(): + assert isinstance(field, db_models.EmptyStringCharField) + assert field.null is True + assert set(migrated_fields) == {("document", "suffix"), ("user_canvas", "tags")} assert events[-1] == ("relax",) +def test_empty_string_char_field_keeps_non_gaussdb_constraints(monkeypatch): + for database_type in ("mysql", "postgres", "oceanbase"): + monkeypatch.setattr(settings, "DATABASE_TYPE", database_type) + field = db_models.EmptyStringCharField(null=False) + + assert field.null is False + assert field.db_value("") == "" + + def test_gaussdb_unique_email_migration_checks_unique_email_index_not_fixed_name(monkeypatch): class Cursor: def fetchone(self): diff --git a/test/unit_test/api/db/test_gaussdb_user_flow.py b/test/unit_test/api/db/test_gaussdb_user_flow.py index 3e22a21bc4..125acbc470 100644 --- a/test/unit_test/api/db/test_gaussdb_user_flow.py +++ b/test/unit_test/api/db/test_gaussdb_user_flow.py @@ -77,7 +77,7 @@ print("gaussdb-adapter-ok") def test_gaussdb_empty_string_compatible_fields_are_nullable_only_for_gaussdb(): gaussdb_result = run_isolated_flow( """ -from api.db.db_models import API4Conversation, Dialog, File, Knowledgebase, Memory, SyncLogs, SystemSettings, Task, Tenant, User, UserCanvas +from api.db.db_models import API4Conversation, Dialog, Document, File, Knowledgebase, Memory, SyncLogs, SystemSettings, Task, Tenant, User, UserCanvas fields = [ User.nickname, @@ -92,6 +92,7 @@ fields = [ Dialog.rerank_id, Memory.embd_id, Memory.llm_id, + Document.suffix, SystemSettings.value, Task.task_type, Task.progress_msg, @@ -135,7 +136,7 @@ print("gaussdb-empty-string-compatible-ok") mysql_result = run_isolated_flow( """ -from api.db.db_models import API4Conversation, Dialog, File, Knowledgebase, Memory, SyncLogs, SystemSettings, Task, Tenant, User, UserCanvas +from api.db.db_models import API4Conversation, Dialog, Document, File, Knowledgebase, Memory, SyncLogs, SystemSettings, Task, Tenant, User, UserCanvas fields = [ (User.nickname, False), @@ -150,6 +151,7 @@ fields = [ (Dialog.rerank_id, False), (Memory.embd_id, False), (Memory.llm_id, False), + (Document.suffix, False), (SystemSettings.value, False), (Task.task_type, False), (Task.progress_msg, True),