Arche: The ancient Greek muse of origins
Arche provides state management for Cassandra via Alia.
- Cassandra state management (Cluster / Session / Prepared Statements / Execution Options / UDTs)
- Optional DI/lifecycle via Integrant or Component
- Externalisation of query definitions via an extension of HugSQL to support CQL
- Automatic hyphen/underscore translation with when using HugCQL
- Query configuration by simple EDN map of key/cql or key/map (when configuring per-query opts)
- Prepared statement execution by keyword, supports all Alia execution modes (vanilla, core.async, manifold)
- User Defined Type (UDT) encoding by keyword
- As much configuration from EDN as possible (see: tagged literals)
-
Cassandra state management, statement preparation, UDT preparation, and execution,
-
com.troy-west.arche/arche-hugcql
Externalise CQL definition and execution options in file/resource. Automatic hyphen/underscore translation.
-
com.troy-west.arche/arche-integrant
Cassandra lifecycle and DI via Integrant
-
com.troy-west.arche/arche-component
Cassandra lifecycle and DI via Component
-
com.troy-west.arche/arche-async
Core.async statement execution (shadows alia.async)
-
com.troy-west.arche/arche-manifold
Manifold statement execution (shadows alia.manifold)
Define your schema (optionally, automate test cluster management with CCM-CLJ)
The tests and examples included with this project use the following:
CREATE TYPE asset (
code text,
currency text,
notional text);
CREATE TABLE trade (
id text,
asset_basket map<text, frozen<asset>>,
PRIMARY KEY (id));
CREATE TABLE client (
id text,
name text,
PRIMARY KEY (id));
Arche-HugCQL makes use of HugSQL to parse CQL statements externalised in files or resources.
- --:name is converted into (an optionally namespaced) keyword that identifies this statement for execution.
- --:options is translated into EDN and applied as default execution configuration for this statement
Hyphens in select columns and named parameters are automatically translated by the quoted identifier technique.
e.g. The following HugCQL file:
--:name test/insert-client
INSERT INTO client (id, name) VALUES (:id, :name)
--:name test/select-client
--:options {:fetch-size 500}
SELECT * FROM client WHERE id = :id
--:name test/insert-trade
INSERT INTO trade (id, asset_basket) VALUES (:id, :asset-basket)
--:name test/select-trade
SELECT id, :i:asset-basket FROM trade where id = :id
Translates to the following map of key -> statements:
{:test/insert-client "INSERT INTO client (id, name) VALUES (:id, :name)"
:test/select-client {:cql "SELECT * FROM client WHERE id = :id"
:opts {:fetch-size 500}}
:test/insert-trade "INSERT INTO trade (id, asset_basket) VALUES (:id, :\"asset-basket\")"
:test/select-trade "SELECT id, asset_basket as \"asset-basket\" FROM trade where id = :id"}
After creating a connection, those statements can be executed by keyword
(arche/execute connection
:test/select-trade
{:values {:id "id"}}))
=> [{:id "some-id"
:asset-basket {"long" {:code "PB" ;; automatic underscore / hyphen translation of columns / keys
:currency "GBP"
:notional "12"}}}]
For convenience, a tagged literal is provided that translates file/resource paths to statements maps, e.g:
#arche/hugcql "stmts1.hcql"
Define statements and UDTs that match the expected schema
(def udts {:test/asset {:name "asset"}})
(def statements {:test/insert-client "INSERT INTO client (id, name) VALUES (:id, :name)"
:test/select-client {:cql "SELECT * FROM client WHERE id = :id"
:opts {:fetch-size 500}}
:test/insert-trade "INSERT INTO trade (id, asset_basket) VALUES (:id, :\"asset-basket\")"
:test/select-trade "SELECT id, asset_basket as \"asset-basket\" FROM trade where id = :id"})
Create an arche connection with the cluster and (optional) keyspace, statements, and UDTs.
(require '[troy-west.arche :as arche])
(def connection (arche/connect (alia/cluster {:contact-points ["127.0.0.1"]
:port 19142})
{:keyspace "sandbox"
:statements statements
:udts udts}))
Using UDT encoders.
(arche/encode-udt connection :test/asset {:code "AB"
:currency "GBP"
:notional "12"})
;; creates UDTValue instance
;; #object[com.datastax.driver.core.UDTValue 0x29632e50 "{code:'AB',currency:'GBP',notional:'12'}"]
Arche provides modules/functions that shadow all standard Alia execution, in modules that similarly shadow Alia.
(arche/execute connection
:test/insert-client
{:values {:id "id-1" :name "Carol"}})
(arche.async/execute-chan connection
:test/insert-client
{:values {:id "id-1" :name "Carol"}})
(arche.manifold/execute connection
:test/insert-client
{:values {:id "id-1" :name "Carol"}})
DI/Lifecycle management with Integrant (recommended)
Create an Ingrant System with HugCQL externalised CQL prepared statements.
(def system
(integrant/init
{:arche/cluster {:contact-points ["127.0.0.1"]
:port 19142}
:arche/connection {:keyspace "sandbox"
:cluster (integrant/ref :arche/cluster)
:statements #arche/hugcql "cql/test.hcql"
:udts [{:arche/asset {:name "asset"}}]}}))
(def connection (:arche/connection system)
(arche/execute connection
:arche/insert-client
{:values {:id "id-1" :name "Carol"}})
(arche.async/execute-chan connection
:arche/select-client
{:values {:id "id-1"}})
(arche.manifold/execute
connection
:arche/insert-trade
{:values {:id "trade-1"
:asset-basket {"long" (arche/encode-udt
connection
:arche/asset
{:code "AB"
:currency "GBP"
:notional "12"})
"short" (arche/encode
connection
:arche/asset
{:code "ZX"
:currency "AUD"
:notional "98"})}}}))
DI/Lifecycle managemet via Component
(def system
(component/start-system
{:cluster #arche/cluster{:contact-points ["127.0.0.1"]
:port 19142}
:connection #arche/connection{:keyspace "sandbox"
:statements [#arche/hugcql "cql/test1.hcql"
#arche/hugcql "cql/test2.hcql"]
:udts [{:arche/asset {:name "asset"}}]
:cluster :cluster}}))
(def connection (:connection system)
Copyright © 2017 Troy-West, Pty Ltd.
Distributed under the Eclipse Public License either version 2.0 or (at your option) any later version.