+ def insert_or_get(cng) do
+ {_, data} = fetch_field(cng, :data)
+ id = data["id"] || data[:id]
+ key = "object:#{id}"
+
+ fetcher = fn _ ->
+ with nil <- get_by_ap_id(id),
+ {:ok, object} <- Repo.insert(cng) do
+ {:commit, object}
+ else
+ %Object{} = object -> {:commit, object}
+ e -> {:ignore, e}
+ end
+ end
+
+ with {state, object} when state in [:commit, :ok] <- Cachex.fetch(:object_cache, key, fetcher) do
+ {:ok, object}
+ end
+ end
+
+ def create(data) do
+ Object.change(%Object{}, %{data: data})
+ |> insert_or_get()
+ end
+
+ def change(struct, params \\ %{}) do
+ struct
+ |> cast(params, [:data])
+ |> validate_required([:data])
+ |> unique_constraint(:ap_id, name: :objects_unique_apid_index)
+ end
+
+ def get_by_ap_id(nil), do: nil
+