{"id":13408985,"url":"https://github.com/vedang/clj_fdb","last_synced_at":"2025-10-27T13:45:57.149Z","repository":{"id":62433611,"uuid":"132255860","full_name":"vedang/clj_fdb","owner":"vedang","description":"A thin Clojure wrapper for the Java API for FoundationDB.","archived":false,"fork":false,"pushed_at":"2022-12-19T17:23:32.000Z","size":235,"stargazers_count":27,"open_issues_count":8,"forks_count":8,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-10-25T23:56:54.524Z","etag":null,"topics":["clojure","clojure-library","foundationdb"],"latest_commit_sha":null,"homepage":"https://vedang.github.io/clj_fdb/","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vedang.png","metadata":{"files":{"readme":"README.md","changelog":"changelog/0.1.0.txt","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-05T14:36:04.000Z","updated_at":"2025-09-20T09:23:20.000Z","dependencies_parsed_at":"2023-01-29T22:15:28.592Z","dependency_job_id":null,"html_url":"https://github.com/vedang/clj_fdb","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/vedang/clj_fdb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vedang%2Fclj_fdb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vedang%2Fclj_fdb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vedang%2Fclj_fdb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vedang%2Fclj_fdb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vedang","download_url":"https://codeload.github.com/vedang/clj_fdb/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vedang%2Fclj_fdb/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281279068,"owners_count":26473855,"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","status":"online","status_checked_at":"2025-10-27T02:00:05.855Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["clojure","clojure-library","foundationdb"],"created_at":"2024-07-30T20:00:57.084Z","updated_at":"2025-10-27T13:45:57.113Z","avatar_url":"https://github.com/vedang.png","language":"Clojure","funding_links":[],"categories":["Bindings"],"sub_categories":[],"readme":"# clj-fdb\n[![Circle CI](https://circleci.com/gh/vedang/clj_fdb.svg?style=svg)](https://app.circleci.com/pipelines/github/vedang/clj_fdb)\n[![Clojars Project](https://img.shields.io/clojars/v/me.vedang/clj-fdb.svg)](https://clojars.org/me.vedang/clj-fdb)\n\nA thin wrapper for the Java API for FoundationDB.\n\n## Layout\n\nTo get started, you need to read/use the functions defined in\n[src/me/vedang/clj_fdb/core.clj](https://github.com/vedang/clj_fdb/blob/master/src/me/vedang/clj_fdb/core.clj).\nThe impatient reader can jump to the [Examples section](#examples) to\nsee the functions in action.\n\nAt the moment, this ns provides the following functions:\n\n    - set [k v] [s k v] [k v opts] [s k v opts]\n    - get [k] [s k] [k opts] [s k opts]\n    - clear [k] [s k] [k opts] [s k opts]\n    - get-range [r] [s] [k opts] [s k] [s k opts]\n    - clear-range [r] [s t] [r opts] [s t opts]\n    - mutate! [mut k] [mut s k] [mut k byte-op] [mut s k byte-op]\n\nFDB only stores data as bytes. When using this library, you are\nexpected to pass in data (both keys as well as values) as either:\n- Byte Arrays\n- Strings (converted to byte-arrays internally with a UTF-8 encoding)\n- FDB data-structures (Tuples, Subspaces, DirectoryLayers, converted\n  to byte-arrays internally using functions provided by FDB)\n\nThe library *transparently converts Tuples, Subspaces and\nDirectoryLayers into byte-arrays (and back)* so my recommendation is\nthat you always use these for keys in FDB, and where possible use\nTuples to wrap the values you want to store in FDB. If you build your\nkeys and values **using Clojure's `vector` function**, your data will\nbe handled automatically. Note that if you use non-Tuple data as\nvalues, the library will return the byte-array as-is to you. You need\nto either pass in a `:valfn` to convert the byte-array to data or you\nneed to handle the conversion yourself. Refer to the examples below.\n\nThe idea is to write a really thin \"clojure-y\" wrapper on top of the\nJava API. The `core.clj` file provides wrapped functions that make\nusing the API simpler, but you should be able to drop down when you\nneed to. I've chosen to mimic the directory structure of the\nunderlying Java driver. So the style is as follows:\n\n    - `src/me/vedang/clj_fdb/` mimics `com.apple.foundationdb` (with\n      `transaction.clj` and `FDB.clj`)\n    - `src/me/vedang/clj_fdb/tuple/` mimics `com.apple.foundationdb.tuple` (with\n      `tuple.clj`)\n\n... and so on. The complete Java API is not available at the moment,\nand will be built out as per my requirements (or via PRs, please).\nCurrently, the core namespace provides sync functions for working with\nto Raw KV, Tuples, Subspaces and Directories.\n\nGoing through `transaction.clj` or `tuple.clj` or `FDB.clj` will give\nyou a clear idea of what I have in mind, please help me by\ncontributing PRs!\n\nThe complete documentation is available at:\nhttps://cljdoc.org/d/me.vedang/clj-fdb/0.3.0\n\n## Installation\n\n* Use the library in your Clojure projects by adding the dep in\n  `project.clj`\n```\n[me.vedang/clj-fdb \"0.3.0\"]\n```\n\n## Examples\n\nHere is some test code to demonstrate how to use the functions defined\nin the core ns:\n```clojure\n;; To run this code, you will need to require the following in your project:\n;; [me.vedang/clj-fdb \"0.3.0\"]\n(comment\n  (require '[me.vedang.clj-fdb.FDB :as cfdb]\n           '[me.vedang.clj-fdb.core :as fc]\n           '[me.vedang.clj-fdb.transaction :as ftr]\n           '[me.vedang.clj-fdb.tuple.tuple :as ftup]\n           '[me.vedang.clj-fdb.subspace.subspace :as fsub])\n\n  ;; Set a value in the DB.\n  (let [fdb (cfdb/select-api-version cfdb/clj-fdb-api-version)]\n    (with-open [db (cfdb/open fdb)]\n      (fc/set db [\"a\" \"test\" \"key\"] [\"some value\"])))\n  ;; =\u003e nil\n\n  ;; Read this value back in the DB.\n  (let [fdb (cfdb/select-api-version cfdb/clj-fdb-api-version)]\n    (with-open [db (cfdb/open fdb)]\n      (fc/get db [\"a\" \"test\" \"key\"])))\n  ;; =\u003e [\"some value\"]\n\n  ;; FDB's Tuple Layer is super handy for efficient range reads. Each\n  ;; element of the tuple can act as a prefix (from left to right).\n  (let [fdb (cfdb/select-api-version cfdb/clj-fdb-api-version)]\n    (with-open [db (cfdb/open fdb)]\n      (fc/set db [\"test\" \"keys\" \"A\"] [\"value A\"])\n      (fc/set db [\"test\" \"keys\" \"B\"] [\"value B\"])\n      (fc/set db [\"test\" \"keys\" \"C\"] [\"value C\"])\n      (fc/get-range db [\"test\" \"keys\"])))\n  ;; =\u003e {[\"test\" \"keys\" \"A\"] [\"value A\"],\n  ;;     [\"test\" \"keys\" \"B\"] [\"value B\"],\n  ;;     [\"test\" \"keys\" \"C\"] [\"value C\"]}\n\n  ;; FDB's Subspace Layer provides a neat way to logically namespace keys.\n  (let [fdb (cfdb/select-api-version cfdb/clj-fdb-api-version)\n        subspace (fsub/create [\"test\" \"keys\"])]\n    (with-open [db (cfdb/open fdb)]\n      (fc/set db subspace [\"A\"] [\"Value A\"])\n      (fc/set db subspace [\"B\"] [\"Value B\"])\n      (fc/get db subspace [\"A\"])))\n  ;; =\u003e [\"Value A\"]\n\n  (let [fdb (cfdb/select-api-version cfdb/clj-fdb-api-version)\n        subspace (fsub/create [\"test\" \"keys\"])]\n    (with-open [db (cfdb/open fdb)]\n      (fc/set db subspace [\"A\"] [\"Value A\"])\n      (fc/set db subspace [\"B\"] [\"Value B\"])\n      (fc/get-range db subspace [] {:valfn first})))\n  ;; =\u003e {[\"A\"] \"Value A\", [\"B\"] \"Value B\"}\n\n  (let [fdb (cfdb/select-api-version cfdb/clj-fdb-api-version)\n        subspace (fsub/create [\"test\" \"keys\"])]\n    (with-open [db (cfdb/open fdb)]\n      (fc/set db subspace [\"A\"] [\"Value A\"])\n      (fc/set db subspace [\"B\"] [\"Value B\"])\n      (fc/get-range db subspace [])))\n  ;; =\u003e {[\"A\"] [\"Value A\"], [\"B\"] [\"Value B\"], [\"C\"] [\"value C\"]}\n\n  ;; FDB's functions are beautifully composable. So you needn't\n  ;; execute each step of the above function in independent\n  ;; transactions. You can perform them all inside a single\n  ;; transaction. (with the full power of ACID behind you)\n  (let [fdb (cfdb/select-api-version cfdb/clj-fdb-api-version)]\n    (with-open [db (cfdb/open fdb)]\n      (ftr/run db\n        (fn [tr]\n          (fc/set tr [\"test\" \"keys\" \"A\"] [\"value inside transaction A\"])\n          (fc/set tr [\"test\" \"keys\" \"B\"] [\"value inside transaction B\"])\n          (fc/set tr [\"test\" \"keys\" \"C\"] [\"value inside transaction C\"])\n          (fc/get-range tr [\"test\" \"keys\"])))))\n  ;; =\u003e {[\"test\" \"keys\" \"A\"] [\"value inside transaction A\"],\n  ;;     [\"test\" \"keys\" \"B\"] [\"value inside transaction B\"],\n  ;;     [\"test\" \"keys\" \"C\"] [\"value inside transaction C\"]}\n\n  ;; The beauty and power of this is here:\n  (let [fdb (cfdb/select-api-version cfdb/clj-fdb-api-version)]\n    (with-open [db (cfdb/open fdb)]\n      (try (ftr/run db\n             (fn [tr]\n               (fc/set tr [\"test\" \"keys\" \"A\"] [\"NEW value A\"])\n               (fc/set tr [\"test\" \"keys\" \"B\"] [\"NEW value B\"])\n               (fc/set tr [\"test\" \"keys\" \"C\"] [\"NEW value C\"])\n               (throw (ex-info \"I don't like completing transactions\"\n                               {:boo :hoo}))))\n           (catch Exception _\n             (fc/get-range db [\"test\" \"keys\"])))))\n  ;; =\u003e {[\"test\" \"keys\" \"A\"] [\"value inside transaction A\"],\n  ;;     [\"test\" \"keys\" \"B\"] [\"value inside transaction B\"],\n  ;;     [\"test\" \"keys\" \"C\"] [\"value inside transaction C\"]}\n  ;; No change to the values because the transaction did not succeed!\n\n  ;; I hope this helps you get started with using this library!\n)\n```\n\nI started writing this code in order to write the example\nthat FoundationDB has documented here:\nhttps://apple.github.io/foundationdb/class-scheduling-java.html\n\nThis library has taken shape as a side-effect of trying to write that\nexample in Clojure.\n\nYou can find the Class Scheduler example\n([here](https://github.com/vedang/farstar/blob/master/src/farstar/class_scheduling.clj)).\n\nYou can also find other examples of using the library\n([here](https://github.com/vedang/farstar)).\n\nBest of luck, and feedback welcome!\n\n## Thanks\n\nThank you to Jan Rychter for feedback and discussion on shaping this library.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvedang%2Fclj_fdb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvedang%2Fclj_fdb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvedang%2Fclj_fdb/lists"}