Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ cache:
directories:
- _build
- deps
notifications:
email: false
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ defmodule MyApp.AddMaterializedPathToComments do

def change do
alter table(:comments) do
add :materialized_path, {:array, :integer}, null: false, default: []
add :path, {:array, :integer}, null: false
end
end
end
Expand Down Expand Up @@ -253,7 +253,7 @@ You can get depth level of the node in the tree

#### `where_depth/2`

You can specify a query to search for nodes with some level of depth
You can specify a query to search for nodes with some level of depth. It uses `CARDINALITY()` postgres function internally, so ensure your postgres version is at least `9.4`.

``` elixir
Comment.where_depth(Comment, is_bigger_than: 2) # => Find all nodes with more than 2 levels deep
Expand Down Expand Up @@ -323,3 +323,15 @@ Comment.brutalist_root(comment)
Comment.brutalist_root?(comment)
# et.c.
```

## About [Brutalist](https://brutalist.press)

<a href="https://brutalist.press">
<img src="https://github.com/asiniy/ecto_materialized_path/blob/master/brutalist_logo.png"
width="400"
height="106"
alt="Brutalist">
</a>
<br /><br />

`ecto_materialized_path` package is maintained and funded by folks from [Brutalist](https://brutalist.press) - media platform for writing and sharing news and stories with strong focus on traditional values, think-tank level analytics and political research.
Binary file added brutalist_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 6 additions & 5 deletions lib/ecto_materialized_path.ex
Original file line number Diff line number Diff line change
Expand Up @@ -130,19 +130,19 @@ defmodule EctoMaterializedPath do
end

defp do_where_depth(query, [is_bigger_than: ibt], column_name) when is_integer(ibt) and ibt > 0 do
Ecto.Query.from(q in query, where: fragment("array_length(?, 1)", ^column_name) > ^ibt)
Ecto.Query.from(q in query, where: fragment("CARDINALITY(?) > ?", field(q, ^column_name), ^ibt))
end
defp do_where_depth(query, [is_bigger_than_or_equal_to: ibtoet], column_name) when is_integer(ibtoet) and ibtoet >= 0 do
Ecto.Query.from(q in query, where: fragment("array_length(?, 1)", ^column_name) >= ^ibtoet)
Ecto.Query.from(q in query, where: fragment("CARDINALITY(?) >= ?", field(q, ^column_name), ^ibtoet))
end
defp do_where_depth(query, [is_equal_to: iet], column_name) when is_integer(iet) and iet > 0 do
Ecto.Query.from(q in query, where: fragment("array_length(?, 1)", ^column_name) == ^iet)
Ecto.Query.from(q in query, where: fragment("CARDINALITY(?) = ?", field(q, ^column_name), ^iet))
end
defp do_where_depth(query, [is_smaller_than_or_equal_to: istoet], column_name) when is_integer(istoet) and istoet >= 0 do
Ecto.Query.from(q in query, where: fragment("array_length(?, 1)", ^column_name) <= ^istoet)
Ecto.Query.from(q in query, where: fragment("CARDINALITY(?) <= ?", field(q, ^column_name), ^istoet))
end
defp do_where_depth(query, [is_smaller_than: ist], column_name) when is_integer(ist) and ist > 0 do
Ecto.Query.from(q in query, where: fragment("array_length(?, 1)", ^column_name) < ^ist)
Ecto.Query.from(q in query, where: fragment("CARDINALITY(?) < ?", field(q, ^column_name), ^ist))
end
defp do_where_depth(_, _, _) do
raise ArgumentError, "invalid arguments"
Expand All @@ -160,6 +160,7 @@ defmodule EctoMaterializedPath do
changeset |> Ecto.Changeset.change(%{ :"#{column_name}" => new_path })
end

def arrange([], _), do: []
def arrange(nodes_list, column_name) do
nodes_depth_map = nodes_list |> nodes_by_depth_map(%{}, column_name)

Expand Down
2 changes: 1 addition & 1 deletion lib/ecto_materialized_path/path.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ defmodule EctoMaterializedPath.Path do
"""

def cast(list) when is_list(list) do
path_is_correct? = Enum.all?(list, fn(path_id) -> is_integer(path_id) end)
path_is_correct? = Enum.all?(list, fn(path_id) -> (is_integer(path_id) || is_binary(path_id)) end)
Copy link
Owner

@asiniy asiniy Mar 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move condition check to the new line, it'll be easier to read. Plus, make it looks better.

Depending on id_type option provided in use, check for either uuid or regular. Create a private function for each. For uuid, please use an Ecto default functionality.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please write an option to use macro, something like

use EctoMaterializedPath,
  id_type: :uuid # default is `:regular`

and add a few lines to the doc

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx for the feedback, I like the way you want it to do. what I'm struggling (Elixir noob) is how to access the id_type passed to use from within the Path module.
Thought about adding a function to the base module, but then I don't know how to access the id_type outside of the macro.

Copy link
Owner

@asiniy asiniy Mar 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to figure out by yourself. I don't have a time right now :( Use SO/elixir forum to get it and write according to my feedback

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok.


if path_is_correct? do
{ :ok, list }
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule EctoMaterializedPath.Mixfile do
use Mix.Project

@project_url "https://github.com/asiniy/ecto_materialized_path"
@version "0.1.0"
@version "0.2.0"

def project do
[
Expand Down
6 changes: 5 additions & 1 deletion test/ecto_materialized_path/path_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ defmodule EctoMaterializedPath.PathTest do
assert Path.cast([13, 45, 18]) == { :ok, [13, 45, 18] }
end

test "passes with UUID's" do
assert Path.cast(["38432046-4351-4676-8988-10f0262da113", "a65ce828-52f2-4931-8719-9f7d97723f3b"]) == { :ok, ["38432046-4351-4676-8988-10f0262da113", "a65ce828-52f2-4931-8719-9f7d97723f3b"] }
end

test "fails with random value" do
assert Path.cast(4) == :error
end

test "fails with wrongs path" do
assert Path.cast([14, "ee", 45]) == :error
assert Path.cast([14, [:ok], 45]) == :error
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"ee" should still fail - because it's not an uuid

end
end
6 changes: 5 additions & 1 deletion test/ecto_materialized_path_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,11 @@ defmodule EctoMaterializedPathTest do
]
end

test "raises an exception when node isn't arranged" do
test "returns empty list if there are no children" do
assert Comment.arrange([]) == []
end

test "raises an exception when node can't arranged" do
comment_1 = %Comment{ id: 1 }
comment_3 = %Comment{ id: 3, path: [1] }
# parent is missing
Expand Down