Ash FrameworkAF
Ash Framework3y ago
81 replies
rohan

Check if an identity exists in a before_action

I'm not quite sure how to accomplish this in Ash:

I'm uploading files to GCS and want to make sure if the hash of the file matches one I already have, I don't upload it again. The upload happens in a before_action on create right now. The hash of the file is an identity, and I thought eager checking would prevent the upload but it doesn't seem to.

I'd like the create_with_binary to return the original record if it exists (without uploading) or upload and create a new record if necessary. So basically find_or_create.

Here's the code so far:
defmodule Scribble.EmailHandler.AudioFile do
  use Ash.Resource, data_layer: AshPostgres.DataLayer

  postgres do
    table "audio_files"
    repo(Scribble.Repo)
  end

  attributes do
    uuid_primary_key :id
    attribute :hash, :string, allow_nil?: false
    attribute :url, :string, allow_nil?: false
  end

  identities do
    identity :hash, [:hash], eager_check_with: Scribble.EmailHandler
  end

  code_interface do
    define_for Scribble.EmailHandler

    define :create_with_binary, args: [:audio_file]
  end

  actions do
    defaults [:read]

    create :create_with_binary do
      argument :audio_file, :map, allow_nil?: false
      accept []

      change fn changeset, _context ->
        Ash.Changeset.before_action(changeset, fn changeset ->
          audio_file = Ash.Changeset.get_argument(changeset, :audio_file)
          filename = audio_file_hash(audio_file)

          {:ok, ^filename} =
            Scribble.Recording.store(%{filename: filename, binary: audio_file.binary})

          url = Scribble.Recording.url(filename)
          Ash.Changeset.change_attributes(changeset, %{url: url, hash: filename})
        end)
      end
    end
  end

  defp audio_file_hash(%{binary: binary, extension: extension}) do
    hash = Scribble.Scribe.audio_hash(binary)
    "#{hash}#{extension}"
  end
end
Was this page helpful?