Skip to content

Commit

Permalink
ensure uniqueness across all args if no keys are specified
Browse files Browse the repository at this point in the history
  • Loading branch information
sannek committed Feb 7, 2024
1 parent d5fe1a1 commit ad2a19b
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 8 deletions.
17 changes: 13 additions & 4 deletions lib/oban/engines/basic.ex
Original file line number Diff line number Diff line change
Expand Up @@ -382,10 +382,19 @@ defmodule Oban.Engines.Basic do
defp unique_field({changeset, field, keys}, acc) when field in [:args, :meta] do
value = unique_map_values(changeset, field, keys)

if value == %{} do
dynamic([j], fragment("? <@ ?", field(j, ^field), ^value) and ^acc)
else
dynamic([j], fragment("? @> ?", field(j, ^field), ^value) and ^acc)
cond do
value == %{} ->
dynamic([j], fragment("? <@ ?", field(j, ^field), ^value) and ^acc)

keys == [] ->
dynamic(
[j],
fragment("? @> ?", field(j, ^field), ^value) and
fragment("? <@ ?", field(j, ^field), ^value) and ^acc
)

:else ->
dynamic([j], fragment("? @> ?", field(j, ^field), ^value) and ^acc)
end
end

Expand Down
17 changes: 13 additions & 4 deletions lib/oban/engines/lite.ex
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,19 @@ defmodule Oban.Engines.Lite do
|> Changeset.get_field(field)
|> map_values(keys)

if value == %{} do
dynamic([j], field(j, ^field) == ^value and ^acc)
else
dynamic([j], json_contains(field(j, ^field), ^Jason.encode!(value)) and ^acc)
cond do
value == %{} ->
dynamic([j], field(j, ^field) == ^value and ^acc)

keys == [] ->
dynamic(
[j],
json_contains(field(j, ^field), ^Jason.encode!(value)) and
json_contains(^Jason.encode!(value), field(j, ^field)) and ^acc
)

:else ->
dynamic([j], json_contains(field(j, ^field), ^Jason.encode!(value)) and ^acc)
end

field, acc ->
Expand Down
26 changes: 26 additions & 0 deletions test/oban/engine_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,32 @@ for engine <- [Oban.Engines.Basic, Oban.Engines.Lite] do
assert id_2 == id_3
end

@tag :unique
test "considering all args to establish uniqueness", %{name: name} do
defmodule MiniUniq do
use Oban.Worker, unique: [fields: [:args]]

@impl Worker
def perform(_job), do: :ok
end

changeset1 = MiniUniq.new(%{id: 1})
changeset2 = MiniUniq.new(%{id: 1, extra: :cool_beans})

assert {:ok, %Job{id: id_1}} = Oban.insert(name, changeset1)
assert {:ok, %Job{id: id_2}} = Oban.insert(name, changeset2)

assert id_1 != id_2

changeset3 = MiniUniq.new(%{id: 2, extra: :cool_beans})
changeset4 = MiniUniq.new(%{id: 2})

assert {:ok, %Job{id: id_1}} = Oban.insert(name, changeset3)
assert {:ok, %Job{id: id_2}} = Oban.insert(name, changeset4)

assert id_1 != id_2
end

@tag :unique
test "scoping uniqueness by specific meta keys", %{name: name} do
unique = [fields: [:meta], keys: [:slug]]
Expand Down

0 comments on commit ad2a19b

Please sign in to comment.