Skip to content

Default inserts with Repo.insert(%Schema{}) are failing as they to insert the id funciton #285

@PragTob

Description

@PragTob

👋

Hi there and thanks for creating the mongodb-driver! 💚

Problem

How I think I'd wanna insert new records, given a repo that can write, fails:

iex(7)> Mongo.Repo.insert(%Mongo.User{name: "Tobi-san"})
[error] Unable to send request to database because of %Mongo.Error{message: "invalid document: &Mongo.object_id/0", code: nil, host: nil, fail_command: nil, error_labels: nil, resumable: false, retryable_reads: nil, retryable_writes: nil, not_writable_primary_or_recovering: nil, error_info: nil}
{:error,
 %Mongo.Error{
   message: "invalid document: &Mongo.object_id/0",
   code: nil,
   host: nil,
   fail_command: nil,
   error_labels: nil,
   resumable: false,
   retryable_reads: nil,
   retryable_writes: nil,
   not_writable_primary_or_recovering: nil,
   error_info: nil
 }}

Context

Pretty normal schema/repo (simplified/omitted attributes):

defmodule Mongo.User do
  use Mongo.Collection

  collection "users" do
    attribute :name, String.t()
  end
end
defmodule Mongo.Repo do
  use Mongo.Repo, otp_app: :my_app
end

Root Cause

I'm pretty sure this fails because per default _id is set to said function:

iex(9)> %Mongo.User{}
%Mongo.User{
  _id: &Mongo.object_id/0,
  # ....
}

And the insert code never calls it before inserting:

def insert(%{__struct__: module} = doc, opts \\ []) do
collection = module.__collection__(:collection)
doc = module.timestamps(doc)
case Mongo.insert_one(@topology, collection, module.dump(doc), opts) do
{:error, reason} -> {:error, reason}
{:ok, %{inserted_id: id}} -> {:ok, %{doc | _id: id}}
end
end

Solution

I believe the insert code should check if _id stores a 0-arity function, and if so call it and replace the value of _id with it

It may also be intentional not to insert records like this directly, but I think it'd be nice. Hence I'm looking for guidance.

Workaround

Some sort of new function can be used as a workaround:

  def new_with_id(attrs \\ %{}) do
    struct!(%__MODULE__{_id: Mongo.object_id()}, attrs)
  end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions