Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repo.set creates new node rather than updating existing node #88

Open
goravbhootra opened this issue Jul 4, 2020 · 3 comments
Open

Comments

@goravbhootra
Copy link

goravbhootra commented Jul 4, 2020

Expected behaviour: Existing node should be updated

Actual behaviour: New node is created every time

version: 0.5.1

Same implementation was working fine with earlier version.

Implementation:

file lib/lms/courses/course.ex contains:

defmodule Lms.Courses.Course do
  use Dlex.Node
  @derive {Phoenix.Param, key: :uid}

  import Ecto.Changeset

  schema "courses" do
    field(:description, :string)
    field(:duration_allowed, :integer)
    field(:duration_units, :integer, default: 3)
    field(:position, :integer)
    field(:status, :integer)
    field(:title, :string, index: ["term"])
    field(:guidelines, :string)
    field(:guidelines_title, :string)
    field(:has_learning_path, :uid)

    field(:created_at, :datetime)
    field(:updated_at, :datetime)
  end

  @doc false
  def changeset(course, attrs) do
    course
    |> cast(attrs, [
      :title,
      :description,
      :duration_allowed,
      :duration_units,
      :status,
      :position,
      :guidelines,
      :guidelines_title
    ])
  end
end

and lib/lms/courses.ex contains:

def update_course(%Course{} = course, attrs) do
    course
    |> Course.changeset(attrs)
    |> Repo.set()
  end

Following creates a new node rather than updating the existing node:

id = "0x7533" # its a valid id and returns Course struct
course = Repo.get!(id)
course_params = [
  attrs: %{
    "description" => "",
    "duration_allowed" => "",
    "guidelines" => "",
    "guidelines_title" => "",
    "position" => "",
    "status" => "1",
    "title" => "updated title"
  }
]
Lms.Courses.update_course(course, course_params)

Course.changeset(attrs) produces:

changeset: #Ecto.Changeset<
  action: nil,
  changes: %{status: 1, title: "updated title"},
  errors: [],
  data: #Lms.Courses.Course<>,
  valid?: true
>

and data key contains:

%Lms.Courses.Course{
  created_at: nil,
  description: nil,
  duration_allowed: nil,
  duration_units: 3,
  guidelines: nil,
  guidelines_title: nil,
  has_learning_path: nil,
  position: nil,
  status: 1,
  title: "now we got it",
  uid: "0x7533",
  updated_at: nil
}

Tried replacing Repo.set with Repo.mutate but same issue persists.

@goravbhootra goravbhootra changed the title Repo.mutate creates new node rather than updating existing node Repo.set creates new node rather than updating existing node Jul 4, 2020
@martinthenth
Copy link
Contributor

When updating, are you casting :uid as a field?

I use

struct
    |> cast(params, [
      :uid,
      :title
    ])
    |> validate_required([:uid])

and it works.

@martinthenth
Copy link
Contributor

martinthenth commented Feb 26, 2021

To those who are looking for a solution, i.e. to update existing nodes in Dgraph with Ecto changesets:

  1. Cast uid in your changeset.
  2. Validate require uid in your changeset.
  3. Force change uid in your changeset.

For example:

def update_changeset(%Struct{} = struct, attrs) do
  struct
  |> cast(attrs, [:uid])
  |> validate_required([:uid])
  |> force_change(:uid, struct.uid)
end

This will update an existing node in Dgraph based on the given uid.

Perhaps it's possible to indicate to Ecto that uid is a primary key so that uid is automatically added to Ecto.Changeset changes field, but I have not tested this.

@goravbhootra
Copy link
Author

Thanks Martin for the solution. I had dropped the implementation, will try to pick it up again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants