{"id":13508897,"url":"https://github.com/drewkerrigan/riak-elixir-client","last_synced_at":"2025-03-30T11:33:04.465Z","repository":{"id":45025023,"uuid":"12996514","full_name":"drewkerrigan/riak-elixir-client","owner":"drewkerrigan","description":"A Riak client written in Elixir.","archived":false,"fork":false,"pushed_at":"2020-09-30T00:30:03.000Z","size":6257,"stargazers_count":197,"open_issues_count":11,"forks_count":55,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-03-23T21:38:18.074Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drewkerrigan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-09-21T14:33:58.000Z","updated_at":"2024-10-05T21:00:35.000Z","dependencies_parsed_at":"2022-09-02T13:10:47.992Z","dependency_job_id":null,"html_url":"https://github.com/drewkerrigan/riak-elixir-client","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drewkerrigan%2Friak-elixir-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drewkerrigan%2Friak-elixir-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drewkerrigan%2Friak-elixir-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drewkerrigan%2Friak-elixir-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drewkerrigan","download_url":"https://codeload.github.com/drewkerrigan/riak-elixir-client/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246314044,"owners_count":20757455,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T02:01:00.161Z","updated_at":"2025-03-30T11:33:02.844Z","avatar_url":"https://github.com/drewkerrigan.png","language":"Elixir","funding_links":[],"categories":["ORM and Datamapping"],"sub_categories":[],"readme":"# Riak Elixir Client\n[![Build Status](https://travis-ci.org/drewkerrigan/riak-elixir-client.svg?branch=master)](https://travis-ci.org/drewkerrigan/riak-elixir-client)\n[![Hex version](https://img.shields.io/hexpm/v/riak.svg \"Hex Version\")](https://hex.pm/packages/riak)\n![Hex downloads](https://img.shields.io/hexpm/dt/riak.svg \"Hex Downloads\")\n[![Stories in Ready](https://badge.waffle.io/drewkerrigan/riak-elixir-client.png?label=ready\u0026title=Ready)](https://waffle.io/drewkerrigan/riak-elixir-client)\n\nA Riak client written in Elixir.  Now includes connection pooling with [pooler](http://github.com/seth/pooler) and a variety of other improvements from [riex](https://github.com/edgurgel/riex).\n\n## Setup\n\n### Prerequisites\n\n* Riak 2.0+\n* Elixir 1.0+\n\n#### In an Elixir application\n\nAdd the following to mix.exs\n\n```elixir\n...\ndef application do\n  [ applications: [ :riak ]]\nend\n...\ndefp deps do\n  [ {:riak, \"~\u003e 1.1.6\"} ]\nend\n...\n```\n\n## Usage\n\n### Establishing a Riak connection\n\n```elixir\n{:ok, pid} = Riak.Connection.start_link('127.0.0.1', 8087) # Default values\n```\n\n### Connection Pooling\n\nMost functions in this module can be called by passing the pid of the established connection or using a pool of connections (provided by pooler).  Define pools by using the group `riak`.  Following is an example `config/config.exs`:\n\n```elixir\nconfig :pooler, pools:\n  [\n    [\n      name: :riaklocal1,\n      group: :riak,\n      max_count: 10,\n      init_count: 5,\n      start_mfa: { Riak.Connection, :start_link, [] }\n    ], [\n      name: :riaklocal2,\n      group: :riak,\n      max_count: 15,\n      init_count: 2,\n      start_mfa: { Riak.Connection, :start_link, ['127.0.0.1', 9090] }\n    ]\n  ]\n```\n\nFor an example using this functionality with a local Riak instance, check [`config/config.exs`](https://github.com/drewkerrigan/riak-elixir-client/blob/master/config/config.exs).  More information about Elixir configuration can be found on [http://elixir-lang.org](http://elixir-lang.org): [Application environment and configuration](http://elixir-lang.org/getting-started/mix-otp/distributed-tasks-and-configuration.html#application-environment-and-configuration).\n\nOnce a pool configuration is properly defined in a project, calls to Riak can omit the pid.  For example:\n\nThis call uses a pid from the pool of connections provided by pooler:\n\n```elixir\nRiak.delete(\"user\", key)\n```\n\nThis call requires a pid obtained by first calling `Riak.Connection.start_link`:\n\n```elixir\nRiak.delete(pid, \"user\", key)\n```\n\n### Save a value\n\n```elixir\no = Riak.Object.create(bucket: \"user\", key: \"my_key\", data: \"Han Solo\")\nRiak.put(pid, o)\n```\n\n### Find an object\n\n```elixir\no = Riak.find(pid, \"user\", \"my_key\")\n```\n\n### Update an object\n\n```elixir\no = %{o | data: \"Something Else\"}\nRiak.put(pid, o)\n```\n\n### Delete an object\n\nUsing key\n\n```elixir\nRiak.delete(pid, \"user\", key)\n```\n\nUsing object\n\n```elixir\nRiak.delete(pid, o)\n```\n\n### Timeseries\n\nRiak Timeseries functionality is available in [TS 1.3.1 releases of Riak](http://docs.basho.com/riak/ts/1.3.1/downloads/) and greater.\n\n#### Setup\n\nCreate a table:\n\n```\nriak-admin bucket-type create GeoCheckin '{\"props\":{\"table_def\": \"CREATE TABLE GeoCheckin (region VARCHAR NOT NULL, state VARCHAR NOT NULL, time TIMESTAMP NOT NULL, weather VARCHAR NOT NULL, temperature DOUBLE, PRIMARY KEY ((region, state, QUANTUM(time, 15, 'm')), region, state, time))\"}}'\nriak-admin bucket-type activate GeoCheckin\n```\n\n#### Insert Rows\n\n```\nRiak.Timeseries.put(\"GeoCheckin\", [\n    {\"region1\", \"state1\", 25, \"hot\", 23.0},\n    {\"region2\", \"state99\", 26, \"windy\", 19.0}\n])\n\u003e :ok\n```\n\n#### Get a row by primary key\n\n```\nRiak.Timeseries.get(\"GeoCheckin\", [\"region1\", \"state1\", 25])\n\u003e {[\"region\", \"state\", \"time\", \"weather\", \"temperature\"], [{\"region1\", \"state1\", 25, \"hot\", 23.0}]}\n```\n\n#### Get all rows\n\n*Note*: This is a very expensive operation for a loaded cluster\n\n```\nRiak.Timeseries.list!(\"GeoCheckin\")\n\u003e [{\"region1\", \"state1\", 25, \"hot\", 23.0}, {\"region2\", \"state99\", 26, \"windy\", 19.0}]\n```\n\n#### Delete a row\n\n```\nRiak.Timeseries.delete(\"GeoCheckin\", [\"region2\", \"state99\", 26])\n\u003e :ok\n```\n\n#### Query\n\n```\nRiak.Timeseries.query(\"select * from GeoCheckin where time \u003e 24 and time \u003c 26 and region = 'region1' and state = 'state1'\")\n\u003e {[\"region\", \"state\", \"time\", \"weather\", \"temperature\"], [{\"region1\", \"state1\", 25, \"hot\", 23.0}]}\n```\n\n### Datatypes\n\nRiak Datatypes (a.k.a. CRDTs) are avaiable in [Riak versions 2.0](http://basho.com/introducing-riak-2-0/) and greater.  The types included are: maps, sets, counters, registers and flags.\n\n#### Setup\n\nDatatypes require the use of bucket-types.  Maps, sets, counters, and hyper-log-logs can be used as top-level bucket-type datatypes; Registers and flags may only be used within maps.\n\nThe following examples assume the presence of 4 datatype enabled bucket-types.  You can create these bucket-types by running the following commands on a single Riak node in your cluster:\n\nBucket-Type: `counters`\n\n```\nriak-admin bucket-type create counters '{\"props\":{\"datatype\":\"counter\"}}'\nriak-admin bucket-type activate counters\n```\n\nBucket-Type: `sets`\n\n```\nriak-admin bucket-type create sets '{\"props\":{\"datatype\":\"set\"}}'\nriak-admin bucket-type activate sets\n```\n\nBucket-Type: `maps`\n\n```\nriak-admin bucket-type create maps '{\"props\":{\"datatype\":\"map\"}}'\nriak-admin bucket-type activate maps\n```\n\nBucket-Type: `hll`\n\n```\nriak-admin bucket-type create hll '{\"props\":{\"datatype\":\"hll\"}}'\nriak-admin bucket-type activate hll\n```\n\n#### Counters\n\nCreate a counter (`alias Riak.CRDT.Counter`):\n\n```elixir\nCounter.new\n  |\u003e Counter.increment\n  |\u003e Counter.increment(2)\n  |\u003e Riak.update(\"counters\", \"my_counter_bucket\", \"my_key\")\n```\n\nFetch a counter:\n\n```elixir\ncounter = Riak.find(\"counters\", \"my_counter_bucket\", \"my_key\")\n  |\u003e Counter.value\n```\n\n`counter` will be 3.\n\n***NOTE***: \"Counter drift\" is a possibility that needs to be accounted for with any distributed system such as Riak.  The problem can manifest itself during failure states in either your applicaiton or Riak itself.  If an increment operation fails from the client's point of view, there is not sufficient information available to know whether or not that call made it to zero or all of the replicas for that counter object.  As such, if the client attempts to retry the increment after recieving something like a error code 500 from Riak, that counter object is at risk of drifting positive.  Similarly if the client decides not to retry, that counter object is at risk of drifting negative.\n\nFor these reasons, counters are only suggested for use-cases that can handle some (albeit small) amount of counter drift.  Good examples of appropriate use-cases are: Facebook likes, Twitter retweet counts, Youtube view counts, etc.  Some examples of poor use-cases for Riak counters are: bank account balances, anything related to money.  It is possible to implement these types of solutions using Riak, but more client side logic is necessary.  For an example of a client-side ledger with tunable retry options, check [github.com/drewkerrigan/riak-ruby-ledger](https://github.com/drewkerrigan/riak-ruby-ledger).  Another approach could be the client-side implementation of a HAT (Highly Available Transaction) algorithm.\n\n#### Sets\n\nCreate a set (`alias Riak.CRDT.Set`):\n\n```elixir\nSet.new\n  |\u003e Set.put(\"foo\")\n  |\u003e Set.put(\"bar\")\n  |\u003e Riak.update(\"sets\", \"my_set_bucket\", \"my_key\")\n```\n\nAnd fetch the set:\n\n```elixir\nset = Riak.find(\"sets\", \"my_set_bucket\", \"my_key\")\n  |\u003e Set.value\n```\n\nWhere `set` is an `orddict`.\n\n#### Maps\n\nMaps handle binary keys with any other datatype (map, set, flag, register and counter).\n\nCreate a map (`alias Riak.CRDT.Map`):\n\n```elixir\nregister = Register.new(\"some string\")\nflag = Flag.new |\u003e Flag.enable\nMap.new\n  |\u003e Map.put(\"k1\", register)\n  |\u003e Map.put(\"k2\", flag)\n  |\u003e Riak.update(\"maps\", \"my_map_bucket\", \"map_key\")\n```\n\nAnd fetch the map:\n\n```elixir\nmap = Riak.find(\"maps\", \"my_map_bucket\", key) |\u003e Map.value\n```\n\nWhere `map` is an `orddict`.\n\n#### Hyper Log Logs\n\nThe use case for this type is counting distinct elements in a monotonic way.\nI think of it as like a counter for customers visited but once a customer visits\nthe counter will never go up again.  It also isn't possible to remove a element\nonce it has been added to the log.\n\nCreate a HLL (`alias Riak.CRDT.HyperLogLog`):\n\n```elixir\nHyperLogLog.new\n  |\u003e HyperLogLog.add_element(\"foo\")\n  |\u003e Riak.update(\"hll\", \"my_hll_bucket\", \"hll_key\")\n```\n\nAnd fetch the distinct count:\n\n```elixir\nhll = Riak.find(\"hll\", \"my_hll_bucket\", \"hll_key\") |\u003e HLL.value\n```\n\nWhere `hll` is an `integer`.\n\n## Examples\n\nCheck the `examples/` directory for a few example elixir applications using the riak client.  \n\nFor more functionality, check `test/` directory.\n\n## Tests\n\n```\nMIX_ENV=test mix do deps.get, test\n```\n\n***NOTE:*** If you see errors related to `{:error, :nil_object}`, Ensure that you have created and activated the below `map`, `set`, and `counter` bucket types.\n\n\n*Note*\n\nThe creation of the following CRDT bucket-types is a prerequisite for passing the CRDT tests.\n\n```\nriak-admin bucket-type create maps '{\"props\":{\"datatype\":\"map\"}}'\nriak-admin bucket-type activate maps\nriak-admin bucket-type create sets '{\"props\":{\"datatype\":\"set\"}}'\nriak-admin bucket-type activate sets\nriak-admin bucket-type create counters '{\"props\":{\"datatype\":\"counter\"}}'\nriak-admin bucket-type activate counters\nriak-admin bucket-type create hll '{\"props\":{\"datatype\":\"hll\"}}'\nriak-admin bucket-type activate hll\n```\n\n*Note*\n\nThe creation of this Timeseries table is a prerequisite for passing the Timeseries tests.\n\n```\nriak-admin bucket-type create GeoCheckin '{\"props\":{\"table_def\": \"CREATE TABLE GeoCheckin (region VARCHAR NOT NULL, state VARCHAR NOT NULL, time TIMESTAMP NOT NULL, weather VARCHAR NOT NULL, temperature DOUBLE, PRIMARY KEY ((region, state, QUANTUM(time, 15, 'm')), region, state, time))\"}}'\nriak-admin bucket-type activate GeoCheckin\n```\n\n\n## License\n\n    Copyright 2017 Drew Kerrigan.\n    Copyright 2014 Eduardo Gurgel.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrewkerrigan%2Friak-elixir-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrewkerrigan%2Friak-elixir-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrewkerrigan%2Friak-elixir-client/lists"}