The ClojureWerkz Blog

News and updates about ClojureWerkz projects

Neocons 3.0.0 Is Released

TL;DR

Neocons is a feature rich idiomatic Clojure client for the Neo4J REST API.

3.0.0 is a major release. It has a major breaking API change compared to 2.0.x: every function now takes a connection as an explicit argument instead of relying on a dynamic var.

Changes between Neocons 2.0.0 and 3.0.0

Breaking Change: Explicit Connection Argument

Neocons no longer uses a dynamic var to hold the state of the connection. This leads to significant changes to the API as the connection has to be passed to functions. The position of the connection argument is always the first argument for the sake of consistency:

1
2
3
4
5
6
7
8
9
10
11
(require '[clojurewerkz.neocons.rest :as nr])
(require '[clojurewerkz.neocons.rest.nodes :as nn])

;; with Neocons 2.0

(nr/connect! "http://localhost:7476/db")
(nn/create {:url "http://clojurewerkz.org/"})

;; with Neocons 3.0
(let [conn (nr/connect "http://localhost:7476/db")]
  (nn/create conn {:url "http://clojurewerkz.org/"}))

Additionally connect! function in clojurewerkz.neocons.rest no longer exists. This has been replaced by function connect in clojurewerkz.neocons.rest. The connect function has the same arguments as the connect! function only it returns a Connection record.

The Connection record has a key called :options which can be used to pass additional parameters to be used by clj-http like debug.

Contributed by Rohit Aggarwal.

Clojure 1.6

Neocons now depends on org.clojure/clojure version 1.6.0. It is still compatible with Clojure 1.4 and if your project.clj depends on a different version, it will be used, but 1.6 is the default now.

Cheshire 5.3

Neocons now uses Cheshire 5.3.

clj-http upgraded to 0.9.1

Neocons now uses clj-http 0.9.1.

Neo4J 2.0 Index Creation Fix

Neocons will now use a key name accepted by Neo4J 2.0.0 GA and later version when creating indexes.

Contributed by Rohit Aggarwal.

Change Log

We encourage all users to give this version a try.

Neocons change log is available on GitHub.

Documentation Updates

Neocons documentation has been updated to cover the new API.

Thank You, Contributors

We’d like to thank Rohit Aggarwal for single-handedly doing all the work in Neocons 3.0. Contributors like Rohit is why open source software works as well as it does.

Neocons is a ClojureWerkz Project

Neocons is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • Monger, a Clojure MongoDB client for a more civilized age
  • Cassaforte, a Cassandra client built around CQL 3
  • Quartzite, a powerful scheduling library

and several others. If you like Neocons, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

Michael on behalf of the ClojureWerkz Team

Langohr 2.11.0 Is Released

TL;DR

Langohr is a small Clojure RabbitMQ client.

2.11.0 is a minor feature release.

Changes between Langohr 2.10.x and 2.11.0

Multi-Host Support In langohr.core/connect

langohr.core/connect now supports :hosts as well as :host. The hosts provided will be iterated over, the first reachable host will be used.

Example:

1
2
3
4
5
6
7
(require '[langohr.core :as rmq])

(rmq/connect {:hosts #{"192.168.1.2" "192.168.1.3"}})
;; uses port 5688 for both hosts
(rmq/connect {:hosts #{"192.168.1.2" "192.168.1.3"} :port 5688})
;; uses multiple host/port pairs
(rmq/connect {:hosts #{["192.168.1.2" 5688] ["192.168.1.3" 5689]}})

Change Log

Langohr change log is available on GitHub.

Langohr is a ClojureWerkz Project

Langohr is part of the group of libraries known as ClojureWerkz, together with

  • Elastisch, a minimalistic well documented Clojure client for ElasticSearch
  • Cassaforte, a Clojure Cassandra client built around CQL 3.0
  • Monger, a Clojure MongoDB client for a more civilized age
  • Neocons, a client for the Neo4J REST API
  • Quartzite, a powerful scheduling library

and several others. If you like Langohr, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About The Author

Michael on behalf of the ClojureWerkz Team

Welle 3.0.0-rc1 Is Released

TL;DR

Welle is an expressive Clojure client for Riak with batteries included.

3.0.0-rc1 is a major release that has breaking API changes.

Changes between Welle 2.0.x and 3.0

Welle 3.0 has breaking API changes in most namespaces.

Client (Connection) is Explicit Argument

All Welle public API functions that issue requests to Riak now require a client (HTTP or PBC) to be passed as an explicit argument:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(ns welle.docs.examples
  (:require [clojurewerkz.welle.core    :as wc]
            [clojurewerkz.welle.buckets :as wb]
            [clojurewerkz.welle.kv      :as kv])
  (:import com.basho.riak.client.http.util.Constants))

(let [conn   (wc/connect)
      bucket "accounts"
      key    "novemberain"
      val    {:name "Michael" :age 27 :username key}]
  (wb/create conn bucket)
  ;; stores data serialized as JSON
  (kv/store conn bucket key val {:content-type Constants/CTYPE_JSON_UTF8})
  ;; fetches it back
  (kv/fetch conn bucket key))

Options as Maps

Functions that take optional arguments now require them to be proper maps (and not pseudo-keywords):

1
2
3
4
5
;; in 2.0
(kv/store bucket key val :content-type Constants/CTYPE_JSON_UTF8)

;; in 3.0
(kv/store conn bucket key val {:content-type Constants/CTYPE_JSON_UTF8})

HTTPComponents 4.3

Welle now excludes HTTPComponents dependency for Riak client and instead uses version 4.3 which clj-http depends on.

Change Log

Welle change log is available on GitHub.

Welle is a ClojureWerkz Project

Welle is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • Monger, a Clojure MongoDB client for a more civilized age
  • Neocons, a feature rich idiomatic Clojure client for the Neo4J REST API
  • Quartzite, a powerful scheduling library

and several others. If you like Welle, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

Donations

ClojureWerkz accepts donations. If you feel like our projects save you time, consider donating. Thanks.

Michael on behalf of the ClojureWerkz Team

Cassaforte 1.3.0 Is Released

TL;DR

Cassaforte is a new Clojure client for Apache Cassandra. It is built around CQL 3 and focuses on ease of use. You will likely find that using Cassandra from Clojure has never been so easy.

1.3.0 is a minor release that introduces a few minor features and improves compatibility with Cassandra 2.0.

Changes between Cassaforte 1.2.x and 1.3.0

Clojure 1.6 By Default

The project now depends on org.clojure/clojure version 1.6.0. It is still compatible with Clojure 1.4 and if your project.clj depends on a different version, it will be used, but 1.6 is the default now.

We encourage all users to upgrade to 1.6, it is a drop-in replacement for the majority of projects out there.

Cassandra Java Driver Update

Cassandra Java driver has been updated to 2.0.x.

UUID Generation Helpers

clojurewerkz.cassaforte.uuids is a new namespace that provides UUID generation helpers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(require '[clojurewerkz.cassaforte.uuids :as uuids])

(uuids/random)
;= #uuid "d43fdc16-a9c3-4d0f-8809-512115289537"

(uuids/time-based)
;= #uuid "90cf6f40-4584-11e3-90c2-65c7571b1a52"

(uuids/unix-timestamp (uuids/time-based))
;= 1383592179743

(u/start-of (u/unix-timestamp (u/time-based)))
;= #uuid "ad1fd130-4584-11e3-8080-808080808080"

(u/end-of (u/unix-timestamp (u/time-based)))
;= #uuid "b31abb3f-4584-11e3-7f7f-7f7f7f7f7f7f"

Hayt Update

Hayt dependency has been updated to 1.4.1, which supports if-not-exists in create-keyspace:

1
2
3
4
5
(create-keyspace "main"
           (if-not-exists)
           (with {:replication
                    {:class "SimpleStrategy"
                     :replication_factor 1 }}))

Extra Clauses Support in insert-batch

It is now possible to use extra CQL clauses for every statement in a batch insert (e.g. to specify TTL):

1
2
3
(cql/insert-batch "table"
  {:something "cats"}
  [{:something "dogs"} (using :ttl 60)])

Contributed by Sam Neubardt.

Alternative where syntax

Now it is possible to specify hash in where clause, which makes queries more composable:

1
2
3
4
(select :users
        (where {:city "Munich"
                :age [> (int 5)]})
        (allow-filtering true))

Batch Insert Improvements

Clauses to be specified for each record in insert-batch:

1
2
3
(let [input [[{:name "Alex" :city "Munich"} (using :ttl 350)]
             [{:name "Alex" :city "Munich"} (using :ttl 350)]]]
  (insert-batch th/session :users input))

Contributed by Sam Neubardt.

News and Updates

New releases and updates are announced on Twitter. Cassaforte also has a mailing list, feel free to ask questions and report issues there.

Cassaforte is a ClojureWerkz Project

Cassaforte is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Monger, a Clojure MongoDB client for a more civilized age
  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • EEP, a Clojure library for stream (event) processing
  • Neocons, a Clojure client for the Neo4J REST API
  • Quartzite, a powerful scheduling library

and several others. If you like Cassaforte, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About the Author

Michael on behalf of the ClojureWerkz Team.

Monger 2.0.0-rc1 Is Released

TL;DR

Monger is an idiomatic Clojure MongoDB driver for a more civilized age. It has batteries included, offers powerful expressive query DSL, strives to support every MongoDB 2.0+ feature and has sane defaults. It also has solid documentation.

2.0.0 is a major backwards-incompatible release that implements in Monger the major breaking API changes announced earlier for several ClojureWerkz projects.

Changes between 1.8.0 and 2.0.0

2.0 is a major release that has breaking public API changes.

Explicit Connection/DB/GridFS Argument

In Monger 2.0, all key public API functions require an explicit DB/connection/GridFS object to be provided instead of relying on a shared dynamic var. This makes Monger much easier to use with systems such as Component and Jig, as well as concurrent applications that need to work with multiple connections, database, or GridFS filesystems.

In other words, instead of

1
2
3
(require '[monger.collection :as mc])

(mc/insert "libraries" {:name "Monger"})

it is now necessary to do

1
2
3
(require '[monger.collection :as mc])

(mc/insert db "libraries" {:name "Monger"})

This also means that monger.core/connect! and monger.core/connect-via-uri! were removed, as was monger.multi namespaces.

To connect to MongoDB, use monger.core/connect:

1
2
3
(require '[monger.core :as mg])

(let [conn (mg/connect)])

or monger.core/connect-via-uri:

1
2
3
(require '[monger.core :as mg])

(let [{:keys [conn db]} (mg/connect-via-uri "mongodb://clojurewerkz/monger:monger@127.0.0.1/monger-test4")])

To get a database reference, use monger.core/get-db, which now requires a connection object:

1
2
3
4
(require '[monger.core :as mg])

(let [conn (mg/connect)
      db   (mg/get-db conn "monger-test")])

Options as Maps

Functions that take options now require a proper Clojure map instead of pseudo keyword arguments:

1
2
3
4
5
# in Monger 1.x
(mc/update db coll {} {:score 0} :multi true)

# in Monger 2.x
(mc/update db coll {} {:score 0} {:multi true})

Change Log

Monger change log is available on GitHub.

Monger is a ClojureWerkz Project

Monger is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Cassaforte, a Clojure Cassandra client built around CQL
  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • Welle, a Riak client with batteries included
  • Neocons, a client for the Neo4J REST API
  • Quartzite, a powerful scheduling library

and several others. If you like Monger, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About the Author

@michaelklishin on behalf of the ClojureWerkz Team

Langohr 2.10.1 Is Released

TL;DR

Langohr is a small Clojure RabbitMQ client.

2.10.1 is a bug fix release.

Changes between Langohr 2.9.x and 2.10.1

Retries for all IOExceptions During Recovery

All IOException subclasses thrown during connection recovery attempts will now be retried.

Contributed by Paul Bellamy (Xively).

RabbitMQ Java Client Upgrade

RabbitMQ Java client dependency has been updated to 3.3.1.

Change Log

Langohr change log is available on GitHub.

Langohr is a ClojureWerkz Project

Langohr is part of the group of libraries known as ClojureWerkz, together with

  • Elastisch, a minimalistic well documented Clojure client for ElasticSearch
  • Cassaforte, a Clojure Cassandra client built around CQL 3.0
  • Monger, a Clojure MongoDB client for a more civilized age
  • Neocons, a client for the Neo4J REST API
  • Quartzite, a powerful scheduling library

and several others. If you like Langohr, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About The Author

Michael on behalf of the ClojureWerkz Team

Monger 1.8.0 Is Released

TL;DR

Monger is an idiomatic Clojure MongoDB driver for a more civilized age. It has batteries included, offers powerful expressive query DSL, strives to support every MongoDB 2.0+ feature and has sane defaults. It also has solid documentation.

1.8.0 is a minor backwards-compatible release that updates MongoDB Java driver and adds a few minor features. The next release will be 2.0 with some major breaking API changes that we’ve announced earlier.

Changes between 1.7.0 and 1.8.0

Clojure 1.6

Monger now depends on org.clojure/clojure version 1.6.0. It is still compatible with Clojure 1.4 and if your project.clj depends on a different version, it will be used, but 1.6 is the default now.

monger.result Use with WriteConcerns is Deprecated

MongoDB Java driver 2.12.x no longer guarantees connection affinity for thread pool threads.

This means that WriteConcern#getLastError is no longer a safe from concurrency hazards. Therefore the use of monger.result functions on WriteConcern instances is now deprecated in MongoDB Java client and Monger.

MongoDB Java Driver Update

MongoDB Java driver dependency has been updated to 2.12.x.

Default WriteConcern Change

Monger now uses WriteConcern/ACKNOWLEDGED by default. Functionality-wise it is the same as WriteConcern/SAFE in earlier versions.

monger.core/connect-via-uri

monger.core/connect-via-uri is a version of monger.core/connect-via-uri! which returns the connection instead of mutating a var.

It should be used by projects that are built from reloadable components, together with monger.multi.*.

Future Plans

The next Monger release will be 2.0 with some major breaking API changes that we’ve announced earlier.

Change Log

Monger change log is available on GitHub.

Monger is a ClojureWerkz Project

Monger is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Cassaforte, a Clojure Cassandra client built around CQL
  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • Welle, a Riak client with batteries included
  • Neocons, a client for the Neo4J REST API
  • Quartzite, a powerful scheduling library

and several others. If you like Monger, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About the Author

@michaelklishin on behalf of the ClojureWerkz Team

Meltdown 1.0.0 Is Released

TL;DR

Meltdown is a Clojure interface to Reactor, an asynchronous programming, event passing and stream processing toolkit for the JVM.

1.0.0 is based on Reactor 1.1.0 which is now final.

Changes between 1.0.0-beta12 and 1.0.0

Reactor Update

Reactor is updated to 1.1.0.RELEASE.

Change log

Meltodwn change log is available on GitHub.

Meltdown is a ClojureWerkz Project

Meltdown is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Elastisch, a Clojure client for ElasticSearch
  • Monger, a Clojure MongoDB client for a more civilized age
  • Cassaforte, a Clojure Cassandra client
  • Titanium, a Clojure graph library
  • Neocons, a client for the Neo4J REST API
  • Quartzite, a powerful scheduling library

and several others. If you like Meltdown, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About the Author

Michael on behalf of the ClojureWerkz Team

Welle 2.0.0 Is Released

TL;DR

Welle is an expressive Clojure client for Riak with batteries included.

2.0.0 is a major release that has breaking API changes and introduces an important bug fix, dependency updates and support for Riak 1.4 features.

It does not include our recently announced “explicit client” changes. Those will be part of 3.0.

Changes between Welle 1.5.0 and 2.0

Welle 2.0 has breaking API changes in clojurewerkz.welle.kv functions.

Changes in K/V Function Return Values

This is a breaking API change.

Welle 2.0 changes how Riak responses are represented as Clojure maps. Welle now will correctly preserve all vector clocks associated with multiple siblings in the response and the response itself.

This means that welle.kv/modify will work correctly and won’t make sibling explosions worse.

The most important part of the change is how responses are represented: every response is an immutable map that has :result key as well as other metadata keys (:has-value?, :has-siblings?, :modified?, :content-type and so on).

This contrasts with earlier versions, where results were returned directly by functions such as welle.kv/fetch, it is now possible to destructure the response in order to obtain the returned value:

1
2
3
4
(require '[clojurewerkz.welle.kv :as kv])

(let [{:keys [result] :as m} (kv/fetch bucket-name k :r 1)]
  (comment "Do something with the result"))

Here are the keys that clojurewerkz.welle.kv/fetch returns now for every response:

  • :result: one or more objects returned by Riak
  • :vclock: vector clock of the response
  • :has-siblings?: true if response has siblings
  • :has-value?: true if response is non-empty
  • :modified?: false when conditional GET returned a non-modified response
  • :deleted?: true if this object has been deleted but there is a vclock for it

Clojure 1.3 Support Dropped

Welle no longer supports Clojure 1.3.

Counters Support (Riak 1.4+)

clojurewerkz.welle.counters is a new namespace that provides operations on Riak counters:

1
2
3
4
5
6
7
8
9
10
11
12
(require '[clojurewerkz.welle.counters :as wcnt])

(let [bucket-name "counters"
      counter     "hit-points"]
  (wcnt/increment-counter bucket-name counter)
  ;= 1
  (wcnt/fetch-counter bucket-name counter)
  ;= 1
  (wcnt/increment-counter bucket-name counter :value 2))
  ;= 3
  (wcnt/increment-counter bucket-name counter :value -3))
  ;= 0

Riak Java Client Update

Welle now uses Riak Java client 1.4.2.

Cheshire Update

Cheshire has been updated to 5.2.0.

clj-http Update

clj-http has been updated to 0.7.7.

Support Update

ClojureWerkz Support has been updated to 0.20.0.

Ports Support in PB Cluster Client

While creating a protocol buffer cluster client you can now provide hosts and ports separated by a colon, e.g. “127.0.0.1:10017”. If a port is not provided, the default port will be used.

So now you can use following format:

1
2
3
4
5
6
7
(wc/connect-to-cluster-via-pb! ["10.0.1.2",
                  "10.0.1.3",
              "10.0.1.4",
              "10.0.1.5",
              "10.0.1.6"])

as well as following format:

clojure (wc/connect-to-cluster-via-pb! [“127.0.0.1:10017”,

                "127.0.0.1:10027",
            "127.0.0.1:10037",
            "127.0.0.1:10047"])

“`

Validateur Dependency Dropped

Validateur is no longer a dependency of Welle.

Don’t worry, they still work well together.

Optional Keywordization of Keys With JSON Serialization

Automatic JSON serialization previously unconditionally converted keys to keywords. This may be a problem for some projects, because keywords are not garbage collected.

clojurewerkz.welle.conversion/*convert-json-keys-to-keywords* is a new dynamic var that controls this behavior. When bound to false, automatic JSON serialization won’t convert keys to keywords.

Change Log

Welle change log is available on GitHub.

Welle is a ClojureWerkz Project

Welle is part of the group of libraries known as ClojureWerkz, together with

  • Langohr, a Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
  • Elastisch, a minimalistic Clojure client for ElasticSearch
  • Monger, a Clojure MongoDB client for a more civilized age
  • Neocons, a feature rich idiomatic Clojure client for the Neo4J REST API
  • Quartzite, a powerful scheduling library

and several others. If you like Welle, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

Donations

ClojureWerkz accepts donations. If you feel like our projects save you time, consider donating. Thanks.

Michael on behalf of the ClojureWerkz Team

Balagan 1.0.0 Is Released

What is Balagan

Balagan is a tiny Clojure library for data structure transformation inspired by Enlive.

Supported Clojure Versions

Balagan targets Clojure 1.4+, tested against 3 Clojure versions x 2 JDKs on travis-ci.org, and is released under the Eclipse Public License.

Documentation and Examples

Balagan builds on ideas from Enlive. It may help to get familiar with them first.

Let’s say you’re working on a Data Access layer for the application. You have a user entry represented as hash:

1
2
3
4
(def user
  {:name "Alex"
   :birth-year 1990
   :nickname "ifesdjeen"})

Transformation

Now, we can start transforming users the way we want: add, remove fields based on certain conditions.

1
2
3
4
5
(update user
           []                  (add-field :cool-dude true) ;; adds a field :cool-dude with value true
           (new-path [:age])   #(- 2014 (:birth-year %))   ;; explicit adding of a new field, calculated from the existing data
           (new-path [:posts]) #(fetch-posts (:name %))    ;; fetching some related data from the DB
           [:posts :*]         #(update-posts %))       ;; apply some transformations to all the fetched posts, if there are any

Queries

Queries are very similar to how you’d query your data with filter in Clojure:

1
2
3
4
(let [data {:a {:b [{:c 1} {:c 2} {:c 3}]
                :d [{:c 5} {:c 6} {:c 7}]}}]
  (select data  [:* :* even? :c]))
;; => (1 3 5 7)  

Results are returned in the order they’ve been seen in your data structure, however you should be aware of the fact that iterating over the hash in Clojure doesn’t guarantee you order.

Path Queries

Path queries are most useful when you’d like to fire a function against some part of your data (be it processing, database initialization or anything else.

You can also run predicate queries based on your map, for example if you want to configure your database servers from rather big and complex config:

1
2
3
4
5
6
7
8
9
(def conf {:db
           {:redis {:cache  [{:host "host01" :port 1234} {:host "host02" :port 1234}]
                    :pubsub [{:host "host01" :port 1234} {:host "host02" :port 1234}]}}
           :cassandra [{:host "host01"} {:host "host02"}]})

(with-paths conf
        [:db :redis :cache]  configure-redis-cache
        [:db :redis :pubsub] configure-redis-pubsub
        [:db :cassandra]     configure-cassandra)

In this example, configure-redis-cache funciton will receive two arguments: value and path:

1
2
3
4
5
6
7
(defn configure-redis-cache
  [value path]
  (println "Value: " value)
  (println "Path: " path))

;; => Value: [{:host host01, :port 1234} {:host host02, :port 1234}]
;; => Path: [:db :redis :cache]

You can also do wildcard-matching with :*, for example:

1
2
3
4
5
(b/select {:a {:b {:c 1} :d {:c 2}}}
          [:a :* :c] (fn [val path]
                       (if (= path [:a :b :c])
                         (is (= val 1))
                         (is (= val 2)))))

Learn more in the documentation section.

Community

To subscribe for announcements of releases, important changes and so on, please follow @ClojureWerkz on Twitter.

License

Distributed under the Eclipse Public License, the same as Clojure.

The source is available on GitHub. We also use GitHub to track issues.

About the Author

The ClojureWerkz Team.