circles-learning-labs / ecto_adapters_dynamodb

DynamoDB adapter for Elixir's Ecto Database layer.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Can't delete record with hash+range key

msmithstubbs opened this issue · comments

I've attempted to delete a record that has a hash and range key but encountered an error.

To reproduce (using the BookPage schema from the test suite):

test "delete a record with a hash/range pkey" do
  name = "mybook"
  page1 = %BookPage{
            id: name,
            page_num: 1,
            text: "abc",
          }
  page2 = %BookPage{
            id: name,
            page_num: 2,
            text: "def",
          }
  cs1 = BookPage.changeset(page1)
  cs2 = BookPage.changeset(page2)
  {:ok, page1} = TestRepo.insert(cs1)
  {:ok, page2} = TestRepo.insert(cs2)
  TestRepo.delete(page1)
end

Result:

 1) test Repo.delete/1 delete a record with a hash/range pkey (Ecto.Adapters.DynamoDB.Test)
     test/ecto_adapters_dynamodb_test.exs:392
     ** (RuntimeError) __MODULE__.update error: more than one result found for record: [id: "mybook"]
     code: TestRepo.delete(page1)

Expected result to not be an error and return:

{:ok, struct}

where struct is the deleted BookPage struct.

Thank you for notifying us. We will attend to it as soon as we can.

This works:
TestRepo.delete(page1, [range_key: {:page_num, 2}])

Please read the ":range_key" section under Custom Inline Options in the README (it's the first one there).

On second look, it seems we indicate in the README that the adapter will try to find the correct range key automatically if none is provided. Let us see about that as well and get back to you.

@msmithstubbs examining the arguments passed to delete (page 629 in "lib/ecto_adapters_dynamodb.ex") when executing the test, we see:

repo -> Ecto.Adapters.DynamoDB.TestRepo,

schema_meta -> %{autogenerate_id: {:id, :binary_id}, context: nil, schema: Ecto.Adapters.DynamoDB.TestSchema.BookPage, source: {nil, "test_book_page"}},

filters -> [id: "mybook"],

opts -> []

the relevant range value (page_num 2) seems missing from the data. This seems to be a result of how Ecto preprocesses the query and the fact that Ecto does not support hash-range keys (that I know of). In this particular case, since our additional automatic query returns two results, there is no way for the adapter to confirm which record we'd like to delete. This is why we provide for the special range_key option. Does that make sense?

@msmithstubbs that said, we could and will provide a more informative error message indicating the range_key option. Thanks.

Thanks for your detailed response @alhambra1. That definitely provides a solution to deleting a record but I was curious if this was a deliberate choice.

Ecto does support multiple primary keys. For example:

defmodule Ecto.Adapters.DynamoDB.TestSchema.BookPage do
  use Ecto.Schema
  @primary_key {:id, :binary_id, autogenerate: true}

  schema "test_book_page" do
    field :page_num, :integer, primary_key: true
    field :text,     :string
  end
end

defines both id and page_num as primary keys. Ecto does not distinguish between 'range' and 'hash' keys but I don't think that is necessary for this functionality.

I believe you would no longer require the range_key option?