View Source CTE.Adapter.Ecto (Closure Table v1.1.5)
A CTE Adapter implementation using an existing Ecto Repo for persisting the models.
The current implementation is depending on Ecto ~> 3.1; using Ecto.SubQuery!
For this implementation to work you'll have to provide two tables, and the name of the Repo used by your application:
- a table name containing the nodes. Having the
id
, as a the primary key - a table name where the tree paths will be stores.
- the name of the Ecto.Repo, defined by your app
In a future version we will provide you with a convenient migration template to help you starting, but for now you must supply these tables.
For example, given you have the following Schemas for comments:
defmodule CT.Comment do
use Ecto.Schema
import Ecto.Changeset
@timestamps_opts [type: :utc_datetime]
schema "comments" do
field :text, :string
belongs_to :author, CT.Author
timestamps()
end
end
and a table used for storing the parent-child relationships
defmodule CT.TreePath do
use Ecto.Schema
import Ecto.Changeset
alias CT.Comment
@primary_key false
schema "tree_paths" do
belongs_to :parent_comment, Comment, foreign_key: :ancestor
belongs_to :comment, Comment, foreign_key: :descendant
field :depth, :integer, default: 0
end
end
we can define the following module:
defmodule CT.MyCTE do
use CTE,
otp_app: :cte,
adapter: CTE.Adapter.Ecto,
repo: CT.Repo,
nodes: CT.Comment,
paths: CT.TreePath
end
We add our CTE Repo to the app's main supervision tree, like this:
defmodule CT.Application do
use Application
def start(_type, _args) do
children = [
CT.Repo,
CT.MyCTE
]
opts = [strategy: :one_for_one, name: CT.Supervisor]
Supervisor.start_link(children, opts)
end
end
restart out app and then using IEx, we can start experimenting. Examples:
iex» CT.MyCTE.ancestors(9)
{:ok, [1, 4, 6]}
iex» CT.MyCTE.tree(6)
{:ok,
%{
nodes: %{
6 => %CT.Comment{
__meta__: #Ecto.Schema.Metadata<:loaded, "comments">,
author: #Ecto.Association.NotLoaded<association :author is not loaded>,
author_id: 2,
id: 6,
inserted_at: ~U[2019-07-21 01:10:35Z],
text: "Everything is easier, than with the Nested Sets.",
updated_at: ~U[2019-07-21 01:10:35Z]
},
8 => %CT.Comment{
__meta__: #Ecto.Schema.Metadata<:loaded, "comments">,
author: #Ecto.Association.NotLoaded<association :author is not loaded>,
author_id: 1,
id: 8,
inserted_at: ~U[2019-07-21 01:10:35Z],
text: "I’m sold! And I’ll use its Elixir implementation! <3",
updated_at: ~U[2019-07-21 01:10:35Z]
},
9 => %CT.Comment{
__meta__: #Ecto.Schema.Metadata<:loaded, "comments">,
author: #Ecto.Association.NotLoaded<association :author is not loaded>,
author_id: 3,
id: 9,
inserted_at: ~U[2019-07-21 01:10:35Z],
text: "w⦿‿⦿t!",
updated_at: ~U[2019-07-21 01:10:35Z]
}
},
paths: [
[6, 6, 0],
[6, 8, 1],
[8, 8, 0],
[6, 9, 1],
[9, 9, 0]
]
}}
Have fun!
Most of the functions implementing the CTE.Adapter
behavior, will accept the following options:
:limit
, to limit the total number of nodes returned, when finding the ancestors or the descendants for nodes:itself
, accepting a boolean value. Whentrue
, the node used for finding its neighbors are returned as part of the results. Default: true:nodes
, accepting a boolean value. Whentrue
, the results are containing additional information about the nodes. Default: false
Summary
Functions
Retrieve the ancestors of a node
Returns a specification to start this module under a supervisor.
Delete a leaf or a subtree.
Retrieve the descendants of a node
Initializes the adapter supervision tree by returning the children and adapter metadata.
Insert a node under an existing ancestor
Move a subtree from one location to another.
start the Adapter server
Calculate and return a "tree" structure containing the paths and the nodes under the given leaf/node
Functions
Retrieve the ancestors of a node
Returns a specification to start this module under a supervisor.
See Supervisor
.
Delete a leaf or a subtree.
To delete a leaf node set the limit option to: 1, and in this particular case all the nodes that reference the leaf will be assigned to the leaf's immediate ancestor
If limit is 0, then the leaf and its descendants will be deleted
Retrieve the descendants of a node
Initializes the adapter supervision tree by returning the children and adapter metadata.
Insert a node under an existing ancestor
Move a subtree from one location to another.
First, the subtree and its descendants are disconnected from its ancestors. And second, the subtree is inserted under the new parent (ancestor) and the subtree, including its descendants, is declared as descendants of all the new ancestors.
start the Adapter server
Calculate and return a "tree" structure containing the paths and the nodes under the given leaf/node