From dee7ac0415e0de1c1f2d44d1dcd1202d5c7d099c Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Wed, 4 Mar 2026 13:04:41 +0400 Subject: [PATCH] Fix ParadeDB key field handling Use uuid ids in the ParadeDB documents table to satisfy BM25 key_field requirements and adjust indexing/search to dump FlakeIds consistently. Also fix the ParadeDB backend unit test to avoid invalid pinning on struct fields. --- lib/pleroma/search/paradedb.ex | 74 +++++++++++++++++---------- test/pleroma/search/paradedb_test.exs | 14 +++-- 2 files changed, 58 insertions(+), 30 deletions(-) diff --git a/lib/pleroma/search/paradedb.ex b/lib/pleroma/search/paradedb.ex index 963d573e8..e5d3018d7 100644 --- a/lib/pleroma/search/paradedb.ex +++ b/lib/pleroma/search/paradedb.ex @@ -67,37 +67,43 @@ defmodule Pleroma.Search.ParadeDB do maybe_search_data = object_to_search_data(activity.object) if activity.data["type"] == "Create" and maybe_search_data do + dumped_activity_id = dump_activity_id(activity.id) actor_ap_id = activity.data["actor"] published_at = DateTime.from_unix!(maybe_search_data.published) - sql = - """ - INSERT INTO #{table()} (id, object_id, object_ap_id, actor_ap_id, content, published_at) - VALUES ($1, $2, $3, $4, $5, $6) - ON CONFLICT (id) DO UPDATE SET - object_id = EXCLUDED.object_id, - object_ap_id = EXCLUDED.object_ap_id, - actor_ap_id = EXCLUDED.actor_ap_id, - content = EXCLUDED.content, - published_at = EXCLUDED.published_at - """ + if is_nil(dumped_activity_id) do + Logger.error("ParadeDB add_to_index failed: invalid activity id #{inspect(activity.id)}") + :ok + else + sql = + """ + INSERT INTO #{table()} (id, object_id, object_ap_id, actor_ap_id, content, published_at) + VALUES ($1, $2, $3, $4, $5, $6) + ON CONFLICT (id) DO UPDATE SET + object_id = EXCLUDED.object_id, + object_ap_id = EXCLUDED.object_ap_id, + actor_ap_id = EXCLUDED.actor_ap_id, + content = EXCLUDED.content, + published_at = EXCLUDED.published_at + """ - params = [ - activity.id, - maybe_search_data.id, - maybe_search_data.ap, - actor_ap_id, - maybe_search_data.content, - published_at - ] + params = [ + dumped_activity_id, + maybe_search_data.id, + maybe_search_data.ap, + actor_ap_id, + maybe_search_data.content, + published_at + ] - case client_impl().query(sql, params) do - {:ok, _} -> - :ok + case client_impl().query(sql, params) do + {:ok, _} -> + :ok - {:error, error} -> - Logger.error("ParadeDB add_to_index failed: #{inspect(error)}") - {:error, error} + {:error, error} -> + Logger.error("ParadeDB add_to_index failed: #{inspect(error)}") + {:error, error} + end end else :ok @@ -139,7 +145,10 @@ defmodule Pleroma.Search.ParadeDB do end defp fetch_activities(ids, user, query, author) do - dumped_ids = Enum.map(ids, &FlakeId.from_string/1) + dumped_ids = + ids + |> Enum.map(&dump_activity_id/1) + |> Enum.reject(&is_nil/1) from(a in Activity, where: a.id in ^dumped_ids) |> Activity.with_preloaded_object() @@ -189,7 +198,7 @@ defmodule Pleroma.Search.ParadeDB do defp create_table_sql(table) do """ CREATE TABLE IF NOT EXISTS #{table} ( - id text PRIMARY KEY, + id uuid PRIMARY KEY, object_id bigint NOT NULL, object_ap_id text NOT NULL, actor_ap_id text, @@ -210,4 +219,15 @@ defmodule Pleroma.Search.ParadeDB do WITH (key_field = 'id') """ end + + defp dump_activity_id(<<_::binary-size(16)>> = uuid), do: uuid + + defp dump_activity_id(id) when is_binary(id) do + case FlakeId.Ecto.CompatType.dump(id) do + {:ok, <<_::binary-size(16)>> = uuid} -> uuid + _ -> nil + end + end + + defp dump_activity_id(_), do: nil end diff --git a/test/pleroma/search/paradedb_test.exs b/test/pleroma/search/paradedb_test.exs index c55e2aa47..3338c78ef 100644 --- a/test/pleroma/search/paradedb_test.exs +++ b/test/pleroma/search/paradedb_test.exs @@ -35,7 +35,9 @@ defmodule Pleroma.Search.ParadeDBTest do [activity_id, object_id, object_ap_id, actor_ap_id, content, published_at] = params - assert activity_id == activity.id + {:ok, dumped_activity_id} = FlakeId.Ecto.CompatType.dump(activity.id) + + assert activity_id == dumped_activity_id assert is_integer(object_id) assert is_binary(object_ap_id) assert actor_ap_id == activity.data["actor"] @@ -144,12 +146,18 @@ defmodule Pleroma.Search.ParadeDBTest do {:ok, activity1} = CommonAPI.post(user, %{status: "first swamp", visibility: "public"}) {:ok, activity2} = CommonAPI.post(user, %{status: "second swamp", visibility: "public"}) + activity1_id = activity1.id + activity2_id = activity2.id + + {:ok, dumped_activity1_id} = FlakeId.Ecto.CompatType.dump(activity1_id) + {:ok, dumped_activity2_id} = FlakeId.Ecto.CompatType.dump(activity2_id) + ClientMock |> expect(:query, fn sql, params -> assert sql =~ "SELECT id FROM pleroma_search_documents" assert ["swamp", _limit, _offset] = params - {:ok, %{rows: [[activity2.id], [activity1.id]]}} + {:ok, %{rows: [[dumped_activity2_id], [dumped_activity1_id]]}} end) Config @@ -161,7 +169,7 @@ defmodule Pleroma.Search.ParadeDBTest do "pleroma_search_documents" end) - assert [%{id: ^activity2.id}, %{id: ^activity1.id}] = + assert [%{id: ^activity2_id}, %{id: ^activity1_id}] = ParadeDB.search(nil, "swamp", limit: 40, offset: 0) end end