Coder Social home page Coder Social logo

ravix's Introduction

ravix_logo

Elixir CI Coverage Status Hex

Ravix

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

Usage

Installing

Add Ravix to your mix.exs dependencies

{:ravix, "~> 0.10.0"}

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.Test.Store,
  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
  }

Note: All the calls to RavenDB are done via HTTP calls, to that we leverage the use of Finch, check there for adapter configurations.

Then you can start the processes in your main supervisor

defmodule Ravix.TestApplication do
  use Application

  def start(_opts, _) do
    children = [
      {Finch, name: Ravix.Finch}, # By default the store searches for a Finch instance called 'Ravix.Finch' 
      {Ravix.Test.Store, [%{}]} # you can create multiple stores
    ]

    Supervisor.init(
      children,
      strategy: :one_for_one
    )
  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.Test.Store.open_session()
{:ok, "985781c8-9154-494b-92d0-a66b49bb17ee"}

Inserting a new document

iex(2)> Ravix.Test.Store.open_session()
iex(2)> {:ok, session_id} = Ravix.Test.Store.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.Test.Store.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 certificates based on the erlang ssl configs to Finch itself.

E.g:

{Finch, name: Ravix.Finch,
    pools: %{
      default: [
        conn_opts: [
          transport_opts: [
            cert: DER_CERT,
            key: DER_KEY
          ]
        ]
      ]
    }
},

Ecto

What about querying your RavenDB using Ecto? Ravix-Ecto

Current State

  • Configuration Reading
  • Session Management
  • Request Executors
  • Unsafe Server Connection
  • Authenticated Server Connection
  • Create Document
  • Delete Document
  • Load Document
  • Queries Engine
  • Clustering
  • Topology Updates
  • Counters
  • Timeseries
  • Asynchronous Subscriptions
  • Attachments

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

ravix's People

Contributors

dependabot[bot] avatar drumusician avatar github-actions[bot] avatar kianmeng avatar ygorcastor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ravix's Issues

RQL/Limit issue

I am trying out the following

 {:ok, session_id} = Some.Store.open_session()

    result =
      from("Txes")
      |> where(equal_to("OrgId",org_id))
      |> and?(between("TxDate",[from_date, to_date]))
      |> limit(0,1)
      |> IO.inspect()
      |> list_all(session_id)

    Some.Store.close_session(session_id)

The results are inconsistent. Sometimes the limit is honored and only 1 result is returned but at other times all other results are returned.

The rql query struct(from IO.inspect) has the correct limit entry

%Ravix.RQL.Query{
   limit_token: %Ravix.RQL.Tokens.Limit{next: 1, skip: 0, token: :limit},
}

Failed to start child

11:00:03.230 [info] [RAVIX] start_link '{:via, Registry, {:request_executors, "DB/URL"}}'

11:00:03.246 [notice] Application raven exited: Raven.Application.start(:normal, []) returned an error: shutdown: failed to start child: Raven.DB.Store
** (EXIT) shutdown: failed to start child: Ravix.Connection
** (EXIT) an exception was raised:
** (RuntimeError) No nodes were registered successfully
(ravix 0.1.4) lib/connection/connection_state_manager.ex:56: Ravix.Connection.State.Manager.initialize/1
(ravix 0.1.4) lib/connection/connection.ex:24: Ravix.Connection.start_link/2
(stdlib 3.10) supervisor.erl:379: :supervisor.do_start_child_i/3
(stdlib 3.10) supervisor.erl:365: :supervisor.do_start_child/2
(stdlib 3.10) supervisor.erl:349: anonymous fn/3 in :supervisor.start_children/2
(stdlib 3.10) supervisor.erl:1157: :supervisor.children_map/4
(stdlib 3.10) supervisor.erl:315: :supervisor.init_children/2
(stdlib 3.10) gen_server.erl:374: :gen_server.init_it/2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.