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"}
]
endUsage
Import it
require Pathex import Pathex, only: [path: 1, path: 2, "~>": 2]Or you can just
usePathex!# This will require Pathex and import all operators and path/2 macro use PathexCreate path
path_to_strees = path :user / :private / :addresses / 0 / :street path_in_json = ~P"users/1/street"jsonThis 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
endReusability
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