MarcoPolo

Main API for interfacing with OrientDB.

This module provides functions to connect to a running OrientDB server and to perform commands on it.

A connection to OrientDB can be established using the start_link/1 function and stoppped with stop/1.

Connection type

OrientDB makes a distinction between server operations and database operations. Server operations are operations that are performed at server level: examples of these operations are checking if a database exists or creating a new database. Database operations have to be performed inside a database: examples of such operations are inserting a new record or getting the number of records in the database.

Server and database operations can only be performed by the appropriate connection: a connection to the server can perform only server operations, while a connection to a database can perform only database operations. The connection type is chosen when the connection is started via start_link/1.

Examples

conn_type = {:db, "GratefulDeadConcerts", :document}
{:ok, conn} = MarcoPolo.start_link(user: "admin", password: "admin", connection: conn_type)
MarcoPolo.command(conn, "SELECT FROM OUser")
#=> {:ok, [...users...]}

Summary

Execute the given query in the database to which conn is connected

Creates a database on the server

Creates a record in the database to which conn is connected

Returns the number of records in the database to which conn is connected

Tells if the database called name with the given type exists

Reloads the database to which conn is connected

Returns the size of the database to which conn is connected

Deletes a record from the database to which conn is connected

Drop a database on the server

Subscribes to a Live Query for the given query

Unsubscribes from the live query identified by token

Loads a record from the database to which conn is connected

Executes a script in the given language on the database conn is connected to

Starts the connection with an OrientDB server

Closes the connection (asynchronously), doing the required cleanup work

Runs operations inside a transaction on the database to which conn is connected

Updates the given record in the databse to which conn is connected

Types

db_type :: :document | :graph
storage_type :: :plocal | :memory
tx_operation :: {:create | :update | :delete, rec}

Functions

command(conn, query, opts \\ [])

Specs

command(pid, String.t, Keyword.t) ::
  {:ok, %{response: term, linked_records: linked_records}} |
  {:error, term}

Execute the given query in the database to which conn is connected.

OrientDB makes a distinction between idempotent queries and non-idempotent queries (it calls the former queries and the latter commands). In order to provide a clean interface for performing operations on the server, MarcoPolo provides only a command/3 function both for idempotent as well as non-idempotent operations. Whether an operation is idempotent is inferred by the text in query. As of now, SELECT and TRAVERSE operations are idempotent while all other operations are non-idempotent.

Options

The options that this function accepts depend in part on the type of the operation.

The options shared by both idempotent and non-idempotent operations are the following:

  • :params - a map of params with atoms or strings as keys and any encodable term as values. These parameters are used by OrientDB to build prepared statements as you can see in the examples below. Defaults to %{}.
  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

The additional options for idempotent (e.g., SELECT) queries are:

  • :fetch_plan: a string specifying the fetch plan. Mandatory for SELECT queries.

Return value

If the query is successful then the return value is an {:ok, values} tuple. values is a map with the following keys:

  • :response - depends on the performed query. For example a SELECT query will return a list of records, while a CREATE CLUSTER command will return a cluster id.
  • :linked_records - it's a set of additional records that have been fetched by OrientDB. This can be controlled using a fetch plan in the query. You're not supposed to manipulate this value directly (so that the implementation can stay flexible); use the functions in the MarcoPolo.FetchPlan module to work with linked records.

This operation can only be performed on connections to a database. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Examples

The following is an example of an idempotent command:

iex> opts = [params: %{name: "jennifer"}, fetch_plan: "*:-1"]
iex> query = "SELECT FROM User WHERE name = :name AND age > 18"
iex> {:ok, %MarcoPolo.Document{} = doc} = MarcoPolo.command(conn, query, opts)
iex> doc.fields["name"]
"jennifer"
iex> doc.fields["age"]
45

The following is an example of a non-idempotent command:

iex> query = "INSERT INTO User(name) VALUES ('meg', 'abed')"
iex> {:ok, [meg, abed]} = MarcoPolo.command(conn, query)
iex> meg.fields["name"]
"meg"
iex> abed.fields["name"]
"abed"
create_db(conn, name, type, storage, opts \\ [])

