transistor 0.3.1

Crux Datalog Client
Documentation

Transistor

A Rust Crux Client crate/lib. For now, this crate intends to support 2 ways to interact with Crux:

Other solutions may be added after the first release.

To add this crate to your project you should add the following line to dependencies in Cargo.toml:

transistor = "0.3.1"
  • For information on Crux and how to use it, please follow the link to opencrux. Note that the current crate version (Docker only) uses a few modified endpoints due to its Docker implementation.

  • For examples on usage, please refer to examples directory.

Creating a Crux Client

All operations with Transistor start in the module client with Crux::new("localhost", "3000"). The struct Crux is responsabile for defining request HeadersMap and the request URL. The URL definition is required and it is done by the static function new, which receives as argument a host and a port and returns a Crux instance. To change HeadersMap info so that you can add AUTHORIZATION you can use the function with_authorization that receives as argument the authorization token and mutates the Crux instance.

  • HeaderMap already contains the header Content-Type: application/edn.

Finally, to create a Crux Client the function <type>_client should be called, for example docker_client. This function returns a struct that contains all possible implementarions to query Crux Docker.

use transistor::client::Crux;

// DockerClient with AUTHORIZATION
let auth_client = Crux::new("127.0.0.1","3000").with_authorization("my-auth-token").docker_client();

// DockerClient without AUTHORIZATION
let client = Crux::new("127.0.0.1","3000").docker_client();

Docker Client

Once you have called docker_client you will have an instance of the DockerClient struct which has a bunch of functions to query Crux on Docker:

  • state queries endpoint / with a GET. No args. Returns various details about the state of the database.
let body = client.state().unwrap();

// StateResponse { 
//     index___index_version: 5, 
//     doc_log___consumer_state: None, 
//     tx_log___consumer_state: None, 
//     kv___kv_store: "crux.kv.rocksdb.RocksKv", 
//     kv___estimate_num_keys: 56, 
//     kv___size: 2271042 
// }
  • tx_log requests endpoint /tx-log via POST. A Vector of Action is expected as argument. The "write" endpoint, to post transactions.
use transistor::docker::{Action};
use transistor::client::Crux;
use transistor::types::{CruxId};

let person1 = Person {
    crux__db___id: CruxId::new("jorge-3"), 
    ..
};

let person2 = Person {
    crux__db___id: CruxId::new("manuel-1"), 
    ..
};

let action1 = Action::Put(person1.serialize());
let action2 = Action::Put(person2.serialize());

let body = client.tx_log(vec![action1, action2]).unwrap();
// {:crux.tx/tx-id 7, :crux.tx/tx-time #inst \"2020-07-16T21:50:39.309-00:00\"}
  • tx_logs requests endpoint /tx-log via GET. No args. Returns a list of all transactions.
use transistor::client::Crux;

let body = client.tx_logs().unwrap();

// TxLogsResponse {
//     tx_events: [
//         TxLogResponse {
//             tx___tx_id: 0,
//             tx___tx_time: "2020-07-09T23:38:06.465-00:00",
//             tx__event___tx_events: Some(
//                 [
//                     [
//                         ":crux.tx/put",
//                         "a15f8b81a160b4eebe5c84e9e3b65c87b9b2f18e",
//                         "125d29eb3bed1bf51d64194601ad4ff93defe0e2",
//                     ],
//                 ],
//             ),
//         },
//         TxLogResponse {
//             tx___tx_id: 1,
//             tx___tx_time: "2020-07-09T23:39:33.815-00:00",
//             tx__event___tx_events: Some(
//                 [
//                     [
//                         ":crux.tx/put",
//                         "a15f8b81a160b4eebe5c84e9e3b65c87b9b2f18e",
//                         "1b42e0d5137e3833423f7bb958622bee29f91eee",
//                     ],
//                 ],
//             ),
//         },
//         ...
//     ]
// } 
  • entity requests endpoint /entity via POST. A serialized CruxId, serialized Edn::Key or a String containing a keyword must be passed as argument. Returns an entity for a given ID and optional valid-time/transaction-time co-ordinates.
