{"action":"created","comment":{"url":"https://api.github.com/repos/elixir-ecto/ecto/pulls/comments/89461193","pull_request_review_id":10005890,"id":89461193,"diff_hunk":"@@ -0,0 +1,604 @@\n+# Ecto Association Guide\n+This guide assumes you worked through the \"getting started\" guide and want to learn more about associations.\n+\n+With ecto (like every other DB layer) you can associate schemas with other schemas.\n+\n+There are three kinds of associations\n+- one-to-one,\n+- one-to-many,and\n+- many-to-many.\n+\n+In this tutorial we're going to create a minimal ecto project\n+(similar to the getting started guide),\n+then we're going to create basic schemas and migrations,\n+and finally associate the schemas.\n+\n+\n+## Ecto Setup\n+First, we're going to create a basic ecto project which is going to be used for\n+the rest of the tutorial.\n+Note, the steps are taken from the getting started guide.\n+You can also clone the project from TODO.\n+\n+Let's create a new project.\n+```\n+$ mix new ecto_assoc --sup\n+```\n+\n+Add `ecto` and `postgrex` as dependencies to `mix.exs` and add them to our\n+application:\n+```\n+# mix.exs\n+# ...\n+def application do\n+  [applications: [:logger, :ecto, :postgrex],\n+   mod: {EctoAssoc, []}]\n+end\n+\n+defp deps do\n+  [{:ecto, \"~> 2.0\"},\n+   {:postgrex, \"~> 0.11\"}]\n+end\n+```\n+\n+Let's generate a repo and create the corresponding DB.\n+```\n+mix ecto.gen.repo -r EctoAssoc.Repo\n+```\n+\n+Make sure the config for the repo is set properly:\n+```\n+# config/config.exs\n+config :ecto_assoc, EctoAssoc.Repo,\n+  adapter: Ecto.Adapters.Postgres,\n+  database: \"ecto_assoc_repo\",\n+  username: \"postgres\",\n+  password: \"postgres\",\n+  hostname: \"localhost\"\n+\n+config :ecto_assoc, ecto_repos: [EctoAssoc.Repo]\n+```\n+\n+Add the repo to the supervision tree:\n+```elixir\n+  def start(_type, _args) do\n+    import Supervisor.Spec, warn: false\n+    children = [\n+      worker(EctoAssoc.Repo, [])\n+    ]\n+    ...\n+```\n+\n+Finally let's create the DB:\n+```\n+$ mix ecto.create\n+$ iex -S mix\n+```\n+\n+## One-to-one\n+### Prep\n+Let's assume we have two schemas: User and Avatar.\n+\n+The schemas and corresponding migrations look like this:\n+```elixir\n+# create a migration: mix ecto.gen.migration create_user\n+# priv/repo/migrations/*_create_user.exs\n+defmodule EctoAssoc.Repo.Migrations.CreateUser do\n+  use Ecto.Migration\n+\n+  def change do\n+    create table(:users) do\n+      add :name, :string\n+      add :email, :string\n+    end\n+  end\n+end\n+```\n+\n+```elixir\n+# lib/ecto_assoc/user.ex\n+defmodule EctoAssoc.User do\n+  use Ecto.Schema\n+\n+  schema \"users\" do\n+    field :name, :string\n+    field :email, :string\n+  end\n+end\n+```\n+\n+```elixir\n+# create a migration: mix ecto.gen.migration create_avatar\n+# priv/repo/migrations/*_create_avatar.exs\n+defmodule EctoAssoc.Repo.Migrations.CreateAvatar do\n+  use Ecto.Migration\n+\n+  def change do\n+    create table(:avatars) do\n+      add :nick_name, :string\n+      add :pic_url, :string\n+    end\n+  end\n+end\n+```\n+\n+```elixir\n+# lib/ecto_assoc/avatar.ex\n+defmodule EctoAssoc.Avatar do\n+  use Ecto.Schema\n+\n+  schema \"avatars\" do\n+    field :nick_name, :string\n+    field :pic_url, :string\n+  end\n+end\n+```\n+\n+### Adding Associations\n+Now we want to associate the user with the avatar and vice versa:\n+- one user has one avatar\n+- one avatar belongs to one user\n+\n+For the *avatar* we create a migration that adds a `user_id` reference.\n+```elixir\n+# priv/repo/migrations/20161117101812_avatar_belongs_to_user.exs\n+defmodule EctoAssoc.Repo.Migrations.AvatarBelongsToUser do\n+  use Ecto.Migration\n+\n+  def change do\n+    alter table(:avatars) do\n+      add :user_id, references(:users)\n+    end\n+  end\n+end\n+```\n+This adds a `user_id` column to the DB which refecences an entry in the users table.\n+\n+For the *avatar* we add a `belongs_to` field to the schema\n+```elixir\n+defmodule EctoAssoc.Avatar do\n+  schema \"avatars\" do\n+    field :nick_name, :string\n+    field :pic_url, :string\n+    belongs_to :user, EctoAssoc.User  # this was added\n+  end\n+end\n+```\n+`belongs_to` is a macro which uses a foreign key (in this case `user_id`) to make the associated schema accessible through the avatar, i.e., you can access the user via `avatar.user`.\n+\n+For the *user* we add a `has_one` field to the schema\n+```elixir\n+# lib/ecto_assoc/user.ex\n+defmodule EctoAssoc.User do\n+  schema \"users\" do\n+    field :name, :string\n+    field :email, :string\n+    has_one :avatar, EctoAssoc.Avatar  # this was added\n+  end\n+end\n+```\n+`has_one` does not add anything to the DB.\n+The foreign key of the associated schema, `Avatar`, is used to make the avatar available from the user, i.e., you can access the avatar via `user.avatar`.\n+\n+### Persistence\n+Now let's add data to the DB.\n+Start iex:\n+```\n+$ iex -S mix\n+```\n+\n+For convenience we alias some modules:\n+```elixir\n+iex(1)> alias EctoAssoc.Repo\n+EctoAssoc.Repo\n+iex(2)> alias EctoAssoc.User\n+EctoAssoc.User\n+iex(3)> alias EctoAssoc.Avatar\n+EctoAssoc.Avatar\n+```\n+\n+Create a user changeset and insert it into the repo:\n+```elixir\n+iex(5)> user_cs = %User{} |> Ecto.Changeset.cast(%{name: \"John Doe\", email: \"johan@example.com\"}, [:name, :email])\n+#Ecto.Changeset<action: nil,\n+ changes: %{email: \"johan@example.com\", name: \"John Doe\"}, errors: [],\n+ data: #EctoAssoc.User<>, valid?: true>\n+\n+iex(6)> user = Repo.insert!(user_cs)\n+%EctoAssoc.User{__meta__: #Ecto.Schema.Metadata<:loaded, \"users\">,\n+ avatar: #Ecto.Association.NotLoaded<association :avatar is not loaded>,\n+ email: \"johan@example.com\", id: 3, name: \"John Doe\"}\n+```\n+\n+This time let's add another user with an avatar association. We use `Ecto.Changeset.put_assoc` for this.\n+```elixir\n+iex(7)> user_cs = %User{} |> Ecto.Changeset.cast(%{name: \"Jane Doe\", email: \"jane@example.com\"}, [:name, :email]) |> Ecto.Changeset.put_assoc(:avatar, %{nick_name: \"EctOr\", pick_url: \"http://elixir-lang.org/images/logo/logo.png\"})\n+#Ecto.Changeset<action: nil,\n+ changes: %{avatar: #Ecto.Changeset<action: :insert,\n+    changes: %{nick_name: \"EctOr\",\n+      pick_url: \"http://elixir-lang.org/images/logo/logo.png\"}, errors: [],\n+    data: #EctoAssoc.Avatar<>, valid?: true>, email: \"jane@example.com\",\n+   name: \"Jane Doe\"}, errors: [], data: #EctoAssoc.User<>, valid?: true>\n+\n+iex(8)> user = Repo.insert!(user_cs)\n+%EctoAssoc.User{__meta__: #Ecto.Schema.Metadata<:loaded, \"users\">,\n+ avatar: %{__meta__: #Ecto.Schema.Metadata<:loaded, \"avatars\">,\n+   __struct__: EctoAssoc.Avatar, id: 2, nick_name: \"EctOr\", pic_url: nil,\n+   pick_url: \"http://elixir-lang.org/images/logo/logo.png\",\n+   user: #Ecto.Association.NotLoaded<association :user is not loaded>,\n+   user_id: 4}, email: \"jane@example.com\", id: 4, name: \"Jane Doe\"}\n+```\n+\n+Let's verify that it works by retrieving all Users and their associated avatars:\n+```elixir\n+iex(9)> Repo.all(User) |> Repo.preload(:avatar)\n+[%EctoAssoc.User{__meta__: #Ecto.Schema.Metadata<:loaded, \"users\">, avatar: nil,\n+  email: \"johan@example.com\", id: 3, name: \"John Doe\"},\n+ %EctoAssoc.User{__meta__: #Ecto.Schema.Metadata<:loaded, \"users\">,\n+  avatar: %EctoAssoc.Avatar{__meta__: #Ecto.Schema.Metadata<:loaded, \"avatars\">,\n+   id: 2, nick_name: \"EctOr\", pic_url: nil,\n+   user: #Ecto.Association.NotLoaded<association :user is not loaded>,\n+   user_id: 4}, email: \"jane@example.com\", id: 4, name: \"Jane Doe\"}]\n+```\n+\n+## Many-to-one\n+### Prep\n+Let's assume we have two schemas: `User` and `Post`.\n+\n+The schamas and corresponding migrations look like this:\n+```elixir\n+# lib/ecto_assoc/user.ex\n+defmodule EctoAssoc.User do\n+  use Ecto.Schema\n+\n+  schema \"users\" do\n+    field :name, :string\n+    field :email, :string\n+  end\n+end\n+```\n+\n+```elixir\n+# create a migration: mix ecto.gen.migration create_user\n+# priv/repo/migrations/*_create_user.exs\n+defmodule EctoAssoc.Repo.Migrations.CreateUser do\n+  use Ecto.Migration\n+\n+  def change do\n+    create table(:users) do\n+      add :name, :string\n+      add :email, :string\n+    end\n+  end\n+end\n+```\n+\n+```elixir\n+# lib/ecto_assoc/post.ex\n+defmodule EctoAssoc.Post do\n+  use Ecto.Schema\n+\n+  schema \"posts\" do\n+    field :header, :string\n+    field :body, :string\n+  end\n+end\n+\n+```\n+\n+```elixir\n+# create a migration: mix ecto.gen.migration create_post\n+# priv/repo/migrations/*_create_post.exs\n+defmodule EctoAssoc.Repo.Migrations.CreatePost do\n+  use Ecto.Migration\n+\n+  def change do\n+    create table(:posts) do\n+      add :header, :string\n+      add :body, :string\n+    end\n+  end\n+end\n+```\n+\n+\n+### Adding Associations\n+Now we want to associate the user with the post and vice versa:\n+- one user has many post\n+- one post belongs to one user\n+\n+For the *post* we\n+- create a migration that adds the `user_id` reference\n+- add a `belongs_to` field to the schema\n+\n+TODO add listing\n+\n+For the *user* we\n+- add a `has_many` field to the schema\n+\n+TODO add listing\n+\n+### Persistence\n+```elixir\n+iex(1)> alias EctoAssoc.Repo\n+EctoAssoc.Repo\n+\n+iex(2)> alias EctoAssoc.User\n+EctoAssoc.User\n+\n+iex(3)> alias EctoAssoc.Post\n+EctoAssoc.Post\n+```\n+\n+```\n+iex(6)> user_cs = %User{} |> Ecto.Changeset.cast(%{name: \"John Doe\", email: \"johan@example.com\"}, [:name, :email])\n+#Ecto.Changeset<action: nil,\n+ changes: %{email: \"johan@example.com\", name: \"John Doe\"}, errors: [],\n+ data: #EctoAssoc.User<>, valid?: true>\n+\n+iex(7)> user = Repo.insert!(user_cs)\n+14:33:35.513 [debug] QUERY OK db=0.3ms queue=0.1ms\n+begin []\n+14:33:35.534 [debug] QUERY OK db=4.6ms\n+INSERT INTO \"users\" (\"email\",\"name\") VALUES ($1,$2) RETURNING \"id\" [\"johan@example.com\", \"John Doe\"]\n+14:33:35.535 [debug] QUERY OK db=1.2ms\n+commit []\n+%EctoAssoc.User{__meta__: #Ecto.Schema.Metadata<:loaded, \"users\">,\n+ email: \"johan@example.com\", id: 1, name: \"John Doe\",\n+ posts: #Ecto.Association.NotLoaded<association :posts is not loaded>}\n+```\n+\n+```\n+iex(6)> post_cs = Ecto.build_assoc(user, :posts, %{header: \"Clickbait header\", body: \"No real content\"})\n+%EctoAssoc.Post{__meta__: #Ecto.Schema.Metadata<:built, \"posts\">,\n+ body: \"No real content\", header: \"Clickbait header\", id: nil,\n+ user: #Ecto.Association.NotLoaded<association :user is not loaded>, user_id: 1}\n+\n+iex(7)> post = Repo.insert!(post_cs)\n+14:54:28.193 [debug] QUERY OK db=0.3ms\n+begin []\n+14:54:28.197 [debug] QUERY OK db=2.9ms\n+INSERT INTO \"posts\" (\"body\",\"header\",\"user_id\") VALUES ($1,$2,$3) RETURNING \"id\" [\"No real content\", \"Clickbait header\", 1]\n+14:54:28.199 [debug] QUERY OK db=2.6ms\n+commit []\n+%EctoAssoc.Post{__meta__: #Ecto.Schema.Metadata<:loaded, \"posts\">,\n+ body: \"No real content\", header: \"Clickbait header\", id: 1,\n+ user: #Ecto.Association.NotLoaded<association :user is not loaded>, user_id: 1}\n+```\n+\n+Let's add another one.\n+```\n+iex(8)> post = Ecto.build_assoc(user, :posts, %{header: \"5 ways to improve your Ecto\", body: \"TODO add url of this tutorial\"}) |> Repo.insert!()\n+14:56:45.571 [debug] QUERY OK db=0.4ms queue=0.1ms\n+begin []\n+14:56:45.573 [debug] QUERY OK db=2.2ms\n+INSERT INTO \"posts\" (\"body\",\"header\",\"user_id\") VALUES ($1,$2,$3) RETURNING \"id\" [\"TODO add url of this tutorial\", \"5 ways to improve your Ecto\", 1]","path":"guides/Associations.md","position":376,"original_position":375,"commit_id":"4c0d48091fd7f8aa99500e7e9736d987bfddea5d","original_commit_id":"bd1b8f2da5579366e7209486cef281b520dac297","user":{"login":"elixir-bot","id":23316919,"avatar_url":"https://avatars.githubusercontent.com/u/23316919?v=3","gravatar_id":"","url":"https://api.github.com/users/elixir-bot","html_url":"https://github.com/elixir-bot","followers_url":"https://api.github.com/users/elixir-bot/followers","following_url":"https://api.github.com/users/elixir-bot/following{/other_user}","gists_url":"https://api.github.com/users/elixir-bot/gists{/gist_id}","starred_url":"https://api.github.com/users/elixir-bot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elixir-bot/subscriptions","organizations_url":"https://api.github.com/users/elixir-bot/orgs","repos_url":"https://api.github.com/users/elixir-bot/repos","events_url":"https://api.github.com/users/elixir-bot/events{/privacy}","received_events_url":"https://api.github.com/users/elixir-bot/received_events","type":"User","site_admin":false},"body":"TODO found","created_at":"2016-11-24T09:33:06Z","updated_at":"2016-11-24T09:33:06Z","html_url":"https://github.com/elixir-ecto/ecto/pull/1811#discussion_r89461193","pull_request_url":"https://api.github.com/repos/elixir-ecto/ecto/pulls/1811","_links":{"self":{"href":"https://api.github.com/repos/elixir-ecto/ecto/pulls/comments/89461193"},"html":{"href":"https://github.com/elixir-ecto/ecto/pull/1811#discussion_r89461193"},"pull_request":{"href":"https://api.github.com/repos/elixir-ecto/ecto/pulls/1811"}}},"pull_request":{"url":"https://api.github.com/repos/elixir-ecto/ecto/pulls/1811","id":94481705,"html_url":"https://github.com/elixir-ecto/ecto/pull/1811","diff_url":"https://github.com/elixir-ecto/ecto/pull/1811.diff","patch_url":"https://github.com/elixir-ecto/ecto/pull/1811.patch","issue_url":"https://api.github.com/repos/elixir-ecto/ecto/issues/1811","number":1811,"state":"open","locked":false,"title":"WIP: ecto association guide [DRAFT]","user":{"login":"sotte","id":79138,"avatar_url":"https://avatars.githubusercontent.com/u/79138?v=3","gravatar_id":"","url":"https://api.github.com/users/sotte","html_url":"https://github.com/sotte","followers_url":"https://api.github.com/users/sotte/followers","following_url":"https://api.github.com/users/sotte/following{/other_user}","gists_url":"https://api.github.com/users/sotte/gists{/gist_id}","starred_url":"https://api.github.com/users/sotte/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sotte/subscriptions","organizations_url":"https://api.github.com/users/sotte/orgs","repos_url":"https://api.github.com/users/sotte/repos","events_url":"https://api.github.com/users/sotte/events{/privacy}","received_events_url":"https://api.github.com/users/sotte/received_events","type":"User","site_admin":false},"body":"This PR will add an association guide to the docs.\r\n\r\nThe PR is the result of [this](https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/elixir-ecto/sP3-U9SeTt8/4JC925SLBgAJ) discursion.\r\n\r\n- [ ] Finish the one-to-one section (which basically defines the format for the following section)\r\n- [ ] many-to-one\r\n- [ ] many-to-many\r\n\r\nWe should also decide what we do with the associated project\r\n- add it to the ecto repo\r\n- keep it separate (but maybe add it to the ecto-elixir organisation)\r\n\r\n\r\n\r\nThe following is c&p from the mailing list:\r\n\r\nI have a little teaching project which (semi) systematically explains and implements the different associations and how Ecto deals with it (schema and migrations).\r\n\r\nNow I'm thinking this could be a nice addition to the Ecto docs, similar to the \"getting started\" guide. \"Narrative docs\" are really missing, I think.\r\n\r\nI hastily copied together some of my notes, some code, an iex session, and parts of the git log to create a (*very* rough) draft of what the guide could be. I just want to get some feedback before I actually spend time doing this. So let me know what you think! Should we have something like this?\r\n\r\nThis is the DRAFT of the guide: https://gist.github.com/sotte/9c4950e2cd479bfc5ff1e68fde19e198\r\nEach section for a given association could look something like this (only one-to-one has some content right now)\r\n- Prep\r\n- Adding Associations\r\n- Persistence\r\n\r\n\r\nThis is the corresponding project: https://github.com/sotte/ecto_assoc_demo\r\n\r\nThere are 4 branches:\r\n- master: some basic setup\r\n- one-to-one: implements one-to-one associations\r\n- one-to-many: implements one-to-many associations\r\n- many-to-many: implements many-to-many associations\r\n\r\nThe commit history is fairly clean and just looking at the commit and the patch shows you what happens:\r\n```\r\ngit checkout one-to-one\r\ngit log --reverse -4 --patch\r\n```\r\n","created_at":"2016-11-19T13:23:06Z","updated_at":"2016-11-24T09:33:06Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c5c55022d2124137f424f96c0bf24c76e5e64cae","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/elixir-ecto/ecto/pulls/1811/commits","review_comments_url":"https://api.github.com/repos/elixir-ecto/ecto/pulls/1811/comments","review_comment_url":"https://api.github.com/repos/elixir-ecto/ecto/pulls/comments{/number}","comments_url":"https://api.github.com/repos/elixir-ecto/ecto/issues/1811/comments","statuses_url":"https://api.github.com/repos/elixir-ecto/ecto/statuses/4c0d48091fd7f8aa99500e7e9736d987bfddea5d","head":{"label":"sotte:association_guide","ref":"association_guide","sha":"4c0d48091fd7f8aa99500e7e9736d987bfddea5d","user":{"login":"sotte","id":79138,"avatar_url":"https://avatars.githubusercontent.com/u/79138?v=3","gravatar_id":"","url":"https://api.github.com/users/sotte","html_url":"https://github.com/sotte","followers_url":"https://api.github.com/users/sotte/followers","following_url":"https://api.github.com/users/sotte/following{/other_user}","gists_url":"https://api.github.com/users/sotte/gists{/gist_id}","starred_url":"https://api.github.com/users/sotte/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sotte/subscriptions","organizations_url":"https://api.github.com/users/sotte/orgs","repos_url":"https://api.github.com/users/sotte/repos","events_url":"https://api.github.com/users/sotte/events{/privacy}","received_events_url":"https://api.github.com/users/sotte/received_events","type":"User","site_admin":false},"repo":{"id":73932009,"name":"ecto","full_name":"sotte/ecto","owner":{"login":"sotte","id":79138,"avatar_url":"https://avatars.githubusercontent.com/u/79138?v=3","gravatar_id":"","url":"https://api.github.com/users/sotte","html_url":"https://github.com/sotte","followers_url":"https://api.github.com/users/sotte/followers","following_url":"https://api.github.com/users/sotte/following{/other_user}","gists_url":"https://api.github.com/users/sotte/gists{/gist_id}","starred_url":"https://api.github.com/users/sotte/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sotte/subscriptions","organizations_url":"https://api.github.com/users/sotte/orgs","repos_url":"https://api.github.com/users/sotte/repos","events_url":"https://api.github.com/users/sotte/events{/privacy}","received_events_url":"https://api.github.com/users/sotte/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/sotte/ecto","description":"A database wrapper and language integrated query for Elixir","fork":true,"url":"https://api.github.com/repos/sotte/ecto","forks_url":"https://api.github.com/repos/sotte/ecto/forks","keys_url":"https://api.github.com/repos/sotte/ecto/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sotte/ecto/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sotte/ecto/teams","hooks_url":"https://api.github.com/repos/sotte/ecto/hooks","issue_events_url":"https://api.github.com/repos/sotte/ecto/issues/events{/number}","events_url":"https://api.github.com/repos/sotte/ecto/events","assignees_url":"https://api.github.com/repos/sotte/ecto/assignees{/user}","branches_url":"https://api.github.com/repos/sotte/ecto/branches{/branch}","tags_url":"https://api.github.com/repos/sotte/ecto/tags","blobs_url":"https://api.github.com/repos/sotte/ecto/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sotte/ecto/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sotte/ecto/git/refs{/sha}","trees_url":"https://api.github.com/repos/sotte/ecto/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sotte/ecto/statuses/{sha}","languages_url":"https://api.github.com/repos/sotte/ecto/languages","stargazers_url":"https://api.github.com/repos/sotte/ecto/stargazers","contributors_url":"https://api.github.com/repos/sotte/ecto/contributors","subscribers_url":"https://api.github.com/repos/sotte/ecto/subscribers","subscription_url":"https://api.github.com/repos/sotte/ecto/subscription","commits_url":"https://api.github.com/repos/sotte/ecto/commits{/sha}","git_commits_url":"https://api.github.com/repos/sotte/ecto/git/commits{/sha}","comments_url":"https://api.github.com/repos/sotte/ecto/comments{/number}","issue_comment_url":"https://api.github.com/repos/sotte/ecto/issues/comments{/number}","contents_url":"https://api.github.com/repos/sotte/ecto/contents/{+path}","compare_url":"https://api.github.com/repos/sotte/ecto/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sotte/ecto/merges","archive_url":"https://api.github.com/repos/sotte/ecto/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sotte/ecto/downloads","issues_url":"https://api.github.com/repos/sotte/ecto/issues{/number}","pulls_url":"https://api.github.com/repos/sotte/ecto/pulls{/number}","milestones_url":"https://api.github.com/repos/sotte/ecto/milestones{/number}","notifications_url":"https://api.github.com/repos/sotte/ecto/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sotte/ecto/labels{/name}","releases_url":"https://api.github.com/repos/sotte/ecto/releases{/id}","deployments_url":"https://api.github.com/repos/sotte/ecto/deployments","created_at":"2016-11-16T15:17:42Z","updated_at":"2016-11-16T15:17:43Z","pushed_at":"2016-11-24T09:32:35Z","git_url":"git://github.com/sotte/ecto.git","ssh_url":"git@github.com:sotte/ecto.git","clone_url":"https://github.com/sotte/ecto.git","svn_url":"https://github.com/sotte/ecto","homepage":"https://hexdocs.pm/ecto","size":8492,"stargazers_count":0,"watchers_count":0,"language":"Elixir","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"elixir-ecto:master","ref":"master","sha":"2e9e0afaea1864260a29b66054020b2606679e85","user":{"login":"elixir-ecto","id":19973437,"avatar_url":"https://avatars.githubusercontent.com/u/19973437?v=3","gravatar_id":"","url":"https://api.github.com/users/elixir-ecto","html_url":"https://github.com/elixir-ecto","followers_url":"https://api.github.com/users/elixir-ecto/followers","following_url":"https://api.github.com/users/elixir-ecto/following{/other_user}","gists_url":"https://api.github.com/users/elixir-ecto/gists{/gist_id}","starred_url":"https://api.github.com/users/elixir-ecto/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elixir-ecto/subscriptions","organizations_url":"https://api.github.com/users/elixir-ecto/orgs","repos_url":"https://api.github.com/users/elixir-ecto/repos","events_url":"https://api.github.com/users/elixir-ecto/events{/privacy}","received_events_url":"https://api.github.com/users/elixir-ecto/received_events","type":"Organization","site_admin":false},"repo":{"id":10649374,"name":"ecto","full_name":"elixir-ecto/ecto","owner":{"login":"elixir-ecto","id":19973437,"avatar_url":"https://avatars.githubusercontent.com/u/19973437?v=3","gravatar_id":"","url":"https://api.github.com/users/elixir-ecto","html_url":"https://github.com/elixir-ecto","followers_url":"https://api.github.com/users/elixir-ecto/followers","following_url":"https://api.github.com/users/elixir-ecto/following{/other_user}","gists_url":"https://api.github.com/users/elixir-ecto/gists{/gist_id}","starred_url":"https://api.github.com/users/elixir-ecto/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elixir-ecto/subscriptions","organizations_url":"https://api.github.com/users/elixir-ecto/orgs","repos_url":"https://api.github.com/users/elixir-ecto/repos","events_url":"https://api.github.com/users/elixir-ecto/events{/privacy}","received_events_url":"https://api.github.com/users/elixir-ecto/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/elixir-ecto/ecto","description":"A database wrapper and language integrated query for Elixir","fork":false,"url":"https://api.github.com/repos/elixir-ecto/ecto","forks_url":"https://api.github.com/repos/elixir-ecto/ecto/forks","keys_url":"https://api.github.com/repos/elixir-ecto/ecto/keys{/key_id}","collaborators_url":"https://api.github.com/repos/elixir-ecto/ecto/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/elixir-ecto/ecto/teams","hooks_url":"https://api.github.com/repos/elixir-ecto/ecto/hooks","issue_events_url":"https://api.github.com/repos/elixir-ecto/ecto/issues/events{/number}","events_url":"https://api.github.com/repos/elixir-ecto/ecto/events","assignees_url":"https://api.github.com/repos/elixir-ecto/ecto/assignees{/user}","branches_url":"https://api.github.com/repos/elixir-ecto/ecto/branches{/branch}","tags_url":"https://api.github.com/repos/elixir-ecto/ecto/tags","blobs_url":"https://api.github.com/repos/elixir-ecto/ecto/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/elixir-ecto/ecto/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/elixir-ecto/ecto/git/refs{/sha}","trees_url":"https://api.github.com/repos/elixir-ecto/ecto/git/trees{/sha}","statuses_url":"https://api.github.com/repos/elixir-ecto/ecto/statuses/{sha}","languages_url":"https://api.github.com/repos/elixir-ecto/ecto/languages","stargazers_url":"https://api.github.com/repos/elixir-ecto/ecto/stargazers","contributors_url":"https://api.github.com/repos/elixir-ecto/ecto/contributors","subscribers_url":"https://api.github.com/repos/elixir-ecto/ecto/subscribers","subscription_url":"https://api.github.com/repos/elixir-ecto/ecto/subscription","commits_url":"https://api.github.com/repos/elixir-ecto/ecto/commits{/sha}","git_commits_url":"https://api.github.com/repos/elixir-ecto/ecto/git/commits{/sha}","comments_url":"https://api.github.com/repos/elixir-ecto/ecto/comments{/number}","issue_comment_url":"https://api.github.com/repos/elixir-ecto/ecto/issues/comments{/number}","contents_url":"https://api.github.com/repos/elixir-ecto/ecto/contents/{+path}","compare_url":"https://api.github.com/repos/elixir-ecto/ecto/compare/{base}...{head}","merges_url":"https://api.github.com/repos/elixir-ecto/ecto/merges","archive_url":"https://api.github.com/repos/elixir-ecto/ecto/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/elixir-ecto/ecto/downloads","issues_url":"https://api.github.com/repos/elixir-ecto/ecto/issues{/number}","pulls_url":"https://api.github.com/repos/elixir-ecto/ecto/pulls{/number}","milestones_url":"https://api.github.com/repos/elixir-ecto/ecto/milestones{/number}","notifications_url":"https://api.github.com/repos/elixir-ecto/ecto/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/elixir-ecto/ecto/labels{/name}","releases_url":"https://api.github.com/repos/elixir-ecto/ecto/releases{/id}","deployments_url":"https://api.github.com/repos/elixir-ecto/ecto/deployments","created_at":"2013-06-12T18:42:06Z","updated_at":"2016-11-23T22:53:01Z","pushed_at":"2016-11-24T09:32:35Z","git_url":"git://github.com/elixir-ecto/ecto.git","ssh_url":"git@github.com:elixir-ecto/ecto.git","clone_url":"https://github.com/elixir-ecto/ecto.git","svn_url":"https://github.com/elixir-ecto/ecto","homepage":"https://hexdocs.pm/ecto","size":9834,"stargazers_count":2257,"watchers_count":2257,"language":"Elixir","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":535,"mirror_url":null,"open_issues_count":14,"forks":535,"open_issues":14,"watchers":2257,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/elixir-ecto/ecto/pulls/1811"},"html":{"href":"https://github.com/elixir-ecto/ecto/pull/1811"},"issue":{"href":"https://api.github.com/repos/elixir-ecto/ecto/issues/1811"},"comments":{"href":"https://api.github.com/repos/elixir-ecto/ecto/issues/1811/comments"},"review_comments":{"href":"https://api.github.com/repos/elixir-ecto/ecto/pulls/1811/comments"},"review_comment":{"href":"https://api.github.com/repos/elixir-ecto/ecto/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/elixir-ecto/ecto/pulls/1811/commits"},"statuses":{"href":"https://api.github.com/repos/elixir-ecto/ecto/statuses/4c0d48091fd7f8aa99500e7e9736d987bfddea5d"}}}}
{"actor":{"display_login":"elixir-bot"}}