revert 4a94c9a31ef11f63ea71ad9c1f085c18cf8ef083
[akkoma] / lib / pleroma / hashtag.ex
index de52c4dae66b5a98e744ea7d4db259e98ec5921f..53e2e9c897d564dd788306a72fa640ff75cbdce8 100644 (file)
@@ -21,22 +21,25 @@ defmodule Pleroma.Hashtag do
     timestamps()
   end
 
-  def get_by_name(name) do
-    Repo.get_by(Hashtag, name: name)
+  def normalize_name(name) do
+    name
+    |> String.downcase()
+    |> String.trim()
   end
 
-  def get_or_create_by_name(name) when is_bitstring(name) do
-    with %Hashtag{} = hashtag <- get_by_name(name) do
-      {:ok, hashtag}
-    else
-      _ ->
-        %Hashtag{}
-        |> changeset(%{name: name})
-        |> Repo.insert()
-    end
+  def get_or_create_by_name(name) do
+    changeset = changeset(%Hashtag{}, %{name: name})
+
+    Repo.insert(
+      changeset,
+      on_conflict: [set: [name: get_field(changeset, :name)]],
+      conflict_target: :name,
+      returning: true
+    )
   end
 
   def get_or_create_by_names(names) when is_list(names) do
+    names = Enum.map(names, &normalize_name/1)
     timestamp = NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
 
     structs =
@@ -47,23 +50,30 @@ defmodule Pleroma.Hashtag do
         |> Map.merge(%{inserted_at: timestamp, updated_at: timestamp})
       end)
 
-    with {:ok, %{query_op: hashtags}} <-
-           Multi.new()
-           |> Multi.insert_all(:insert_all_op, Hashtag, structs, on_conflict: :nothing)
-           |> Multi.run(:query_op, fn _repo, _changes ->
-             {:ok, Repo.all(from(ht in Hashtag, where: ht.name in ^names))}
-           end)
-           |> Repo.transaction() do
-      {:ok, hashtags}
-    else
-      {:error, _name, value, _changes_so_far} -> {:error, value}
+    try do
+      with {:ok, %{query_op: hashtags}} <-
+             Multi.new()
+             |> Multi.insert_all(:insert_all_op, Hashtag, structs,
+               on_conflict: :nothing,
+               conflict_target: :name
+             )
+             |> Multi.run(:query_op, fn _repo, _changes ->
+               {:ok, Repo.all(from(ht in Hashtag, where: ht.name in ^names))}
+             end)
+             |> Repo.transaction() do
+        {:ok, hashtags}
+      else
+        {:error, _name, value, _changes_so_far} -> {:error, value}
+      end
+    rescue
+      e -> {:error, e}
     end
   end
 
   def changeset(%Hashtag{} = struct, params) do
     struct
     |> cast(params, [:name])
-    |> update_change(:name, &String.downcase/1)
+    |> update_change(:name, &normalize_name/1)
     |> validate_required([:name])
     |> unique_constraint(:name)
   end
@@ -74,8 +84,9 @@ defmodule Pleroma.Hashtag do
              where: hto.object_id == ^object_id,
              select: hto.hashtag_id
            )
-           |> Repo.delete_all() do
-      delete_unreferenced(hashtag_ids)
+           |> Repo.delete_all(),
+         {:ok, unreferenced_count} <- delete_unreferenced(hashtag_ids) do
+      {:ok, length(hashtag_ids), unreferenced_count}
     end
   end