{"id":13508749,"url":"https://github.com/coryodaniel/arbor","last_synced_at":"2025-04-12T22:34:30.639Z","repository":{"id":54654870,"uuid":"73030781","full_name":"coryodaniel/arbor","owner":"coryodaniel","description":"Ecto elixir adjacency list and tree traversal. Supports Ecto versions 2 and 3.","archived":false,"fork":false,"pushed_at":"2022-08-27T20:20:40.000Z","size":54,"stargazers_count":239,"open_issues_count":15,"forks_count":25,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-10-13T18:44:54.644Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coryodaniel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["coryodaniel"]}},"created_at":"2016-11-07T01:19:26.000Z","updated_at":"2024-08-04T02:39:06.000Z","dependencies_parsed_at":"2022-08-13T23:00:40.786Z","dependency_job_id":null,"html_url":"https://github.com/coryodaniel/arbor","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coryodaniel%2Farbor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coryodaniel%2Farbor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coryodaniel%2Farbor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coryodaniel%2Farbor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coryodaniel","download_url":"https://codeload.github.com/coryodaniel/arbor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248641804,"owners_count":21138270,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T02:00:57.897Z","updated_at":"2025-04-12T22:34:30.603Z","avatar_url":"https://github.com/coryodaniel.png","language":"Elixir","funding_links":["https://github.com/sponsors/coryodaniel"],"categories":["ORM and Datamapping"],"sub_categories":[],"readme":"# Arbor\n\n[![Build Status](https://travis-ci.org/coryodaniel/arbor.svg)](https://travis-ci.org/coryodaniel/arbor)\n[![Hex Version](http://img.shields.io/hexpm/v/arbor.svg?style=flat)](https://hex.pm/packages/arbor)\n[![Hex docs](http://img.shields.io/badge/hex.pm-docs-green.svg?style=flat)](https://hexdocs.pm/arbor)\n\nEcto adjacency list and tree traversal using CTEs. Arbor uses a `parent_id` field\nand CTEs to create simple deep tree-like SQL hierarchies.\n\n## Installation\n\nIf [available in Hex](https://hex.pm/docs/publish), the package can be installed as:\n\nAdd `arbor` to your list of dependencies in `mix.exs`:\n\nFor Ecto SQL 3+:\n\n```elixir\n  def deps do\n    [{:arbor, \"~\u003e 1.1.0\"}]\n  end\n```\n\nFor Ecto 2:\n\n```elixir\n  def deps do\n    [{:arbor, \"~\u003e 1.0.6\"}]\n  end\n```\n\n\n## Benchmarks\n\nArbor has been [benchmarked](https://github.com/coryodaniel/arbor_bench) on 10mm+ record tables with efficient results:\n\n10,000,000 rows, 25% root\n```\nRunning siblings\n\t10000 runs\n\tTotal time: 1.793026000000013\n\tAvg: 1.7930260000000131e-4\nRunning children\n\t10000 runs\n\tTotal time: 1.5967949999999786\n\tAvg: 1.5967949999999787e-4\nRunning descendants\n\t10000 runs\n\tTotal time: 2.5418830000000012\n\tAvg: 2.5418830000000013e-4\nRunning ancestors\n\t10000 runs\n\tTotal time: 2.87076499999998\n\tAvg: 2.87076499999998e-4\n```\n\n## Usage\n\n```elixir\ndefmodule Comment do\n  use Ecto.Schema\n  # See config options below\n  use Arbor.Tree, foreign_key_type: :binary_id\n\n  schema \"comments\" do\n    field :body, :string\n    belongs_to :parent, __MODULE__\n\n    timestamps\n  end\nend\n```\n\nAll methods return composable Ecto queries. For in depth examples see the [tests](./test/arbor)\n\n### Roots\n\nReturns root level records.\n\n```elixir\nroots = Comment.roots\n        |\u003e Repo.all\n```\n\n\n### Siblings\n\nReturn the siblings of a record.\n\n```elixir\nsiblings = my_comment\n           |\u003e Comment.siblings\n           |\u003e Comment.order_by_popularity\n           |\u003e Repo.all\n```\n\n### ancestors\n\nReturns the entire ancestor (parent's parent's parent, etc) path to the record, but not including the record.\n\n```elixir\nancestors = my_comment\n              |\u003e Comment.ancestors\n              |\u003e Comment.order_by_inserted_at\n              |\u003e Repo.all\n```\n\n\n### Descendants\n\nReturns the entire descendant tree of a record, but not including the record.\n\n```elixir\ndescendants = my_comment\n              |\u003e Comment.descendants\n              |\u003e Comment.order_by_inserted_at\n              |\u003e Repo.all\n```\n\nA second parameter can be passed to `descendants` to specify how deep\nfrom the root of the tree to retrieve the descendants from.\n\n```elixir\ndescendants = my_comment\n              |\u003e Comment.descendants(2)\n              |\u003e Comment.order_by_inserted_at\n              |\u003e Repo.all\n```\n\n### Children\n\nReturns the immediate children of a record.\n\n```elixir\nchildren = my_comment\n           |\u003e Comment.children\n           |\u003e Repo.all\n```\n\n### Parent\n\nReturns the record's parent.\n\n```elixir\nparent = my_comment\n         |\u003e Comment.parent\n         |\u003e Repo.first\n```\n\n## Options\n\n* *table_name* - set the table name to use in [CTEs](https://www.postgresql.org/docs/9.1/static/queries-with.html)\n* *tree_name* - set the name of the CTE\n* *primary_key* - defaults to field from Ecto's `@primary_key`\n* *primary_key_type* - defaults to type from Ecto's `@primary_key`\n* *foreign_key* - defauts to `:parent_id`\n* *foreign_key_type* - defaults to type from Ecto's `@primary_key`\n* *orphan_strategy* - defaults to `:nothing` currently unimplemented\n\n## Contributing\n\nYou'll need PostgreSQL installed and a user that can create and drop databases.\n\nThere is a docker-compose file for your convienence.\n\nYou can specify it with the environment variable `ARBOR_DB_USER`.\n\nThe `mix test` task will drop and create the database for each run.\n\n```shell\ndocker-compose up -d\nARBOR_DB_USER=postgres mix test\ndocker-compose down\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoryodaniel%2Farbor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoryodaniel%2Farbor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoryodaniel%2Farbor/lists"}