Pathex
Fast. Really fast.
What is Pathex?
Pathex is a library for performing fast actions with nested data structures in Elixir. With pathex you can trivially set, get and update values in structures. It provides all necessary logic to manipulate data structures in different ways
Why another library?
Existing methods of accesssing data in nested structures are either slow (like Focus
)
or do not provide much functionality (like put_in
or get_in
).
For example setting the value in structure with Pathex is 70-160x
faster than Focus
or 2-3x
faster than put_in
and get_in
You can checkout benchmarks at https://github.com/hissssst/pathex_bench
Check out Pathex documentation!
You can find complete documentation with examples, howto's, guides at https://hexdocs.pm/pathex
Installation
def deps do
[
{:pathex, "~> 1.0"}
]
end
Usage
Import it
require Pathex import Pathex, only: [path: 1, path: 2, "~>": 2]
Or you can just
use
Pathex!# This will require Pathex and import all operators and path/2 macro use Pathex
Create path
path_to_strees = path :user / :private / :addresses / 0 / :street path_in_json = ~P"users/1/street"json
This creates closure which can get, set and update values in this path
Use the path!
{:ok, "6th avenue" = street} = %{ user: %{ id: 1, name: "hissssst", private: %{ phone: "123-456-789", addresses: [ [city: "City", street: "6th avenue", mail_index: 123456] ] } } } |> Pathex.view(path_to_streets) %{ "users" => %{ "1" => %{"street" => "6th avenue"} } } = Pathex.force_set!(%{}, path_in_json, street)
Features
Speed
Paths are really a set of pattern-matching cases. This is done to extract maximum efficency from BEAM's pattern-matching compiler
# Code for viewing variables for path
path(1 / "y", :map)
# Almost equals to
case do
%{1 => %{"y" => res}} -> {:ok, res}
_ -> :error
end
Reusability
Paths can be created and used or composed later with rich set of composition functions
# Takes username from user structure
username = path(:personal / :fname)
{:ok, "Kabs"} =
%{
personal: %{fname: "Kabs", sname: "Rocks"},
phone: "123-456-789"
}
# Takes all usernames!
all = Pathex.Lenses.all()
{:ok, ["Kabs", "Blabs"]} =
[
%{
personal: %{fname: "Kabs", sname: "Rocks"},
phone: "123-456-789"
},
%{
personal: %{fname: "Blabs"},
phone: "123-456-790"
}
]
|> Pathex.view(all ~> username)
Rich toolkit
Perform create, update, select operation with different behaviours using Pathex.Lenses
module
High level operations like filtering and updating nested values have never been this easy
import Pathex; import Pathex.Lenses
# Change first username in a list
[
%{personal: %{fname: "Alabs", sname: "Rocks"}},
%{personal: %{fname: "Blabs"}}
] =
[
%{personal: %{fname: "Kabs", sname: "Rocks"}},
%{personal: %{fname: "Blabs"}}
]
|> Pathex.set!(some() ~> path(:personal / :fname), "Alabs")
Powerfull abstraction
Pathex is built around simple primitive called path
, therefore can be simply extended.path
or path-closure
is just a closure with special primitives. Anything complying with Pathex.t()
spec can
be used within Pathex
Safe and simple
All path-closures are pure and macro are hygienic. There is no magic
Contributions
Welcome! You can check existing TODO
's
By the way
- If you have any suggestions or want to change something in this library don't hesitate to open an issue
- If you have any whitepapers about functional lenses, you can add them in a PR to the bottom of this readme