Specs

create_db(pid, String.t, db_type, storage_type, Keyword.t) ::
  :ok |
  {:error, term}

Creates a database on the server.

name is used as the database name, type as the database type (:document or :graph) and storage as the storage type (:plocal or :memory).

This operation can only be performed on connections to the server. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Options

This function accepts the following options:

  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

Examples

iex> MarcoPolo.create_db(conn, "MyCoolDatabase", :document, :plocal)
:ok
create_record(conn, cluster_id, record, opts \\ [])

Specs

create_record(pid, non_neg_integer, rec, Keyword.t) ::
  {:ok, {MarcoPolo.RID.t, non_neg_integer}} |
  {:error, term}

Creates a record in the database to which conn is connected.

cluster_id specifies the cluster to create the record in, while record is the MarcoPolo.Document struct representing the record to create.

The return value in case of success is {:ok, {rid, version}} where rid is the rid of the newly created record and version is the version of the newly created record.

Options

This function accepts the following options:

  • :no_response - if true, send the request to the OrientDB server without waiting for a response. This performs a fire and forget operation, returning :ok every time.
  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

This operation can only be performed on connections to a database. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Examples

iex> record = %MarcoPolo.Document{class: "MyClass", fields: %{"foo" => "bar"}}
iex> MarcoPolo.create_record(conn, 15, record)
{:ok, {%MarcoPolo.RID{cluster_id: 15, position: 10}, 1}}
db_countrecords(conn, opts \\ [])

Specs

db_countrecords(pid, Keyword.t) ::
  {:ok, non_neg_integer} |
  {:error, term}

Returns the number of records in the database to which conn is connected.

This operation can only be performed on connections to a database. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Options

This function accepts the following options:

  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

Examples

iex> MarcoPolo.db_countrecords(conn)
{:ok, 7931}
db_exists?(conn, name, type, opts \\ [])

Specs

db_exists?(pid, String.t, storage_type, Keyword.t) ::
  {:ok, boolean} |
  {:error, term}

Tells if the database called name with the given type exists.

This operation can only be performed on connections to the server. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Options

This function accepts the following options:

  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

Examples

iex> MarcoPolo.db_exists?(conn, "GratefulDeadConcerts", :plocal)
{:ok, true}
db_reload(conn, opts \\ [])

Reloads the database to which conn is connected.

This operation can only be performed on connections to a database. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Options

This function accepts the following options:

  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

Examples

iex> MarcoPolo.db_reload(conn)
:ok
db_size(conn, opts \\ [])

Specs

db_size(pid, Keyword.t) ::
  {:ok, non_neg_integer} |
  {:error, term}

Returns the size of the database to which conn is connected.

This operation can only be performed on connections to a database. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Options

This function accepts the following options:

  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

Examples

iex> MarcoPolo.db_size(conn)
{:ok, 1158891}
delete_record(conn, rid, version, opts \\ [])

Specs

delete_record(pid, MarcoPolo.RID.t, non_neg_integer, Keyword.t) ::
  {:ok, boolean} |
  {:error, term}

Deletes a record from the database to which conn is connected.

The record to delete is identified by rid; version version is deleted. Returns {:ok, deleted?} where deleted? is a boolean that tells if the record has been deleted.

Options

This function accepts the following options:

  • :no_response - if true, send the request to the OrientDB server without waiting for a response. This performs a fire and forget operation, returning :ok every time.
  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

This operation can only be performed on connections to a database. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Examples

iex> rid = %MarcoPolo.RID{cluster_id: 76, position: 12}
iex> MarcoPolo.delete_record(conn, rid, 1)
{:ok, true}
drop_db(conn, name, storage, opts \\ [])

Specs

drop_db(pid, String.t, storage_type, Keyword.t) ::
  :ok |
  {:error, term}

Drop a database on the server.

This function drops the database identified by the name name and the storage type type (either :plocal or :memory).

This operation can only be performed on connections to the server. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Options

This function accepts the following options:

  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

Examples

iex> MarcoPolo.drop_db(conn, "UselessDatabase", :memory)
:ok
live_query(conn, query, receiver, opts \\ [])

