ravix_logo

Elixir CICoverage Status

Ravix

Ravix is a in-development project to implement a client for the amazing RavenDB NoSQL Database.

Usage

Instaling

Add Ravix to your mix.exs dependencies

{:ravix, "~> 0.1"}

Setting up your Repository

 

Create a Ravix Store Module for your repository

defmodule YourProject.YourStore do
use Ravix.Documents.Store, otp_app: :your_app
end

 

You can configure your Store in your config.exs files

config :ravix, Ravix.TestStore,
urls: [System.get_env("RAVENDB_URL", "http://localhost:8080")],
database: "test",
retry_on_failure: true,
retry_backoff: 100,
retry_count: 3,
force_create_database: true,
document_conventions: %{
max_number_of_requests_per_session: 30,
max_ids_to_catch: 32,
timeout: 30,
use_optimistic_concurrency: false,
max_length_of_query_using_get_url: 1024 + 512,
identity_parts_separator: "/",
disable_topology_update: false
}

 

Then you can start the processes in your main supervisor

defmodule Ravix.TestApplication do
use Supervisor
def init(_opts) do
children = [
{Ravix, [%{}]},
{Ravix.TestStore, [%{}]} # you can create multiple stores
]
Supervisor.init(
children,
strategy: :one_for_one
)
end
def start_link(init_arg) do
Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
end
end

 

Querying the Database

 

All operations supported by the driver should be executed inside a session, to open a session you can just call the open_session/0 function from the store you defined. All the changes are only persisted when the function Ravix.Documents.Session.save_changes/1 is called!

iex(2)> Ravix.TestStore.open_session()
{:ok, "985781c8-9154-494b-92d0-a66b49bb17ee"}

Inserting a new document

iex(2)> Ravix.TestStore.open_session()
iex(2)> {:ok, session_id} = Ravix.TestStore.open_session()
{:ok, "c4fb1f48-c969-4c76-9b12-5521926c7533"}
iex(3)> Ravix.Documents.Session.store(session_id, %{id: "cat/1", cat_name: "Adolfus"})
{:ok, %{cat_name: "Adolfus", id: "cat/1"}}
iex(4)> Ravix.Documents.Session.save_changes(session_id)
{:ok,
%{
"Results" => [
%{
"@change-vector" => "A:264-vzsRp+yZT0GDkS5GJY/pAQ",
"@collection" => "@empty",
"@id" => "cat/1",
"@last-modified" => "2022-03-28T15:01:45.6545514Z",
"Type" => "PUT"
}
]
}}

Loading a document into the session

iex(3)> {:ok, session_id} = Ravix.TestStore.open_session()
{:ok, "d17e2be8-8c1e-4a59-8626-46725387f769"}
iex(4)> Ravix.Documents.Session.load(session_id, ["cat/1"])
{:ok,
%{
"Includes" => %{},
"Results" => [
%{
"@metadata" => %{
"@change-vector" => "A:264-vzsRp+yZT0GDkS5GJY/pAQ",
"@id" => "cat/1",
"@last-modified" => "2022-03-28T15:01:45.6545514Z"
},
"cat_name" => "Adolfus",
"id" => "cat/1"
}
],
"already_loaded_ids" => []
}}

Querying using RQL

RavenDB provides a query-language called RQL, and for that Ravix provides two ways to deal with queries, using builder functions and raw RQLs

RQL Builder

You can build RQLs using the builder provided by the Ravix.RQL.Query module

iex(11)> from("@all_docs") |> where(equal_to("cat_name", "Adolfus")) |> list_all(session_id)
{:ok,
%{
"DurationInMs" => 1,
"IncludedPaths" => nil,
"Includes" => %{},
"IndexName" => "Auto/AllDocs/Bycat_nameAndid",
"IndexTimestamp" => "2022-03-28T18:39:58.7637789",
"IsStale" => false,
"LastQueryTime" => "2022-03-28T18:49:05.9272430",
"LongTotalResults" => 1,
"NodeTag" => "A",
"ResultEtag" => -4402181509807245325,
"Results" => [
%{
"@metadata" => %{
"@change-vector" => "A:264-vzsRp+yZT0GDkS5GJY/pAQ",
"@id" => "cat/1",
"@index-score" => 5.330733299255371,
"@last-modified" => "2022-03-28T15:01:45.6545514Z"
},
"cat_name" => "Adolfus",
"id" => "cat/1"
}
],
"SkippedResults" => 0,
"TotalResults" => 1
}}

Raw Query

iex(13)> raw("from @all_docs where cat_name = \"Adolfus\"") |> list_all(session_id)
{:ok,
%{
"DurationInMs" => 1,
"IncludedPaths" => nil,
"Includes" => %{},
"IndexName" => "Auto/AllDocs/Bycat_nameAndid",
"IndexTimestamp" => "2022-03-28T18:39:58.7637789",
"IsStale" => false,
"LastQueryTime" => "2022-03-28T18:53:27.4689173",
"LongTotalResults" => 1,
"NodeTag" => "A",
"ResultEtag" => -4402181509807245325,
"Results" => [
%{
"@metadata" => %{
"@change-vector" => "A:264-vzsRp+yZT0GDkS5GJY/pAQ",
"@id" => "cat/1",
"@index-score" => 5.330733299255371,
"@last-modified" => "2022-03-28T15:01:45.6545514Z"
},
"cat_name" => "Adolfus",
"id" => "cat/1"
}
],
"SkippedResults" => 0,
"TotalResults" => 1
}}

Collections

RavenDB can organize the documents in collections, Ravix will automatically insert the document in a collection if you use the Ravix. Document macro. If you don't want to use the macro, your struct just need to have the :@metadata field.

defmodule Ravix.SampleModel.Cat do
use Ravix.Document, fields: [:id, :name, :breed]
end

Secure Server

To connect to a secure server, you can just inform the SSL certificate using the certificate or the certificate_file configuration.

config :ravix, Ravix.TestStore,
urls: [System.get_env("RAVENDB_URL", "http://localhost:8080")],
database: "test",
certificate: CERT_IN_BASE_64,
certificate_file: "/opt/certs/cert.pfx"

Current State

The driver is working for the basic operations, clustering and resiliency are also implemented.