{"id":22790306,"url":"https://github.com/zven21/ancestry","last_synced_at":"2025-08-17T20:10:21.048Z","repository":{"id":48295116,"uuid":"191514518","full_name":"zven21/ancestry","owner":"zven21","description":"The tree structure implementations for Elixir Ecto.","archived":false,"fork":false,"pushed_at":"2021-08-02T21:18:01.000Z","size":85,"stargazers_count":32,"open_issues_count":9,"forks_count":4,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-08-03T07:36:36.172Z","etag":null,"topics":["ancestry","ecto","elixir","elixir-lang","elixir-library","mix","tree"],"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/zven21.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-06-12T06:51:37.000Z","updated_at":"2024-10-06T12:14:27.000Z","dependencies_parsed_at":"2022-09-26T18:30:56.416Z","dependency_job_id":null,"html_url":"https://github.com/zven21/ancestry","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zven21/ancestry","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zven21%2Fancestry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zven21%2Fancestry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zven21%2Fancestry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zven21%2Fancestry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zven21","download_url":"https://codeload.github.com/zven21/ancestry/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zven21%2Fancestry/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270899582,"owners_count":24664720,"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","status":"online","status_checked_at":"2025-08-17T02:00:09.016Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["ancestry","ecto","elixir","elixir-lang","elixir-library","mix","tree"],"created_at":"2024-12-12T02:19:57.812Z","updated_at":"2025-08-17T20:10:21.020Z","avatar_url":"https://github.com/zven21.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ancestry\n\n[![Build Status](https://travis-ci.org/zven21/ancestry.svg?branch=master)](https://travis-ci.org/zven21/ancestry)\n[![Coverage Status](https://coveralls.io/repos/github/zven21/ancestry/badge.svg)](https://coveralls.io/github/zven21/ancestry)\n\n**The tree structure implementations for Ecto.**\n\n## Table of contents\n\n* [Getting started](#getting-started)\n* [Navigation](#navigation)\n* [Options for use Ancestry](#options-for-use-ancestry)\n* [Arrangement](#arrangement)\n* [Examples](#examples)\n* [Contributing](#contributing)\n* [Make a pull request](#make-a-pull-request)\n* [License](#license)\n* [Credits](#credits)\n\n\n## Getting started\n\nIf [available in Hex](https://hex.pm/docs/publish), the package can be installed\nby adding `ancestry` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:ancestry, \"~\u003e 0.1.3\"}\n  ]\nend\n```\n\nGen migration file to add string field in your model.\n\n```shell\nmix ecto.gen.migration add_ancestry_to_\u003cmodel\u003e\n```\n\nAdd ancestry field and index to migration file.\n\n```elixir\ndef change do\n  alter table(:my_models) do\n    add :ancestry, :string\n  end\n  create index(:my_models, [:ancestry])\nend\n```\n\n```shell\nmix ecto.migration\n```\n\nAdd `use Ancestry, repo: MyApp.repo` to you model.ex\n\n```elixir\ndefmodule MyModel do\n  use Ecto.Schema\n  use Ancestry, repo: MyApp.repo\n\n  import Ecto.Changeset\n\n  schema \"my_models\" do\n    field :ancestry, :string\n  end\n\n  def changeset(struct, params) do\n    struct\n    |\u003e cast(params, [:ancestry])\n  end\nend\n```\n\n## Navigation\n\n|  method           | return value | usage example | finished? |\n|-------------------|--------------------------|---------------|-----------|\n|`roots`            |all root node| `MyModel.roots` | `true` |\n|`parent`           |parent of the record, nil for a root node| `MyModel.parent(record)` | `true` |\n|`parent_id`        |parent id of the record, nil for a root node| `MyModel.parent_id(record)` | `true` |\n|`has_parent?`      |true if the record has a parent, false otherwise| `MyModel.has_parent?(record)` | `true` |\n|`root`             |root of the record's tree, self for a root node| `MyModel.root(record)` | `true` |\n|`root_id`          |root id of the record's tree, self for a root node| `MyModel.root_id(record)` | `true` |\n|`is_root?`         |  true if the record is a root node, false otherwise| `MyModel.is_root?(record)` | `true` |\n|`ancestors`        |ancestors of the record, starting with the root and ending with the parent| `MyModel.ancestors(record)` | `true` |\n|`ancestor_ids`     |ancestor ids of the record| `MyModel.ancestor_ids(record)` | `true` |\n|`children`         |direct children of the record| `MyModel.children(record)` | `true` |\n|`child_ids`        |direct children's ids| `MyModel.child_ids(record)`| `true` |\n|`has_children?`    |true if the record has any children, false otherwise| `MyModel.has_children?(record)` | `true` |\n|`is_childless?`    |true is the record has no children, false otherwise| `MyModel.is_childless?(record)` | `true` |\n|`siblings`         |siblings of the record, the record itself is included*| `MyModel.siblings(record)` | `true` |\n|`sibling_ids`      |sibling ids| `MyModel.sibling_ids(record)` | `true` |\n|`has_siblings?`    |true if the record's parent has more than one child| `MyModel.has_siblings?(record)` | `true` |\n|`is_only_child?`   |true if the record is the only child of its parent| `MyModel.is_only_child?(record)`| `true`|\n|`descendants`      |direct and indirect children of the record| `MyModel.descendants(record)`| `true` |\n|`descendant_ids`   |direct and indirect children's ids of the record| `MyModel.descendant_ids(record)` | `true` |\n|`subtree`          |the model on descendants and itself| `MyModel.subtree(record)` | `true` |\n|`subtree_ids`      |a list of all ids in the record's subtree| `MyModel.subtree_ids(record)`| `true` |\n|`path`             |path of the record, starting with the root and ending with self| `MyModel.path(record)` | `true`|\n|`path_ids`         |a list the path ids, starting with the root id and ending with the node's own id| `MyModel.path_ids(record)`| `true` |\n|`depth`            |the depth of the node, root nodes are at depth 0| `MyModel.depth(record)`| `true` |\n\n## Options for `use Ancestry`\n\nThe `use Ancestry` method supports the following options:\n\n    :repo                  The current app repo\n    :ancestry_column       Pass in a symbol to store ancestry in a different column\n    :orphan_strategy       Instruct Ancestry what to do with children of a node that is destroyed:\n                           :destroy   All children are destroyed as well (default)\n                           :rootify   The children of the destroyed node become root nodes\n                           :restrict  An AncestryException is raised if any children exist\n                           :adopt     The orphan subtree is added to the parent of the deleted node.\n                                      If the deleted node is Root, then rootify the orphan subtree.\n\n\n## Arrangement\n\nAncestry can arrange an entire subtree into nested hashes for easy navigation after retrieval from the database.\n\n```elixir\nMyModel.arrange(record) =\u003e\n%{\n  id: 1,\n  name: \"root\",\n  ancestry: nil,\n  children: [\n    %{\n      id: \"2\",\n      name: \"childA\",\n      ancestry: \"1\",\n      children: [\n        %{\n          id: 3,\n          name: \"childA1\",\n          ancestry: \"1/2\",\n          children: []\n        }\n      ]\n    }\n  ],\n}\n```\n\n## Examples\n\n```elixir\n# use `MyModel.delete` deal with orphan strategy.\niex\u003e MyModel.delete(record)\n\n# use `MyModel.get_ancestry_value(record, \"children|siblings\")` gen `ancestry` value\niex\u003e MyModel.get_ancestry_value(record, \"children\")\n\n# use `MyModel.arrange`\niex\u003e MyModel.arrange(record)\n```\n\n## TODO's\n\n* [ ] Establish data relationships\n* [ ] Parent create child\n* [ ] Create child with parent\n\n## Contributing\n\nBug report or pull request are welcome.\n\n## Make a pull request\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n\nPlease write unit test with your code if necessary.\n\n## License\n\nThe mix is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n## Credits\n\n* [ancestry](https://github.com/stefankroes/ancestry) - Organise ActiveRecord model into a tree structure(Ruby classes).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzven21%2Fancestry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzven21%2Fancestry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzven21%2Fancestry/lists"}