Specs

live_query(pid, String.t, pid, Keyword.t) ::
  {:ok, integer} |
  {:error, term}

Subscribes to a Live Query for the given query.

This function subscribes to a Live Query for the given query. Every time a change happens in the given query, a message will be sent to receiver.

If the subscription is successful, this function returns {:ok, token} where token is a unique identifier for the subscription to the give live query. It's important to keep it around as it's needed to unsubscribe from the live query (see live_query_unsubscribe/2).

The messages sent to receiver each time there's a change in the live query has the following structure:

{:orientdb_live_query, token, {operation, record}}

where:

  • token is the token mentioned above
  • operation is one of :create, :update, or :delete, based on the operation happened on the server
  • record is the subject of the operation happened on the server

Options

This function accepts the following options:

  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

Examples

{:ok, token} = MarcoPolo.live_query(conn, "LIVE SELECT FROM Language", self())

Now, another client performs this query:

INSERT INTO Language(name, creators) VALUES ('Elixir', 'José Valim')

Back to the process that started the live query:

receive do
  {:orientdb_live_query, ^token, {operation, record}} ->
    operation #=> :create
    record.fields["name"] #=> "Elixir"
end
live_query_unsubscribe(conn, token)

Specs

live_query_unsubscribe(pid, integer) :: :ok

Unsubscribes from the live query identified by token.

This function unsubscribes from the live query identified by token (see live_query/4). Once an unsubscription from a live query happens, no more messages will be sent to the receiver specified when the live query had been started.

This operation happens asynchronously, hence it always returns :ok.

Examples

iex> MarcoPolo.live_query_unsubscribe(conn, token)
:ok
load_record(conn, rid, opts \\ [])

Specs

load_record(pid, MarcoPolo.RID.t, Keyword.t) ::
  {:ok, {rec, linked_records}} |
  {:error, term}

Loads a record from the database to which conn is connected.

The record to load is identified by rid.

Options

This function accepts the following options:

  • :fetch_plan - the fetching strategy used to fetch the record from the database.
  • :ignore_cache - if true, the cache is ignored, if false it's not. Defaults to true.
  • :load_tombstones - if true, information about deleted records is loaded, if false it's not. Defaults to false.
  • :if_version_not_latest - if true, only load the given record if the version specified in the :version option is not the latest. If this option is present, the :version option is required. This functionality is supported in OrientDB >= 2.1.
  • :version - see the :if_version_not_latest option.
  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

Return value

This function returns {:ok, resp} in case of a successful request or {:error, reason} otherwise. In case of success, resp will be a two-element tuple with the loaded record as the first elemen, and with a set of records linked to it as the second element. This set of linked records can be controlled via the :fetch_plan options. You're not supposed to manipulate this value directly (so that the implementation can stay flexible); use the functions in the MarcoPolo.FetchPlan module to work with linked records.

This operation can only be performed on connections to a database. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Examples

iex> rid = %MarcoPolo.RID{cluster_id: 10, position: 184}
iex> {:ok, {record, linked_records}} = MarcoPolo.load_record(conn, rid)
iex> record.fields
%{"foo" => "bar"}
script(conn, language, text, opts \\ [])

Specs

script(pid, String.t, String.t, Keyword.t) ::
  {:ok, term} |
  {:error, term}

Executes a script in the given language on the database conn is connected to.

The text of the script is passed as text. opts is a list of options.

Note: for this to work, scripting must be enabled in the server configuration. You can read more about scripting in the OrientDB docs.

This operation can only be performed on connections to a database. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Options

This function accepts the following options:

  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

Examples

iex> script = "for (i = 0; i < 3; i++) db.command('INSERT INTO Foo(idx) VALUES (' + i + ')');"
iex> {:ok, last_record} = MarcoPolo.script(conn, "Javascript", script)
iex> last_record.fields["idx"]
2
start_link(opts \\ [])

Specs

start_link(Keyword.t) :: GenServer.on_start

Starts the connection with an OrientDB server.

