Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/coryodaniel/arbor
Ecto elixir adjacency list and tree traversal. Supports Ecto versions 2 and 3.
https://github.com/coryodaniel/arbor
Last synced: 6 days ago
JSON representation
Ecto elixir adjacency list and tree traversal. Supports Ecto versions 2 and 3.
- Host: GitHub
- URL: https://github.com/coryodaniel/arbor
- Owner: coryodaniel
- License: mit
- Created: 2016-11-07T01:19:26.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2022-08-27T20:20:40.000Z (over 2 years ago)
- Last Synced: 2024-10-13T18:44:54.644Z (4 months ago)
- Language: Elixir
- Homepage:
- Size: 52.7 KB
- Stars: 239
- Watchers: 9
- Forks: 25
- Open Issues: 15
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
- freaking_awesome_elixir - Elixir - Ecto adjacency list and tree traversal. (ORM and Datamapping)
- fucking-awesome-elixir - arbor - Ecto adjacency list and tree traversal. (ORM and Datamapping)
- awesome-elixir - arbor - Ecto adjacency list and tree traversal. (ORM and Datamapping)
README
# Arbor
[![Build Status](https://travis-ci.org/coryodaniel/arbor.svg)](https://travis-ci.org/coryodaniel/arbor)
[![Hex Version](http://img.shields.io/hexpm/v/arbor.svg?style=flat)](https://hex.pm/packages/arbor)
[![Hex docs](http://img.shields.io/badge/hex.pm-docs-green.svg?style=flat)](https://hexdocs.pm/arbor)Ecto adjacency list and tree traversal using CTEs. Arbor uses a `parent_id` field
and CTEs to create simple deep tree-like SQL hierarchies.## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed as:
Add `arbor` to your list of dependencies in `mix.exs`:
For Ecto SQL 3+:
```elixir
def deps do
[{:arbor, "~> 1.1.0"}]
end
```For Ecto 2:
```elixir
def deps do
[{:arbor, "~> 1.0.6"}]
end
```## Benchmarks
Arbor has been [benchmarked](https://github.com/coryodaniel/arbor_bench) on 10mm+ record tables with efficient results:
10,000,000 rows, 25% root
```
Running siblings
10000 runs
Total time: 1.793026000000013
Avg: 1.7930260000000131e-4
Running children
10000 runs
Total time: 1.5967949999999786
Avg: 1.5967949999999787e-4
Running descendants
10000 runs
Total time: 2.5418830000000012
Avg: 2.5418830000000013e-4
Running ancestors
10000 runs
Total time: 2.87076499999998
Avg: 2.87076499999998e-4
```## Usage
```elixir
defmodule Comment do
use Ecto.Schema
# See config options below
use Arbor.Tree, foreign_key_type: :binary_idschema "comments" do
field :body, :string
belongs_to :parent, __MODULE__timestamps
end
end
```All methods return composable Ecto queries. For in depth examples see the [tests](./test/arbor)
### Roots
Returns root level records.
```elixir
roots = Comment.roots
|> Repo.all
```### Siblings
Return the siblings of a record.
```elixir
siblings = my_comment
|> Comment.siblings
|> Comment.order_by_popularity
|> Repo.all
```### ancestors
Returns the entire ancestor (parent's parent's parent, etc) path to the record, but not including the record.
```elixir
ancestors = my_comment
|> Comment.ancestors
|> Comment.order_by_inserted_at
|> Repo.all
```### Descendants
Returns the entire descendant tree of a record, but not including the record.
```elixir
descendants = my_comment
|> Comment.descendants
|> Comment.order_by_inserted_at
|> Repo.all
```A second parameter can be passed to `descendants` to specify how deep
from the root of the tree to retrieve the descendants from.```elixir
descendants = my_comment
|> Comment.descendants(2)
|> Comment.order_by_inserted_at
|> Repo.all
```### Children
Returns the immediate children of a record.
```elixir
children = my_comment
|> Comment.children
|> Repo.all
```### Parent
Returns the record's parent.
```elixir
parent = my_comment
|> Comment.parent
|> Repo.first
```## Options
* *table_name* - set the table name to use in [CTEs](https://www.postgresql.org/docs/9.1/static/queries-with.html)
* *tree_name* - set the name of the CTE
* *primary_key* - defaults to field from Ecto's `@primary_key`
* *primary_key_type* - defaults to type from Ecto's `@primary_key`
* *foreign_key* - defauts to `:parent_id`
* *foreign_key_type* - defaults to type from Ecto's `@primary_key`
* *orphan_strategy* - defaults to `:nothing` currently unimplemented## Contributing
You'll need PostgreSQL installed and a user that can create and drop databases.
There is a docker-compose file for your convienence.
You can specify it with the environment variable `ARBOR_DB_USER`.
The `mix test` task will drop and create the database for each run.
```shell
docker-compose up -d
ARBOR_DB_USER=postgres mix test
docker-compose down
```