let person = Person {
    crux__db___id: CruxId::new("hello-entity"), 
    ...
};

let client = Crux::new("localhost", "3000").docker_client();

let edn_body = client.entity(person.crux__db___id.serialize()).unwrap();
// Map(
//     Map(
//         {
//             ":crux.db/id": Key(
//                 ":hello-entity",
//             ),
//             ":first-name": Str(
//                 "Hello",
//             ),
//             ":last-name": Str(
//                 "World",
//             ),
//         },
//     ),
// )
  • entity_tx requests endpoint /entity-tx via POST. A serialized CruxId, serialized Edn::Key or a String containing a keyword must be passed as argument. Returns the transaction that most recently set a key.
use transistor::docker::{Action};
use transistor::client::Crux;
use transistor::types::{CruxId};

let person = Person {
    crux__db___id: CruxId::new("hello-entity"), 
    ...
};

let client = Crux::new("localhost", "3000").docker_client();

let tx_body = client.entity_tx(person.crux__db___id.serialize()).unwrap();
// EntityTxResponse {
//     db___id: "d72ccae848ce3a371bd313865cedc3d20b1478ca",
//     db___content_hash: "1828ebf4466f98ea3f5252a58734208cd0414376",
//     db___valid_time: "2020-07-20T20:38:27.515-00:00",
//     tx___tx_id: 31,
//     tx___tx_time: "2020-07-20T20:38:27.515-00:00",
// }
  • document_by_id requests endpoint /document/{:content-hash} via GET. {:content-hash} can be obtained with function entity_tx. Returns the document for a given content hash.
use transistor::docker::{Action};
use transistor::client::Crux;
use transistor::types::{CruxId};

let person = Person {
    crux__db___id: CruxId::new("hello-entity"),
    first_name: "Hello".to_string(),
    last_name: "World".to_string()
};

let client = Crux::new("localhost", "3000").docker_client();

let document = client.document_by_id(tx_body.db___content_hash).unwrap();
// Person {
//     crux__db___id: CruxId(
//         ":hello-entity",
//     ),
//     first_name: "Hello",
//     last_name: "World",
// }
  • documents requests endpoint /documents via POST. The argument of this reuqest is a vector of content-hashes that converts to an edn set as a body. Returns a map of document ids and respective documents for a given set of content hashes submitted in the request body.
use transistor::docker::{Action};
use transistor::client::Crux;
use transistor::types::{CruxId};

let person1 = Person {
    crux__db___id: CruxId::new("hello-entity"),
    ...
};

let person2 = Person {
    crux__db___id: CruxId::new("hello-documents"),
    ...
};

let client = Crux::new("localhost", "3000").docker_client();

let contesnt_hashes = vec![tx_body1.db___content_hash, tx_body2.db___content_hash];

let documents = client.documents(contesnt_hashes).unwrap();
// {
//     "1828ebf4466f98ea3f5252a58734208cd0414376": Map(
//         Map(
//             {
//                 ":crux.db/id": Key(
//                     ":hello-entity",
//                 ),
//                 ":first-name": Str(
//                     "Hello",
//                 ),
//                 ":last-name": Str(
//                     "World",
//                 ),
//             },
//         ),
//     ),
//     "1aeb98a4e11f30827e0304a9c289aad673b6cf57": Map(
//         Map(
//             {
//                 ":crux.db/id": Key(
//                     ":hello-documents",
//                 ),
//                 ":first-name": Str(
//                     "Hello",
//                 ),
//                 ":last-name": Str(
//                     "Documents",
//                 ),
//             },
//         ),
//     ),
// }

Action is an enum with a set of options to use in association with the function tx_log:

  • PUT - Write a version of a document
  • Delete - Deletes the specific document at a given valid time
  • Evict - Evicts a document entirely, including all historical versions (receives only the ID to evict)

Dependencies

A strong dependency of this crate is the edn-rs crate, as many of the return types are in the Edn format. The sync http client is reqwest with blocking feature enabled.

Licensing

This project is licensed under LGPP-3.0 (GNU Lesser General Public License v3.0).