This function accepts the following options:

  • :user - (string) the OrientDB user. This option is required.
  • :password - (string) the OrientDB password. This option is required.
  • :connection - specifies the connection type. This option is required. To learn more about the connection type, refer to the docs for the MarcoPolo module (there's a "Connection type" section). It can be:
    • :server - connects to the server to perform server operations
    • {:db, db_name, db_type} - connects to a database to perform database operations. db_type can be either :document or :graph.
  • :host - (string or charlist) the host where the OrientDB server is running. Defaults to "localhost".
  • :port - (integer) the port where the OrientDB server is running. Defaults to 2424.

It also accepts all options that GenServer.start_link/3 accepts (e.g., :name for registering the new process or :timeout for providing a connection timeout).

Examples

Connecting to the server:

iex> {:ok, conn} = MarcoPolo.start_link user: "admin", password: "admin", connection: :server
iex> is_pid(conn)
true

Connecting to a database:

iex> connection = {:db, "MyDatabase", :document}
iex> {:ok, conn} = MarcoPolo.start_link user: "admin", password: "admin", connection: connection
iex> is_pid(conn)
true
stop(conn)

Specs

stop(pid) :: :ok

Closes the connection (asynchronously), doing the required cleanup work.

It always returns :ok as soon as it's called (regardless of the operation being successful) since it is asynchronous.

Examples

iex> MarcoPolo.stop(conn)
:ok
transaction(conn, operations, opts \\ [])

Specs

transaction(pid, [tx_operation], Keyword.t) ::
  {:ok, %{created: [{MarcoPolo.RID.t, non_neg_integer}], updated: [{MarcoPolo.RID.t, non_neg_integer}]}} |
  {:error, term}

Runs operations inside a transaction on the database to which conn is connected.

This function will run a list of operations inside a server-side transaction. Operations can be creations, updates and deletions of records. Each operation has the form:

{op_type, record}

where op_type can be one of :create, :update or :delete.

Options

This function accepts the following options:

  • :using_tx_log - tells the server whether to use the transaction log to recover the transaction or not. Defaults to true. Note: disabling the log could speed up the execution of the transaction, but it makes impossible to rollback the transaction in case of errors. This could lead to inconsistencies in indexes as well, since in case of duplicated keys the rollback is not called to restore the index status.
  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

Examples

iex> ops = [{:create, %MarcoPolo.Document{class: "Foo", fields: %{"foo" => "bar"}}},
...>        {:delete, %MarcoPolo.Document{rid: %MarcoPolo.RID{cluster_id: 1, position: 2}}]
iex> {:ok, %{created: [created], updated: []} = MarcoPolo.transaction(conn, ops)
iex> created
%MarcoPolo.Document{class: "Foo", fields: %{"foo" => "bar"}, rid: %MarcoPolo.RID{...}}
update_record(conn, rid, version, new_record, update_content?, opts \\ [])

Specs

update_record(pid, MarcoPolo.RID.t, non_neg_integer, MarcoPolo.Document.t, boolean, Keyword.t) ::
  {:ok, non_neg_integer} |
  {:error, term}

Updates the given record in the databse to which conn is connected.

The record to update is identified by its rid; version is the version to update. new_record is the updated record. update_content? can be:

  • true - the content of the record has been changed and should be updated in the storage.
  • false - the record was modified but its own content has not changed: related collections (e.g. RidBags) have to be updated, but the record version and its contents should not be updated.

When the update is successful, {:ok, new_version} is returned; otherwise, {:error, reason}.

Options

This function accepts the following options:

  • :no_response - if true, send the request to the OrientDB server without waiting for a response. This performs a fire and forget operation, returning :ok every time.
  • :timeout - operation timeout in milliseconds. If this timeout expires, an exit signal will be sent to the calling process.

This operation can only be performed on connections to a database. To learn more about the connection type, look at the "Connection type" section in the docs for the MarcoPolo module.

Examples

iex> rid = %MarcoPolo.RID{cluster_id: 1, position: 10}
iex> new_record = %MarcoPolo.Document{class: "MyClass", fields: %{foo: "new value"}}
iex> MarcoPolo.update_record(conn, rid, 1, new_record, true)
{:ok, 2}