zookzook / yildun

Yildun is a white-hued star in the northern circumpolar constellation of Ursa Minor, forming the second star in the bear's tail. And it is a very small library to support structs while using the MongoDB driver for Elixir.
5 stars 2 forks source link

Integrate Collection with Ecto.Changeset? #4

Open bryansray opened 3 years ago

bryansray commented 3 years ago

Apologies for placing this here ... it doesn't look like "Discussions" are enabled on this repo.

I was curious if anyone has had any success with integrating this library with Ecto.Changeset?

I'm fairly certain that I could use Schemaless Changesets? But I'm just curious if anyone has gone down this rabbit hole before, before venturing into the great unknown. Or has had any success with any other solution I may not be thinking of? ✨

Thanks so much.

bryansray commented 3 years ago

Could someone help me understand why we're storing the type information like this?

https://github.com/zookzook/yildun/blob/master/lib/yildun/collection.ex#L661

Here's what I'm trying to accomplish ... in order to use Ecto.Changeset I need to provide it a tuple of {data, types}. Great, this seems easy enough ...

In my collection I've defined this (among other things):

embeds_many :enrollments, Photon.Registrar.Enrollment, default: []

Then I can use the __collection__(:types) to get a list of types that have been defined in the collection. Doing so gives me back a map that looks like this ...

[
  enrollments: {{:., [],
    [
      {:__aliases__, [counter: {Photon.Registrar.Cohort, 14}, line: 28],
       [:Photon, :Registrar, :Enrollment]},
      :t
    ]}, [], []},
  updated_at: :utc_datetime,
  inserted_at: :utc_datetime,
  id: :string,
  _id: {{:., [], [{:__aliases__, [alias: false], [:BSON, :ObjectId]}, :t]}, [],
   []}
]

I'm not quite sure what to do with that enrollments and id key? That appears to be something related to the AST? This is a little outside my wheelhouse, so I'm struggling a bit and hoping someone could help guide me ...

Ultimately, what I think I'm looking for is a map that comes out looking like this:

[
  enrollments: Photon.Registrar.Enrollment,
  updated_at: :utc_datetime,
  inserted_at: :utc_datetime,
  id: :string,
  _id: BSON.ObjectId
]

Am I going about this the wrong way? Or missing something super obvious?

cc @zookzook

zookzook commented 3 years ago

Hi bryansray,

I was curious if anyone has had any success with integrating this library with Ecto.Changeset?

I'm sorry, but I would not integrate this library with Ecto.Changeset, because the Changeset does not work with documents in a really nice way. It is created for rows and tables, but if you try to use embedded documents like maps and arrays it is getting very complicated.

For the most of my use cases I know what elements/attributes I will change, so I don't need to call some cast functions. Validation can be difficult and complex, so you always need to add some custom "cast" function and then, you providing a lot of workaround to get Changeset happy.

zookzook commented 3 years ago

I'm not quite sure what to do with that enrollments and id key? That appears to be something related to the AST? This is a little outside my wheelhouse, so I'm struggling a bit and hoping someone could help guide me ...

It is a long time ago, since I wrote this library, but I try to remember. I guess, the specs are always written for AST. You never use it, it is just for the dializer. (This is a reason, why I don't care about the specs).

The @types is used to generate the code something like

        @type t() :: %Label{String.t(), String.t()}
  @doc """
  Inserts boilercode for the @type attribute.
  """
  defmacro __type__(types) do
    quote bind_quoted: [types: types] do
      @type t() :: %__MODULE__{unquote_splicing(types)}
    end
  end

and therefore it is expressed as AST. But I think, we can add a new function or change it.