{"id":13508768,"url":"https://github.com/crate/craterl","last_synced_at":"2025-03-30T11:32:47.542Z","repository":{"id":15873186,"uuid":"18613992","full_name":"crate/craterl","owner":"crate","description":"Client Libraries for Erlang","archived":true,"fork":false,"pushed_at":"2015-12-30T13:56:39.000Z","size":1896,"stargazers_count":8,"open_issues_count":1,"forks_count":3,"subscribers_count":47,"default_branch":"master","last_synced_at":"2024-11-01T08:33:54.480Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crate.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.txt","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":"2014-04-09T21:26:47.000Z","updated_at":"2023-01-28T18:10:51.000Z","dependencies_parsed_at":"2022-08-27T03:51:22.938Z","dependency_job_id":null,"html_url":"https://github.com/crate/craterl","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crate%2Fcraterl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crate%2Fcraterl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crate%2Fcraterl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crate%2Fcraterl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crate","download_url":"https://codeload.github.com/crate/craterl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246314015,"owners_count":20757453,"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:00:58.137Z","updated_at":"2025-03-30T11:32:46.617Z","avatar_url":"https://github.com/crate.png","language":"Erlang","funding_links":[],"categories":["ORM and Datamapping"],"sub_categories":[],"readme":"# Craterl #\n\n[![Join the chat at https://gitter.im/crate/craterl](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/crate/craterl?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n\n[![Build Status](https://travis-ci.org/crate/craterl.svg?branch=master)](https://travis-ci.org/crate/craterl)\n![Another Badge](http://img.shields.io/badge/another-badge-green.svg)\n\nErlang client for crate.\n\nThis client is in an alpha state and, though tested very intensively,\nnot yet verified to be rock-solid in a production environment.\n\n## Compatibility ##\n\nTested with OTP releases ``R16B``, ``17`` and ``18``.\n\n## Installation\n\n### Rebar 3\n\nCraterl is built using [rebar3](https://github.com/rebar/rebar3), \nusing it in your project is highly recommended. \n\nHere is how you'd add it to your dependencies.\n\nIf you want to load a craterl release from [hex.pm](https://hex.pm/packages/craterl), configure it like so:\n\n```erlang\n{deps,[\n  {craterl,\"0.2.3\"}\n]}.\n```\n\nOr load it directly from github:\n\n```erlang\n{deps,[\n    {craterl, {git, \"git://github.com/crate/craterl.git\", {tag, \"0.2.3\"}}}\n]}.\n```\n\n### Rebar 2\n\nYou can also use craterl in your project using [rebar2](https://github.com/rebar/rebar),\nthough [rebar3](https://github.com/rebar/rebar3) is recommended.\n\nWith rebar2 you need to load craterl from github. \nUse a git tag or a commit ref in order to get reproducable builds:\n\n```erlang\n{deps,[\n    {craterl, \"0.2.3\", {git, \"git://github.com/crate.craterl.git\", {tag, \"0.2.3}}}\n]}.\n```\n\n\n### Mix\n\nCraterl releases are hosted on [hex.pm](https://hex.pm/packages/craterl).\n\nDeclare it as a dependency in your ``mix.exs`` file:\n\n```elixir\ndef deps do\n    [{:craterl, \"~\u003e 0.2.3\"}]\nend\n```\n\nOr load it directly from github:\n\n```elixir\ndef deps do\n    [{:craterl, git: \"git://github.com/crate/craterl.git\", tag: \"0.2.3\"}]\nend\n``` \n\n## Usage ##\n\nNormally you'd start craterl as part of your application's startup, so the \nErlang/OTP application framework will take care of actually starting craterl.\n\nHowever, if you want to play around with craterl on the erlang or\nelixir shell you can start it up with the following convenience method:\n\n```erlang\nok = craterl:start().\n```\n\nHaving a running ``craterl`` application, the next step is starting a client\ninstance using a variant of the ```craterl:new()``` function:\n\n```erlang\nClientSpec = {local, my_client}.\nServers = [{\u003c\u003c\"localhost\"\u003e\u003e, 4200}, \"localhost:4201\"].\nOptions = [{poolsize, 1000}, {timeout, 5000}].\nClientRef = craterl:new(ClientSpec, Servers, Options).\n```\n\nIt is possible to create many clients on one erlang node.\n```craterl``` client instances are created using a client spec which is\na tuple you would use when registering a process, like ```{local, your_name}```.\nThe process name, ```your_name``` in this example, must be unique on a node.\n\n### Options ###\n\nThe following options can be used to change the behaviour of a newly created craterl client:\n\n* poolname - ```string()``` or ```binary()```, the name of the connection pool, handled by hackney (erlang http client)\n* poolsize - ```integer()```, the size of the connection pool, also handled by hackney\n* timeout - ```integer()```, the receive and connect timeout for connections to crate servers, in milliseconds\n* ssl_options - ```term()```, the same options the erlang ssl module accepts as ```ssloptions()```\n* ssl_insecure - ```boolean()```, whether ssl certificates should be validated or not\n\nExample:\n\n```erlang\nOptions = [\n    {poolname, \"my_pool\"}, \n    {poolsize, 200}, {timeout, 6000}, \n    {ssl_insecure, false}, \n    {ssl_options, [\n        {cipers, [{rsa, aes_256_cbc, sha}]}, \n        {cacerts, MyDerEncodedCaCerts}\n    ]}\n].\nClientRef = craterl:new({local, craterl}, [{\u003c\u003c\"localhost\"\u003e\u003e, 4200}], Options).\n```\n\nSee the documentation of the ```craterl``` module for more detailed api documentation.\n\n### SQL ###\n\nIssuing SQL statements using craterl is possible with one of the variants \nof ```craterl:sql()```:\n\n```erlang\n{ok Response} = craterl:sql(\"select id, name from sys.cluster\").\n[[\u003c\u003c\"89b8f6bf-4082-415b-937e-7de66b67f6fe\"\u003e\u003e, \u003c\u003c\"crate\"\u003e\u003e]] = craterl_resp:rows(Response).\n[\u003c\u003c\"id\"\u003e\u003e,\u003c\u003c\"name\"\u003e\u003e] = craterl_resp:column_names(Response).\n\nStmt = \u003c\u003c\"select * from user where id in (?, ?, ?)\"\u003e\u003e.\nArgs = [1, 2, 3].\n{ok, Response2} = craterl:sql(ClientRef, Stmt, Args).\n```\n\nFor issuing multiple INSERT / DELETE or UPDATE requests with one roundtrip, \nthe ```craterl:sql_bulk()``` functions can be used:\n\n```erlang\nStmt = \u003c\u003c\"insert into t (id, name) values (?, ?)\"\u003e\u003e.\nBulkArgs = [[1, \u003c\u003c\"Ford\"\u003e\u003e], [2, \u003c\u003c\"Trillian\"\u003e\u003e], [3, \u003c\u003c\"Zaphod\"\u003e\u003e]].\n{ok, BulkResponse} = craterl:sql_bulk(ClientRef, Stmt, BulkArgs).\nBulkResults = craterl_resp:bulk_results(BulkResponse).\n[1,1,1] = lists:map(fun craterl_resp:row_count/1, BulkResults).\n\nStmt2 = \u003c\u003c\"update t set new_column=? where id=?\"\u003e\u003e.\nBulkArgs2 = [[\u003c\u003c\"funky\"\u003e\u003e, 1], [\u003c\u003c\"shizzle\"\u003e\u003e, 2], [\u003c\u003c\"indeed\"\u003e\u003e, 3]].\n{ok, BulkResponse2} = craterl:sql_bulk(Stmt2, BulkArgs2).\nBulkResults2 = craterl_resp:bulk_results(BulkResponse2).\n[1,1,1] = lists:map(fun craterl_resp:row_count/1, BulkResults2).\n\n{ok, SelectResponse} = craterl:sql(\"select * from t\").\n[[1,\u003c\u003c\"Ford\"\u003e\u003e,\u003c\u003c\"funky\"\u003e\u003e],\n [2,\u003c\u003c\"Trillian\"\u003e\u003e,\u003c\u003c\"shizzle\"\u003e\u003e],\n [3,\u003c\u003c\"Zaphod\"\u003e\u003e,\u003c\u003c\"indeed\"\u003e\u003e]] = craterl_resp:rows(SelectResponse).\n```\n\nEvery sql api function has a variant that accepts a ```ClientRef``` as first \nargument that is an atom referencing a ```craterl``` client that has been \nstarted using a variant ```craterl:new()``` in order to issue your request \nagainst a specific server / cluster.\n\n### Blobs ###\n\nCrate is able to store blobs, files, binary somethings. They can be replicated to \nmake sure you won't lose data.\n\nCraterl fully supports storing, retrieving and manipulating blobs.\n\nAt first a blob table is needed to store blobs into:\n\n```erlang\n{ok, SqlResponse} = craterl:sql(\"create blob table myblobs with (number_of_replicas=1)\").\n```\n\nIt is possible to upload blobs from stuff you have available in ram or from a file:\n \n```erlang\nContent = \u003c\u003c\"awesome!\"\u003e\u003e.\n{ok, {created, HashDigest}} = craterl:blob_put(\u003c\u003c\"myblobs\"\u003e\u003e, Content).\nHashDigest = \u003c\u003c\"040f06fd774092478d450774f5ba30c5da78acc8\"\u003e\u003e.\n\nFile = \u003c\u003c\"/usr/share/dict/words\"\u003e\u003e\n{ok,{created, WordsHash}} = craterl:blob_put_file(ClientRef, \u003c\u003c\"myblobs\"\u003e\u003e, \u003c\u003c\"/usr/share/dict/words\"\u003e\u003e).\nWordsHash = \u003c\u003c\"a62edf8685920f7d5a95113020631cdebd18a185\"\u003e\u003e.\n```\n\nYou can get blobs to memory or to file. Both methods will make use of chunked HTTP\nencoding so you will receive the blob piece by piece and won't load big blobs into memory at once.\n\n```erlang\n{ok, GetDataFun} = craterl:blob_get(\u003c\u003c\"myblobs\"\u003e\u003e, WordsHash).\nGetDataFun()\n{ok,\u003c\u003c\"A\\na\\naa\\naal\\naalii\\naam\\nAani\\naardvark\\naardwolf\\nAaron\\nAaronic\\nAaronical\\nAaronite\\nAaronitic\\nAaru\\nAb\\naba\\nAbabdeh\\nA\"...\u003e\u003e}\nGetDataFun()\n{ok,\u003c\u003c\"inoposterior\\nabdominoscope\\nabdominoscopy\\nabdominothoracic\\nabdominous\\nabdominovaginal\\nabdominovesical\\nabduce\\n\"...\u003e\u003e}\n...\nGetDataFun()\n{ok, done}\n\nNewWordsFile = \u003c\u003c\"/tmp/blobwords\"\u003e\u003e\n{ok, NewWordsFile} = craterl:blob_get_to_file(\u003c\u003c\"myblobs\"\u003e\u003e, WordsHash, NewWordsFile).\nfile:read_file(NewWordsFile)\n{ok,\u003c\u003c\"A\\na\\naa\\naal\\naalii\\naam\\nAani\\naardvark\\naardwolf\\nAaron\\nAaronic\\nAaronical\\nAaronite\\nAaronitic\\nAaru\\nAb\\naba\\nAbabdeh\\nA\"...\u003e\u003e}\n```\n\nCheck for existence of blobs:\n\n```erlang\nok = craterl:blob_exists(ClientRef, \u003c\u003c\"myblobs\"\u003e\u003e, WordsHash).\n{error, 404} = craterl:blob_exists(craterl, \u003c\u003c\"myblobs\"\u003e\u003e, \u003c\u003c\"doesnotexist\"\u003e\u003e).\n```\n\nDelete blobs:\n\n```erlang\nok = craterl:blob_delete(\u003c\u003c\"myblobs\"\u003e\u003e, WordsHash).\n{error, 404} = craterl:blob_delete(\u003c\u003c\"myblobs\"\u003e\u003e, WordsHash).\n```\n\nEvery blob api function, like the sql functions,  has a variant that accepts \na ```ClientRef``` as first argument that is an atom referencing a ```craterl``` \nclient that has been started using a variant of ```craterl:new()```.\n\n## Tests ##\n\n\nSimply call ```make test``` to run the unit and integration tests for ```craterl```.\n\n\n## Contributions ##\n\nAre very welcome, be it code, constructive feedback, money, or some motivating words!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrate%2Fcraterl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrate%2Fcraterl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrate%2Fcraterl/lists"}