Open flaviogranero opened 8 years ago
So, I'm thinking in adding support for has_many
, has_one
and belongs_to
.
Here's a draft of the api.
The Dayron.Model will now support the has_many
, has_one
and belongs_to
keys.
The value of this keys would be keyword lists
defmodule MyApp.User do
# api requests to http://api.example.com/users
use Dayron.Model, resource: "users", has_many: comments: Comment
# struct defining model attributes
defstruct name: "", age: 0
end
defmodule MyApp.Comment do
use Dayron.Model, resource: "comments", belongs_to: user: MyApp.User
defstruct text: ""
end
Support for the ecto schema will still be the same
defmodule MyApp.User do
use Ecto.Schema
use Dayron.Model
schema "users" do
field :name, :string
field :age, :integer, default: 0
has_many :comments, MyApp.Comment
end
end
defmodule MyApp.Comment do
use Ecto.Schema
use Dayron.Model
schema "comments" do
field :text, :string
belongs_to: :user, MyApp.User
end
end
And the api will be used like this:
RestRepo.all(post, :comments) # => get users/:id/comments
RestRepo.get(post, :comments, comment_id) #=> get users/:id/comments/:comment_id
RestRepo.update!(post, :comments, comment_id, comment_params) # => put users/:id/comments
RestRepo.insert!(post, :comments, comments_params) #=> post users/:id/comments
RestRepo.delete!(post, :comments, comment_id) #=> delete users/:id/comments/:id
For now I'm not planing to suport nested preloads
like RestRepo.get(post, [:comments, :attachments], comment_id)
but this can be added in the future.
Also, if the json response already have the relationships, it will be parsed normally.
GET users/1
{id: 1, name: "john doe", comments: {id: 1, text: "that's a comment"}}
The Post
returned by this get
will have the comment property already loaded.
In this case I'm thinking in adding the RestRepo.assoc_loaded?(post, :comments)
so
the user can check this before sending another request.
What do you think?
Thinking a little bit better, I think #43 and #44 should be done before this because for this to work we will need to support data mapping for ecto relationships.
@tiagoengel I like your proposal, and also agree with other tasks dependencies. It's a good plan to check Ecto 2 changes before going with this.
My initial idea for supporting relationships was to mimic the ecto relationships. This way it will be easy to maintain the support for ecto models.
The idea is to have the same functions ecto have to check the relationships.
__schema__(:associations)
returns all association names.
__schema__(:association, name)
returns the association reflection.
I actually implemented those functions (without the reflections), you can take a look here.
An association reflection in ecto looks like this:
# BelongsTo
%Ecto.Association.BelongsTo{cardinality: :one, defaults: [], field: :company,
on_cast: nil, on_replace: :raise, owner: App.Activity,
owner_key: :company_id, queryable: App.Company,
related: App.Company, related_key: :id, relationship: :parent}
# HasOne
%Ecto.Association.Has{cardinality: :one, defaults: [], field: :department,
on_cast: nil, on_delete: :nothing, on_replace: :raise,
owner: App.Activity, owner_key: :id,
queryable: App.Department, related: App.Department,
related_key: :activity_id, relationship: :child}
# HasMany
%Ecto.Association.Has{cardinality: :many, defaults: [],
field: :product_activities, on_cast: nil, on_delete: :nothing,
on_replace: :raise, owner: App.Activity, owner_key: :id,
queryable: App.ProductActivity, related: App.ProductActivity,
related_key: :activity_id, relationship: :child}
We don't need to add all these fields only the ones dayron needs
Ecto also have the Ecto.Association.NotLoaded
module to indicate an association
is not loaded.
Having all this information about the associations I think we can easily parse the relationships.
Maybe adding a method build
in every Model
that will first build the associations if they're present
and only after that call the struct
method.
If we add support for all this I think adding the api to fetch associations will be straightforward.
Dayron needs to support requests to nested resources, such as
/posts/:id/comments